blob: 53e85c70c6e581c1a951a6774a4beb454c1eef74 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * Generic address resolution entity
4 *
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
7 * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * Fixes:
10 * Vitaly E. Lavrov releasing NULL neighbor in neigh_add.
11 * Harald Welte Add neighbour cache statistics like rtstat
12 */
13
Joe Perchese005d192012-05-16 19:58:40 +000014#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090016#include <linux/slab.h>
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +030017#include <linux/kmemleak.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/types.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/socket.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/netdevice.h>
23#include <linux/proc_fs.h>
24#ifdef CONFIG_SYSCTL
25#include <linux/sysctl.h>
26#endif
27#include <linux/times.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020028#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <net/neighbour.h>
David Ahern4b2a2bf2019-05-01 18:18:42 -070030#include <net/arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <net/dst.h>
32#include <net/sock.h>
Tom Tucker8d717402006-07-30 20:43:36 -070033#include <net/netevent.h>
Thomas Grafa14a49d2006-08-07 17:53:08 -070034#include <net/netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/rtnetlink.h>
36#include <linux/random.h>
Paulo Marques543537b2005-06-23 00:09:02 -070037#include <linux/string.h>
vignesh babuc3609d52007-08-24 22:27:55 -070038#include <linux/log2.h>
Jiri Pirko1d4c8c22013-12-07 19:26:56 +010039#include <linux/inetdevice.h>
Jiri Pirkobba24892013-12-07 19:26:57 +010040#include <net/addrconf.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Roopa Prabhu56dd18a2019-02-14 09:15:11 -080042#include <trace/events/neigh.h>
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#define NEIGH_DEBUG 1
Joe Perchesd5d427c2013-04-15 15:17:19 +000045#define neigh_dbg(level, fmt, ...) \
46do { \
47 if (level <= NEIGH_DEBUG) \
48 pr_debug(fmt, ##__VA_ARGS__); \
49} while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51#define PNEIGH_HASHMASK 0xF
52
Kees Cooke99e88a2017-10-16 14:43:17 -070053static void neigh_timer_handler(struct timer_list *t);
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -070054static void __neigh_notify(struct neighbour *n, int type, int flags,
55 u32 pid);
56static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid);
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +020057static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
58 struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Amos Waterland45fc3b12005-09-24 16:53:16 -070060#ifdef CONFIG_PROC_FS
Christoph Hellwig71a50532018-04-15 10:16:41 +020061static const struct seq_operations neigh_stat_seq_ops;
Amos Waterland45fc3b12005-09-24 16:53:16 -070062#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64/*
65 Neighbour hash table buckets are protected with rwlock tbl->lock.
66
67 - All the scans/updates to hash buckets MUST be made under this lock.
68 - NOTHING clever should be made under this lock: no callbacks
69 to protocol backends, no attempts to send something to network.
70 It will result in deadlocks, if backend/driver wants to use neighbour
71 cache.
72 - If the entry requires some non-trivial actions, increase
73 its reference count and release table lock.
74
75 Neighbour entries are protected:
76 - with reference count.
77 - with rwlock neigh->lock
78
79 Reference count prevents destruction.
80
81 neigh->lock mainly serializes ll address data and its validity state.
82 However, the same lock is used to protect another entry fields:
83 - timer
84 - resolution queue
85
86 Again, nothing clever shall be made under neigh->lock,
87 the most complicated procedure, which we allow is dev->hard_header.
88 It is supposed, that dev->hard_header is simplistic and does
89 not make callbacks to neighbour tables.
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 */
91
David S. Miller8f40b162011-07-17 13:34:11 -070092static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -070093{
94 kfree_skb(skb);
95 return -ENETDOWN;
96}
97
Thomas Graf4f494552007-08-08 23:12:36 -070098static void neigh_cleanup_and_release(struct neighbour *neigh)
99{
Roopa Prabhu56dd18a2019-02-14 09:15:11 -0800100 trace_neigh_cleanup_and_release(neigh, 0);
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -0700101 __neigh_notify(neigh, RTM_DELNEIGH, 0, 0);
Ido Schimmel53f800e2016-12-23 09:32:48 +0100102 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
Thomas Graf4f494552007-08-08 23:12:36 -0700103 neigh_release(neigh);
104}
105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106/*
107 * It is random distribution in the interval (1/2)*base...(3/2)*base.
108 * It corresponds to default IPv6 settings and is not overridable,
109 * because it is really reasonable choice.
110 */
111
112unsigned long neigh_rand_reach_time(unsigned long base)
113{
Aruna-Hewapathirane63862b52014-01-11 07:15:59 -0500114 return base ? (prandom_u32() % base) + (base >> 1) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900116EXPORT_SYMBOL(neigh_rand_reach_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
David Ahern58956312018-12-07 12:24:57 -0800118static void neigh_mark_dead(struct neighbour *n)
119{
120 n->dead = 1;
121 if (!list_empty(&n->gc_list)) {
122 list_del_init(&n->gc_list);
123 atomic_dec(&n->tbl->gc_entries);
124 }
125}
126
David Ahern9c29a2f2018-12-11 18:57:21 -0700127static void neigh_update_gc_list(struct neighbour *n)
David Ahern58956312018-12-07 12:24:57 -0800128{
David Aherne997f8a2018-12-11 18:57:25 -0700129 bool on_gc_list, exempt_from_gc;
David Ahern58956312018-12-07 12:24:57 -0800130
David Ahern9c29a2f2018-12-11 18:57:21 -0700131 write_lock_bh(&n->tbl->lock);
132 write_lock(&n->lock);
David Ahern58956312018-12-07 12:24:57 -0800133
Chinmay Agarwaleefb45e2021-04-22 01:12:22 +0530134 if (n->dead)
135 goto out;
136
David Aherne997f8a2018-12-11 18:57:25 -0700137 /* remove from the gc list if new state is permanent or if neighbor
138 * is externally learned; otherwise entry should be on the gc list
David Ahern58956312018-12-07 12:24:57 -0800139 */
David Aherne997f8a2018-12-11 18:57:25 -0700140 exempt_from_gc = n->nud_state & NUD_PERMANENT ||
141 n->flags & NTF_EXT_LEARNED;
David Ahern9c29a2f2018-12-11 18:57:21 -0700142 on_gc_list = !list_empty(&n->gc_list);
David Ahern8cc196d2018-12-10 13:54:07 -0800143
David Aherne997f8a2018-12-11 18:57:25 -0700144 if (exempt_from_gc && on_gc_list) {
David Ahern9c29a2f2018-12-11 18:57:21 -0700145 list_del_init(&n->gc_list);
David Ahern58956312018-12-07 12:24:57 -0800146 atomic_dec(&n->tbl->gc_entries);
David Aherne997f8a2018-12-11 18:57:25 -0700147 } else if (!exempt_from_gc && !on_gc_list) {
David Ahern58956312018-12-07 12:24:57 -0800148 /* add entries to the tail; cleaning removes from the front */
149 list_add_tail(&n->gc_list, &n->tbl->gc_list);
150 atomic_inc(&n->tbl->gc_entries);
151 }
David Ahern9c29a2f2018-12-11 18:57:21 -0700152
Chinmay Agarwaleefb45e2021-04-22 01:12:22 +0530153out:
David Ahern9c29a2f2018-12-11 18:57:21 -0700154 write_unlock(&n->lock);
155 write_unlock_bh(&n->tbl->lock);
David Ahern58956312018-12-07 12:24:57 -0800156}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
David Aherne997f8a2018-12-11 18:57:25 -0700158static bool neigh_update_ext_learned(struct neighbour *neigh, u32 flags,
David Ahern526f1b52018-12-11 18:57:24 -0700159 int *notify)
160{
David Aherne997f8a2018-12-11 18:57:25 -0700161 bool rc = false;
David Ahern526f1b52018-12-11 18:57:24 -0700162 u8 ndm_flags;
163
164 if (!(flags & NEIGH_UPDATE_F_ADMIN))
David Aherne997f8a2018-12-11 18:57:25 -0700165 return rc;
David Ahern526f1b52018-12-11 18:57:24 -0700166
167 ndm_flags = (flags & NEIGH_UPDATE_F_EXT_LEARNED) ? NTF_EXT_LEARNED : 0;
168 if ((neigh->flags ^ ndm_flags) & NTF_EXT_LEARNED) {
169 if (ndm_flags & NTF_EXT_LEARNED)
170 neigh->flags |= NTF_EXT_LEARNED;
171 else
172 neigh->flags &= ~NTF_EXT_LEARNED;
David Aherne997f8a2018-12-11 18:57:25 -0700173 rc = true;
David Ahern526f1b52018-12-11 18:57:24 -0700174 *notify = 1;
175 }
David Aherne997f8a2018-12-11 18:57:25 -0700176
177 return rc;
David Ahern526f1b52018-12-11 18:57:24 -0700178}
179
David Ahern7e6f1822018-12-11 18:57:23 -0700180static bool neigh_del(struct neighbour *n, struct neighbour __rcu **np,
181 struct neigh_table *tbl)
Sowmini Varadhan50710342017-06-02 09:01:49 -0700182{
183 bool retval = false;
184
185 write_lock(&n->lock);
David Ahern7e6f1822018-12-11 18:57:23 -0700186 if (refcount_read(&n->refcnt) == 1) {
Sowmini Varadhan50710342017-06-02 09:01:49 -0700187 struct neighbour *neigh;
188
189 neigh = rcu_dereference_protected(n->next,
190 lockdep_is_held(&tbl->lock));
191 rcu_assign_pointer(*np, neigh);
David Ahern58956312018-12-07 12:24:57 -0800192 neigh_mark_dead(n);
Sowmini Varadhan50710342017-06-02 09:01:49 -0700193 retval = true;
194 }
195 write_unlock(&n->lock);
196 if (retval)
197 neigh_cleanup_and_release(n);
198 return retval;
199}
200
201bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl)
202{
203 struct neigh_hash_table *nht;
204 void *pkey = ndel->primary_key;
205 u32 hash_val;
206 struct neighbour *n;
207 struct neighbour __rcu **np;
208
209 nht = rcu_dereference_protected(tbl->nht,
210 lockdep_is_held(&tbl->lock));
211 hash_val = tbl->hash(pkey, ndel->dev, nht->hash_rnd);
212 hash_val = hash_val >> (32 - nht->hash_shift);
213
214 np = &nht->hash_buckets[hash_val];
215 while ((n = rcu_dereference_protected(*np,
216 lockdep_is_held(&tbl->lock)))) {
217 if (n == ndel)
David Ahern7e6f1822018-12-11 18:57:23 -0700218 return neigh_del(n, np, tbl);
Sowmini Varadhan50710342017-06-02 09:01:49 -0700219 np = &n->next;
220 }
221 return false;
222}
223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224static int neigh_forced_gc(struct neigh_table *tbl)
225{
David Ahern58956312018-12-07 12:24:57 -0800226 int max_clean = atomic_read(&tbl->gc_entries) - tbl->gc_thresh2;
227 unsigned long tref = jiffies - 5 * HZ;
David Ahern58956312018-12-07 12:24:57 -0800228 struct neighbour *n, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 int shrunk = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231 NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
232
233 write_lock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
David Ahern58956312018-12-07 12:24:57 -0800235 list_for_each_entry_safe(n, tmp, &tbl->gc_list, gc_list) {
236 if (refcount_read(&n->refcnt) == 1) {
237 bool remove = false;
238
239 write_lock(&n->lock);
David Ahern758a7f02018-12-11 18:57:22 -0700240 if ((n->nud_state == NUD_FAILED) ||
David Ahern7a6b1ab2021-06-07 11:35:30 -0600241 (n->nud_state == NUD_NOARP) ||
Jeff Dike8cf88212020-11-12 20:58:15 -0500242 (tbl->is_multicast &&
243 tbl->is_multicast(n->primary_key)) ||
David Aherne997f8a2018-12-11 18:57:25 -0700244 time_after(tref, n->updated))
David Ahern58956312018-12-07 12:24:57 -0800245 remove = true;
246 write_unlock(&n->lock);
247
248 if (remove && neigh_remove_one(n, tbl))
249 shrunk++;
250 if (shrunk >= max_clean)
251 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 }
253 }
254
255 tbl->last_flush = jiffies;
256
257 write_unlock_bh(&tbl->lock);
258
259 return shrunk;
260}
261
Pavel Emelyanova43d8992007-12-20 15:49:05 -0800262static void neigh_add_timer(struct neighbour *n, unsigned long when)
263{
264 neigh_hold(n);
265 if (unlikely(mod_timer(&n->timer, when))) {
266 printk("NEIGH: BUG, double timer add, state is %x\n",
267 n->nud_state);
268 dump_stack();
269 }
270}
271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272static int neigh_del_timer(struct neighbour *n)
273{
274 if ((n->nud_state & NUD_IN_TIMER) &&
275 del_timer(&n->timer)) {
276 neigh_release(n);
277 return 1;
278 }
279 return 0;
280}
281
282static void pneigh_queue_purge(struct sk_buff_head *list)
283{
284 struct sk_buff *skb;
285
286 while ((skb = skb_dequeue(list)) != NULL) {
287 dev_put(skb->dev);
288 kfree_skb(skb);
289 }
290}
291
David Ahern859bd2e2018-10-11 20:33:49 -0700292static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
293 bool skip_perm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294{
295 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000296 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000298 nht = rcu_dereference_protected(tbl->nht,
299 lockdep_is_held(&tbl->lock));
300
David S. Millercd089332011-07-11 01:28:12 -0700301 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700302 struct neighbour *n;
303 struct neighbour __rcu **np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Eric Dumazet767e97e2010-10-06 17:49:21 -0700305 while ((n = rcu_dereference_protected(*np,
306 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 if (dev && n->dev != dev) {
308 np = &n->next;
309 continue;
310 }
David Ahern859bd2e2018-10-11 20:33:49 -0700311 if (skip_perm && n->nud_state & NUD_PERMANENT) {
312 np = &n->next;
313 continue;
314 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700315 rcu_assign_pointer(*np,
316 rcu_dereference_protected(n->next,
317 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 write_lock(&n->lock);
319 neigh_del_timer(n);
David Ahern58956312018-12-07 12:24:57 -0800320 neigh_mark_dead(n);
Reshetova, Elena9f237432017-06-30 13:07:55 +0300321 if (refcount_read(&n->refcnt) != 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 /* The most unpleasant situation.
323 We must destroy neighbour entry,
324 but someone still uses it.
325
326 The destroy will be delayed until
327 the last user releases us, but
328 we must kill timers etc. and move
329 it to safe state.
330 */
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700331 __skb_queue_purge(&n->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000332 n->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 n->output = neigh_blackhole;
334 if (n->nud_state & NUD_VALID)
335 n->nud_state = NUD_NOARP;
336 else
337 n->nud_state = NUD_NONE;
Joe Perchesd5d427c2013-04-15 15:17:19 +0000338 neigh_dbg(2, "neigh %p is stray\n", n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 }
340 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700341 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 }
343 }
Herbert Xu49636bb2005-10-23 17:18:00 +1000344}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Herbert Xu49636bb2005-10-23 17:18:00 +1000346void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
347{
348 write_lock_bh(&tbl->lock);
David Ahern859bd2e2018-10-11 20:33:49 -0700349 neigh_flush_dev(tbl, dev, false);
Herbert Xu49636bb2005-10-23 17:18:00 +1000350 write_unlock_bh(&tbl->lock);
351}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900352EXPORT_SYMBOL(neigh_changeaddr);
Herbert Xu49636bb2005-10-23 17:18:00 +1000353
David Ahern859bd2e2018-10-11 20:33:49 -0700354static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
355 bool skip_perm)
Herbert Xu49636bb2005-10-23 17:18:00 +1000356{
357 write_lock_bh(&tbl->lock);
David Ahern859bd2e2018-10-11 20:33:49 -0700358 neigh_flush_dev(tbl, dev, skip_perm);
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200359 pneigh_ifdown_and_unlock(tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
361 del_timer_sync(&tbl->proxy_timer);
362 pneigh_queue_purge(&tbl->proxy_queue);
363 return 0;
364}
David Ahern859bd2e2018-10-11 20:33:49 -0700365
366int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev)
367{
368 __neigh_ifdown(tbl, dev, true);
369 return 0;
370}
371EXPORT_SYMBOL(neigh_carrier_down);
372
373int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
374{
375 __neigh_ifdown(tbl, dev, false);
376 return 0;
377}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900378EXPORT_SYMBOL(neigh_ifdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
David Ahern58956312018-12-07 12:24:57 -0800380static struct neighbour *neigh_alloc(struct neigh_table *tbl,
381 struct net_device *dev,
David Aherne997f8a2018-12-11 18:57:25 -0700382 bool exempt_from_gc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383{
384 struct neighbour *n = NULL;
385 unsigned long now = jiffies;
386 int entries;
387
David Aherne997f8a2018-12-11 18:57:25 -0700388 if (exempt_from_gc)
David Ahern58956312018-12-07 12:24:57 -0800389 goto do_alloc;
390
391 entries = atomic_inc_return(&tbl->gc_entries) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 if (entries >= tbl->gc_thresh3 ||
393 (entries >= tbl->gc_thresh2 &&
394 time_after(now, tbl->last_flush + 5 * HZ))) {
395 if (!neigh_forced_gc(tbl) &&
Rick Jonesfb811392015-08-07 11:10:37 -0700396 entries >= tbl->gc_thresh3) {
397 net_info_ratelimited("%s: neighbor table overflow!\n",
398 tbl->id);
399 NEIGH_CACHE_STAT_INC(tbl, table_fulls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 goto out_entries;
Rick Jonesfb811392015-08-07 11:10:37 -0700401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 }
403
David Ahern58956312018-12-07 12:24:57 -0800404do_alloc:
YOSHIFUJI Hideaki / 吉藤英明08433ef2013-01-24 00:44:23 +0000405 n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 if (!n)
407 goto out_entries;
408
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700409 __skb_queue_head_init(&n->arp_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 rwlock_init(&n->lock);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +0000411 seqlock_init(&n->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 n->updated = n->used = now;
413 n->nud_state = NUD_NONE;
414 n->output = neigh_blackhole;
David S. Millerf6b72b622011-07-14 07:53:20 -0700415 seqlock_init(&n->hh.hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 n->parms = neigh_parms_clone(&tbl->parms);
Kees Cooke99e88a2017-10-16 14:43:17 -0700417 timer_setup(&n->timer, neigh_timer_handler, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 NEIGH_CACHE_STAT_INC(tbl, allocs);
420 n->tbl = tbl;
Reshetova, Elena9f237432017-06-30 13:07:55 +0300421 refcount_set(&n->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 n->dead = 1;
David Ahern8cc196d2018-12-10 13:54:07 -0800423 INIT_LIST_HEAD(&n->gc_list);
David Ahern58956312018-12-07 12:24:57 -0800424
425 atomic_inc(&tbl->entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426out:
427 return n;
428
429out_entries:
David Aherne997f8a2018-12-11 18:57:25 -0700430 if (!exempt_from_gc)
David Ahern58956312018-12-07 12:24:57 -0800431 atomic_dec(&tbl->gc_entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 goto out;
433}
434
David S. Miller2c2aba62011-12-28 15:06:58 -0500435static void neigh_get_hash_rnd(u32 *x)
436{
Jason A. Donenfeldb3d0f782017-06-07 23:00:05 -0400437 *x = get_random_u32() | 1;
David S. Miller2c2aba62011-12-28 15:06:58 -0500438}
439
David S. Millercd089332011-07-11 01:28:12 -0700440static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441{
David S. Millercd089332011-07-11 01:28:12 -0700442 size_t size = (1 << shift) * sizeof(struct neighbour *);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000443 struct neigh_hash_table *ret;
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000444 struct neighbour __rcu **buckets;
David S. Miller2c2aba62011-12-28 15:06:58 -0500445 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000447 ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
448 if (!ret)
449 return NULL;
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300450 if (size <= PAGE_SIZE) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000451 buckets = kzalloc(size, GFP_ATOMIC);
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300452 } else {
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000453 buckets = (struct neighbour __rcu **)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000454 __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
455 get_order(size));
Konstantin Khlebnikov01b833a2019-01-14 13:38:43 +0300456 kmemleak_alloc(buckets, size, 1, GFP_ATOMIC);
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300457 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000458 if (!buckets) {
459 kfree(ret);
460 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 }
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000462 ret->hash_buckets = buckets;
David S. Millercd089332011-07-11 01:28:12 -0700463 ret->hash_shift = shift;
David S. Miller2c2aba62011-12-28 15:06:58 -0500464 for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
465 neigh_get_hash_rnd(&ret->hash_rnd[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 return ret;
467}
468
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000469static void neigh_hash_free_rcu(struct rcu_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000471 struct neigh_hash_table *nht = container_of(head,
472 struct neigh_hash_table,
473 rcu);
David S. Millercd089332011-07-11 01:28:12 -0700474 size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000475 struct neighbour __rcu **buckets = nht->hash_buckets;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300477 if (size <= PAGE_SIZE) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000478 kfree(buckets);
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300479 } else {
480 kmemleak_free(buckets);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000481 free_pages((unsigned long)buckets, get_order(size));
Konstantin Khlebnikov85704cb2019-01-08 12:30:00 +0300482 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000483 kfree(nht);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484}
485
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000486static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
David S. Millercd089332011-07-11 01:28:12 -0700487 unsigned long new_shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000489 unsigned int i, hash;
490 struct neigh_hash_table *new_nht, *old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
492 NEIGH_CACHE_STAT_INC(tbl, hash_grows);
493
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000494 old_nht = rcu_dereference_protected(tbl->nht,
495 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700496 new_nht = neigh_hash_alloc(new_shift);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000497 if (!new_nht)
498 return old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
David S. Millercd089332011-07-11 01:28:12 -0700500 for (i = 0; i < (1 << old_nht->hash_shift); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 struct neighbour *n, *next;
502
Eric Dumazet767e97e2010-10-06 17:49:21 -0700503 for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
504 lockdep_is_held(&tbl->lock));
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000505 n != NULL;
506 n = next) {
507 hash = tbl->hash(n->primary_key, n->dev,
508 new_nht->hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
David S. Millercd089332011-07-11 01:28:12 -0700510 hash >>= (32 - new_nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700511 next = rcu_dereference_protected(n->next,
512 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
Eric Dumazet767e97e2010-10-06 17:49:21 -0700514 rcu_assign_pointer(n->next,
515 rcu_dereference_protected(
516 new_nht->hash_buckets[hash],
517 lockdep_is_held(&tbl->lock)));
518 rcu_assign_pointer(new_nht->hash_buckets[hash], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 }
520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000522 rcu_assign_pointer(tbl->nht, new_nht);
523 call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
524 return new_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525}
526
527struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
528 struct net_device *dev)
529{
530 struct neighbour *n;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900531
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 NEIGH_CACHE_STAT_INC(tbl, lookups);
533
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000534 rcu_read_lock_bh();
Eric W. Biederman60395a22015-03-03 17:10:44 -0600535 n = __neigh_lookup_noref(tbl, pkey, dev);
536 if (n) {
Reshetova, Elena9f237432017-06-30 13:07:55 +0300537 if (!refcount_inc_not_zero(&n->refcnt))
Eric W. Biederman60395a22015-03-03 17:10:44 -0600538 n = NULL;
539 NEIGH_CACHE_STAT_INC(tbl, hits);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700541
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000542 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 return n;
544}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900545EXPORT_SYMBOL(neigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Eric W. Biederman426b5302008-01-24 00:13:18 -0800547struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
548 const void *pkey)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549{
550 struct neighbour *n;
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300551 unsigned int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800552 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000553 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 NEIGH_CACHE_STAT_INC(tbl, lookups);
556
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000557 rcu_read_lock_bh();
558 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700559 hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700560
561 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
562 n != NULL;
563 n = rcu_dereference_bh(n->next)) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800564 if (!memcmp(n->primary_key, pkey, key_len) &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900565 net_eq(dev_net(n->dev), net)) {
Reshetova, Elena9f237432017-06-30 13:07:55 +0300566 if (!refcount_inc_not_zero(&n->refcnt))
Eric Dumazet767e97e2010-10-06 17:49:21 -0700567 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 NEIGH_CACHE_STAT_INC(tbl, hits);
569 break;
570 }
571 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700572
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000573 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 return n;
575}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900576EXPORT_SYMBOL(neigh_lookup_nodev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
David Ahern58956312018-12-07 12:24:57 -0800578static struct neighbour *___neigh_create(struct neigh_table *tbl,
579 const void *pkey,
580 struct net_device *dev,
David Aherne997f8a2018-12-11 18:57:25 -0700581 bool exempt_from_gc, bool want_ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582{
David Aherne997f8a2018-12-11 18:57:25 -0700583 struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev, exempt_from_gc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 u32 hash_val;
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300585 unsigned int key_len = tbl->key_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 int error;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000587 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
David Ahernfc651002019-05-22 12:22:21 -0700589 trace_neigh_create(tbl, dev, pkey, n, exempt_from_gc);
590
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 if (!n) {
592 rc = ERR_PTR(-ENOBUFS);
593 goto out;
594 }
595
596 memcpy(n->primary_key, pkey, key_len);
597 n->dev = dev;
598 dev_hold(dev);
599
600 /* Protocol specific setup. */
601 if (tbl->constructor && (error = tbl->constructor(n)) < 0) {
602 rc = ERR_PTR(error);
603 goto out_neigh_release;
604 }
605
David Millerda6a8fa2011-07-25 00:01:38 +0000606 if (dev->netdev_ops->ndo_neigh_construct) {
Jiri Pirko503eebc2016-07-05 11:27:37 +0200607 error = dev->netdev_ops->ndo_neigh_construct(dev, n);
David Millerda6a8fa2011-07-25 00:01:38 +0000608 if (error < 0) {
609 rc = ERR_PTR(error);
610 goto out_neigh_release;
611 }
612 }
613
David S. Miller447f2192011-12-19 15:04:41 -0500614 /* Device specific setup. */
615 if (n->parms->neigh_setup &&
616 (error = n->parms->neigh_setup(n)) < 0) {
617 rc = ERR_PTR(error);
618 goto out_neigh_release;
619 }
620
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100621 n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
623 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000624 nht = rcu_dereference_protected(tbl->nht,
625 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
David S. Millercd089332011-07-11 01:28:12 -0700627 if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
628 nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
Jim Westfall096b9852018-01-14 04:18:50 -0800630 hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
632 if (n->parms->dead) {
633 rc = ERR_PTR(-EINVAL);
634 goto out_tbl_unlock;
635 }
636
Eric Dumazet767e97e2010-10-06 17:49:21 -0700637 for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
638 lockdep_is_held(&tbl->lock));
639 n1 != NULL;
640 n1 = rcu_dereference_protected(n1->next,
641 lockdep_is_held(&tbl->lock))) {
Jim Westfall096b9852018-01-14 04:18:50 -0800642 if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) {
David S. Millera263b302012-07-02 02:02:15 -0700643 if (want_ref)
644 neigh_hold(n1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 rc = n1;
646 goto out_tbl_unlock;
647 }
648 }
649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 n->dead = 0;
David Aherne997f8a2018-12-11 18:57:25 -0700651 if (!exempt_from_gc)
David Ahern8cc196d2018-12-10 13:54:07 -0800652 list_add_tail(&n->gc_list, &n->tbl->gc_list);
653
David S. Millera263b302012-07-02 02:02:15 -0700654 if (want_ref)
655 neigh_hold(n);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700656 rcu_assign_pointer(n->next,
657 rcu_dereference_protected(nht->hash_buckets[hash_val],
658 lockdep_is_held(&tbl->lock)));
659 rcu_assign_pointer(nht->hash_buckets[hash_val], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 write_unlock_bh(&tbl->lock);
Joe Perchesd5d427c2013-04-15 15:17:19 +0000661 neigh_dbg(2, "neigh %p is created\n", n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 rc = n;
663out:
664 return rc;
665out_tbl_unlock:
666 write_unlock_bh(&tbl->lock);
667out_neigh_release:
David Ahern64c6f4b2019-05-01 18:08:34 -0700668 if (!exempt_from_gc)
669 atomic_dec(&tbl->gc_entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 neigh_release(n);
671 goto out;
672}
David Ahern58956312018-12-07 12:24:57 -0800673
674struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
675 struct net_device *dev, bool want_ref)
676{
677 return ___neigh_create(tbl, pkey, dev, false, want_ref);
678}
David S. Millera263b302012-07-02 02:02:15 -0700679EXPORT_SYMBOL(__neigh_create);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300681static u32 pneigh_hash(const void *pkey, unsigned int key_len)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700682{
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700683 u32 hash_val = *(u32 *)(pkey + key_len - 4);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700684 hash_val ^= (hash_val >> 16);
685 hash_val ^= hash_val >> 8;
686 hash_val ^= hash_val >> 4;
687 hash_val &= PNEIGH_HASHMASK;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900688 return hash_val;
689}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700690
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900691static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
692 struct net *net,
693 const void *pkey,
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300694 unsigned int key_len,
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900695 struct net_device *dev)
696{
697 while (n) {
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700698 if (!memcmp(n->key, pkey, key_len) &&
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900699 net_eq(pneigh_net(n), net) &&
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700700 (n->dev == dev || !n->dev))
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900701 return n;
702 n = n->next;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700703 }
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900704 return NULL;
705}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700706
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900707struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
708 struct net *net, const void *pkey, struct net_device *dev)
709{
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300710 unsigned int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900711 u32 hash_val = pneigh_hash(pkey, key_len);
712
713 return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
714 net, pkey, key_len, dev);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700715}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900716EXPORT_SYMBOL_GPL(__pneigh_lookup);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700717
Eric W. Biederman426b5302008-01-24 00:13:18 -0800718struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
719 struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 struct net_device *dev, int creat)
721{
722 struct pneigh_entry *n;
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300723 unsigned int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900724 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 read_lock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900727 n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
728 net, pkey, key_len, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 read_unlock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900730
731 if (n || !creat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 goto out;
733
Pavel Emelyanov4ae28942007-10-15 12:54:15 -0700734 ASSERT_RTNL();
735
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
737 if (!n)
738 goto out;
739
David Ahern754d5da2018-12-19 15:53:22 -0800740 n->protocol = 0;
Eric W. Biedermanefd7ef12015-03-11 23:04:08 -0500741 write_pnet(&n->net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 memcpy(n->key, pkey, key_len);
743 n->dev = dev;
744 if (dev)
745 dev_hold(dev);
746
747 if (tbl->pconstructor && tbl->pconstructor(n)) {
748 if (dev)
749 dev_put(dev);
750 kfree(n);
751 n = NULL;
752 goto out;
753 }
754
755 write_lock_bh(&tbl->lock);
756 n->next = tbl->phash_buckets[hash_val];
757 tbl->phash_buckets[hash_val] = n;
758 write_unlock_bh(&tbl->lock);
759out:
760 return n;
761}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900762EXPORT_SYMBOL(pneigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
764
Eric W. Biederman426b5302008-01-24 00:13:18 -0800765int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 struct net_device *dev)
767{
768 struct pneigh_entry *n, **np;
Alexey Dobriyan01ccdf12017-09-23 23:03:04 +0300769 unsigned int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900770 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
772 write_lock_bh(&tbl->lock);
773 for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
774 np = &n->next) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800775 if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900776 net_eq(pneigh_net(n), net)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 *np = n->next;
778 write_unlock_bh(&tbl->lock);
779 if (tbl->pdestructor)
780 tbl->pdestructor(n);
781 if (n->dev)
782 dev_put(n->dev);
783 kfree(n);
784 return 0;
785 }
786 }
787 write_unlock_bh(&tbl->lock);
788 return -ENOENT;
789}
790
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200791static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
792 struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793{
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200794 struct pneigh_entry *n, **np, *freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 u32 h;
796
797 for (h = 0; h <= PNEIGH_HASHMASK; h++) {
798 np = &tbl->phash_buckets[h];
799 while ((n = *np) != NULL) {
800 if (!dev || n->dev == dev) {
801 *np = n->next;
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200802 n->next = freelist;
803 freelist = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 continue;
805 }
806 np = &n->next;
807 }
808 }
Wolfgang Bumiller53b76cd2018-04-12 10:46:55 +0200809 write_unlock_bh(&tbl->lock);
810 while ((n = freelist)) {
811 freelist = n->next;
812 n->next = NULL;
813 if (tbl->pdestructor)
814 tbl->pdestructor(n);
815 if (n->dev)
816 dev_put(n->dev);
817 kfree(n);
818 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 return -ENOENT;
820}
821
Denis V. Lunev06f05112008-01-24 00:30:58 -0800822static void neigh_parms_destroy(struct neigh_parms *parms);
823
824static inline void neigh_parms_put(struct neigh_parms *parms)
825{
Reshetova, Elena63439442017-06-30 13:07:56 +0300826 if (refcount_dec_and_test(&parms->refcnt))
Denis V. Lunev06f05112008-01-24 00:30:58 -0800827 neigh_parms_destroy(parms);
828}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
830/*
831 * neighbour must already be out of the table;
832 *
833 */
834void neigh_destroy(struct neighbour *neigh)
835{
David Millerda6a8fa2011-07-25 00:01:38 +0000836 struct net_device *dev = neigh->dev;
837
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
839
840 if (!neigh->dead) {
Joe Perchese005d192012-05-16 19:58:40 +0000841 pr_warn("Destroying alive neighbour %p\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 dump_stack();
843 return;
844 }
845
846 if (neigh_del_timer(neigh))
Joe Perchese005d192012-05-16 19:58:40 +0000847 pr_warn("Impossible event\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
Eric Dumazetc9ab4d82013-06-28 02:37:42 -0700849 write_lock_bh(&neigh->lock);
850 __skb_queue_purge(&neigh->arp_queue);
851 write_unlock_bh(&neigh->lock);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000852 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
David S. Miller447f2192011-12-19 15:04:41 -0500854 if (dev->netdev_ops->ndo_neigh_destroy)
Jiri Pirko503eebc2016-07-05 11:27:37 +0200855 dev->netdev_ops->ndo_neigh_destroy(dev, neigh);
David S. Miller447f2192011-12-19 15:04:41 -0500856
David Millerda6a8fa2011-07-25 00:01:38 +0000857 dev_put(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 neigh_parms_put(neigh->parms);
859
Joe Perchesd5d427c2013-04-15 15:17:19 +0000860 neigh_dbg(2, "neigh %p is destroyed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861
862 atomic_dec(&neigh->tbl->entries);
David Miller5b8b0062011-07-25 00:01:22 +0000863 kfree_rcu(neigh, rcu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900865EXPORT_SYMBOL(neigh_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
867/* Neighbour state is suspicious;
868 disable fast path.
869
870 Called with write_locked neigh.
871 */
872static void neigh_suspect(struct neighbour *neigh)
873{
Joe Perchesd5d427c2013-04-15 15:17:19 +0000874 neigh_dbg(2, "neigh %p is suspected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
876 neigh->output = neigh->ops->output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877}
878
879/* Neighbour state is OK;
880 enable fast path.
881
882 Called with write_locked neigh.
883 */
884static void neigh_connect(struct neighbour *neigh)
885{
Joe Perchesd5d427c2013-04-15 15:17:19 +0000886 neigh_dbg(2, "neigh %p is connected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887
888 neigh->output = neigh->ops->connected_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889}
890
Eric Dumazete4c4e442009-07-30 03:15:07 +0000891static void neigh_periodic_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892{
Eric Dumazete4c4e442009-07-30 03:15:07 +0000893 struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700894 struct neighbour *n;
895 struct neighbour __rcu **np;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000896 unsigned int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000897 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898
899 NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
900
Eric Dumazete4c4e442009-07-30 03:15:07 +0000901 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000902 nht = rcu_dereference_protected(tbl->nht,
903 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
905 /*
906 * periodically recompute ReachableTime from random function
907 */
908
Eric Dumazete4c4e442009-07-30 03:15:07 +0000909 if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 struct neigh_parms *p;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000911 tbl->last_rand = jiffies;
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +0100912 list_for_each_entry(p, &tbl->parms_list, list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 p->reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100914 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 }
916
Duan Jiongfeff9ab2014-02-27 17:14:41 +0800917 if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
918 goto out;
919
David S. Millercd089332011-07-11 01:28:12 -0700920 for (i = 0 ; i < (1 << nht->hash_shift); i++) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000921 np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Eric Dumazet767e97e2010-10-06 17:49:21 -0700923 while ((n = rcu_dereference_protected(*np,
924 lockdep_is_held(&tbl->lock))) != NULL) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000925 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
Eric Dumazete4c4e442009-07-30 03:15:07 +0000927 write_lock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
Eric Dumazete4c4e442009-07-30 03:15:07 +0000929 state = n->nud_state;
Roopa Prabhu9ce33e42018-04-24 13:49:34 -0700930 if ((state & (NUD_PERMANENT | NUD_IN_TIMER)) ||
931 (n->flags & NTF_EXT_LEARNED)) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000932 write_unlock(&n->lock);
933 goto next_elt;
934 }
935
936 if (time_before(n->used, n->confirmed))
937 n->used = n->confirmed;
938
Reshetova, Elena9f237432017-06-30 13:07:55 +0300939 if (refcount_read(&n->refcnt) == 1 &&
Eric Dumazete4c4e442009-07-30 03:15:07 +0000940 (state == NUD_FAILED ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100941 time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000942 *np = n->next;
David Ahern58956312018-12-07 12:24:57 -0800943 neigh_mark_dead(n);
Eric Dumazete4c4e442009-07-30 03:15:07 +0000944 write_unlock(&n->lock);
945 neigh_cleanup_and_release(n);
946 continue;
947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 write_unlock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
950next_elt:
Eric Dumazete4c4e442009-07-30 03:15:07 +0000951 np = &n->next;
952 }
953 /*
954 * It's fine to release lock here, even if hash table
955 * grows while we are preempted.
956 */
957 write_unlock_bh(&tbl->lock);
958 cond_resched();
959 write_lock_bh(&tbl->lock);
Michel Machado84338a62012-02-21 16:04:13 -0500960 nht = rcu_dereference_protected(tbl->nht,
961 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 }
YOSHIFUJI Hideaki / 吉藤英明27246802013-01-22 05:20:05 +0000963out:
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100964 /* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks.
965 * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2
966 * BASE_REACHABLE_TIME.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 */
viresh kumarf6180022014-01-22 12:23:33 +0530968 queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
Jiri Pirko1f9248e2013-12-07 19:26:53 +0100969 NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
Eric Dumazete4c4e442009-07-30 03:15:07 +0000970 write_unlock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971}
972
973static __inline__ int neigh_max_probes(struct neighbour *n)
974{
975 struct neigh_parms *p = n->parms;
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +0900976 return NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) +
977 (n->nud_state & NUD_PROBE ? NEIGH_VAR(p, MCAST_REPROBES) :
978 NEIGH_VAR(p, MCAST_PROBES));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979}
980
Timo Teras5ef12d92009-06-11 04:16:28 -0700981static void neigh_invalidate(struct neighbour *neigh)
Eric Dumazet0a141502010-03-09 19:40:54 +0000982 __releases(neigh->lock)
983 __acquires(neigh->lock)
Timo Teras5ef12d92009-06-11 04:16:28 -0700984{
985 struct sk_buff *skb;
986
987 NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
Joe Perchesd5d427c2013-04-15 15:17:19 +0000988 neigh_dbg(2, "neigh %p is failed\n", neigh);
Timo Teras5ef12d92009-06-11 04:16:28 -0700989 neigh->updated = jiffies;
990
991 /* It is very thin place. report_unreachable is very complicated
992 routine. Particularly, it can hit the same neighbour entry!
993
994 So that, we try to be accurate and avoid dead loop. --ANK
995 */
996 while (neigh->nud_state == NUD_FAILED &&
997 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
998 write_unlock(&neigh->lock);
999 neigh->ops->error_report(neigh, skb);
1000 write_lock(&neigh->lock);
1001 }
Eric Dumazetc9ab4d82013-06-28 02:37:42 -07001002 __skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001003 neigh->arp_queue_len_bytes = 0;
Timo Teras5ef12d92009-06-11 04:16:28 -07001004}
1005
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001006static void neigh_probe(struct neighbour *neigh)
1007 __releases(neigh->lock)
1008{
Hannes Frederic Sowa4ed377e2013-09-21 06:32:34 +02001009 struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001010 /* keep skb alive even if arp_queue overflows */
1011 if (skb)
Martin Zhang19125c12015-11-17 20:49:30 +08001012 skb = skb_clone(skb, GFP_ATOMIC);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001013 write_unlock(&neigh->lock);
Eric Dumazet48481c82017-03-23 12:39:21 -07001014 if (neigh->ops->solicit)
1015 neigh->ops->solicit(neigh, skb);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001016 atomic_inc(&neigh->probes);
Yang Wei87fff3ca2019-01-17 23:11:30 +08001017 consume_skb(skb);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001018}
1019
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020/* Called when a timer expires for a neighbour entry. */
1021
Kees Cooke99e88a2017-10-16 14:43:17 -07001022static void neigh_timer_handler(struct timer_list *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023{
1024 unsigned long now, next;
Kees Cooke99e88a2017-10-16 14:43:17 -07001025 struct neighbour *neigh = from_timer(neigh, t, timer);
Eric Dumazet95c96172012-04-15 05:58:06 +00001026 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 int notify = 0;
1028
1029 write_lock(&neigh->lock);
1030
1031 state = neigh->nud_state;
1032 now = jiffies;
1033 next = now + HZ;
1034
David S. Miller045f7b32011-11-01 17:45:55 -04001035 if (!(state & NUD_IN_TIMER))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
1038 if (state & NUD_REACHABLE) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001039 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 neigh->confirmed + neigh->parms->reachable_time)) {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001041 neigh_dbg(2, "neigh %p is still alive\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 next = neigh->confirmed + neigh->parms->reachable_time;
1043 } else if (time_before_eq(now,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001044 neigh->used +
1045 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001046 neigh_dbg(2, "neigh %p is delayed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001048 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 neigh_suspect(neigh);
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001050 next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 } else {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001052 neigh_dbg(2, "neigh %p is suspected\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 neigh->nud_state = NUD_STALE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001054 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 neigh_suspect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -07001056 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 }
1058 } else if (state & NUD_DELAY) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001059 if (time_before_eq(now,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001060 neigh->confirmed +
1061 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001062 neigh_dbg(2, "neigh %p is now reachable\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 neigh->nud_state = NUD_REACHABLE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001064 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 neigh_connect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -07001066 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 next = neigh->confirmed + neigh->parms->reachable_time;
1068 } else {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001069 neigh_dbg(2, "neigh %p is probed\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 neigh->nud_state = NUD_PROBE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001071 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 atomic_set(&neigh->probes, 0);
Erik Kline765c9c62015-05-18 19:44:41 +09001073 notify = 1;
Hangbin Liu19e16d22020-04-01 14:46:20 +08001074 next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
1075 HZ/100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 }
1077 } else {
1078 /* NUD_PROBE|NUD_INCOMPLETE */
Hangbin Liu19e16d22020-04-01 14:46:20 +08001079 next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), HZ/100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 }
1081
1082 if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
1083 atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 neigh->nud_state = NUD_FAILED;
1085 notify = 1;
Timo Teras5ef12d92009-06-11 04:16:28 -07001086 neigh_invalidate(neigh);
Duan Jiong5e2c21d2014-02-27 17:03:03 +08001087 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 }
1089
1090 if (neigh->nud_state & NUD_IN_TIMER) {
Hangbin Liu96d10d52020-05-28 15:15:13 +08001091 if (time_before(next, jiffies + HZ/100))
1092 next = jiffies + HZ/100;
Herbert Xu6fb99742005-10-23 16:37:48 +10001093 if (!mod_timer(&neigh->timer, next))
1094 neigh_hold(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 }
1096 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001097 neigh_probe(neigh);
David S. Miller9ff56602008-02-17 18:39:54 -08001098 } else {
David S. Miller69cc64d2008-02-11 21:45:44 -08001099out:
David S. Miller9ff56602008-02-17 18:39:54 -08001100 write_unlock(&neigh->lock);
1101 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
Thomas Grafd961db32007-08-08 23:12:56 -07001103 if (notify)
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07001104 neigh_update_notify(neigh, 0);
Thomas Grafd961db32007-08-08 23:12:56 -07001105
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001106 trace_neigh_timer_handler(neigh, 0);
1107
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 neigh_release(neigh);
1109}
1110
1111int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
1112{
1113 int rc;
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001114 bool immediate_probe = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
1116 write_lock_bh(&neigh->lock);
1117
1118 rc = 0;
1119 if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
1120 goto out_unlock_bh;
Julian Anastasov2c51a972015-06-16 22:56:39 +03001121 if (neigh->dead)
1122 goto out_dead;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001125 if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
1126 NEIGH_VAR(neigh->parms, APP_PROBES)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001127 unsigned long next, now = jiffies;
1128
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001129 atomic_set(&neigh->probes,
1130 NEIGH_VAR(neigh->parms, UCAST_PROBES));
Lorenzo Bianconi071c3792019-07-14 23:36:11 +02001131 neigh_del_timer(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 neigh->nud_state = NUD_INCOMPLETE;
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001133 neigh->updated = now;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001134 next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
Hangbin Liu19e16d22020-04-01 14:46:20 +08001135 HZ/100);
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001136 neigh_add_timer(neigh, next);
1137 immediate_probe = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 } else {
1139 neigh->nud_state = NUD_FAILED;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001140 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 write_unlock_bh(&neigh->lock);
1142
Wei Yongjunf3fbbe02009-02-25 00:37:32 +00001143 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 return 1;
1145 }
1146 } else if (neigh->nud_state & NUD_STALE) {
Joe Perchesd5d427c2013-04-15 15:17:19 +00001147 neigh_dbg(2, "neigh %p is delayed\n", neigh);
Lorenzo Bianconi071c3792019-07-14 23:36:11 +02001148 neigh_del_timer(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001150 neigh->updated = jiffies;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001151 neigh_add_timer(neigh, jiffies +
1152 NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 }
1154
1155 if (neigh->nud_state == NUD_INCOMPLETE) {
1156 if (skb) {
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001157 while (neigh->arp_queue_len_bytes + skb->truesize >
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001158 NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 struct sk_buff *buff;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001160
David S. Millerf72051b2008-09-23 01:11:18 -07001161 buff = __skb_dequeue(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001162 if (!buff)
1163 break;
1164 neigh->arp_queue_len_bytes -= buff->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 kfree_skb(buff);
Neil Horman9a6d2762008-07-16 20:50:49 -07001166 NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 }
Eric Dumazeta4731132010-05-27 16:09:39 -07001168 skb_dst_force(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 __skb_queue_tail(&neigh->arp_queue, skb);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001170 neigh->arp_queue_len_bytes += skb->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 }
1172 rc = 1;
1173 }
1174out_unlock_bh:
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001175 if (immediate_probe)
1176 neigh_probe(neigh);
1177 else
1178 write_unlock(&neigh->lock);
1179 local_bh_enable();
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001180 trace_neigh_event_send_done(neigh, rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 return rc;
Julian Anastasov2c51a972015-06-16 22:56:39 +03001182
1183out_dead:
1184 if (neigh->nud_state & NUD_STALE)
1185 goto out_unlock_bh;
1186 write_unlock_bh(&neigh->lock);
1187 kfree_skb(skb);
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001188 trace_neigh_event_send_dead(neigh, 1);
Julian Anastasov2c51a972015-06-16 22:56:39 +03001189 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001191EXPORT_SYMBOL(__neigh_event_send);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
David S. Millerf6b72b622011-07-14 07:53:20 -07001193static void neigh_update_hhs(struct neighbour *neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194{
1195 struct hh_cache *hh;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001196 void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
Doug Kehn91a72a72010-07-14 18:02:16 -07001197 = NULL;
1198
1199 if (neigh->dev->header_ops)
1200 update = neigh->dev->header_ops->cache_update;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201
1202 if (update) {
David S. Millerf6b72b622011-07-14 07:53:20 -07001203 hh = &neigh->hh;
Eric Dumazetc305c6ae2019-11-07 18:29:11 -08001204 if (READ_ONCE(hh->hh_len)) {
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001205 write_seqlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 update(hh, neigh->dev, neigh->ha);
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001207 write_sequnlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 }
1209 }
1210}
1211
1212
1213
1214/* Generic update routine.
1215 -- lladdr is new lladdr or NULL, if it is not supplied.
1216 -- new is new state.
1217 -- flags
1218 NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
1219 if it is different.
1220 NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001221 lladdr instead of overriding it
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 if it is different.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 NEIGH_UPDATE_F_ADMIN means that the change is administrative.
1224
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001225 NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 NTF_ROUTER flag.
1227 NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
1228 a router.
1229
1230 Caller MUST hold reference count on the entry.
1231 */
1232
David Ahern7a35a502018-12-05 20:02:29 -08001233static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
1234 u8 new, u32 flags, u32 nlmsg_pid,
1235 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236{
David Aherne997f8a2018-12-11 18:57:25 -07001237 bool ext_learn_change = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 u8 old;
1239 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 int notify = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 struct net_device *dev;
1242 int update_isrouter = 0;
1243
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001244 trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid);
1245
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 write_lock_bh(&neigh->lock);
1247
1248 dev = neigh->dev;
1249 old = neigh->nud_state;
1250 err = -EPERM;
1251
Chinmay Agarwaleb4e8fa2021-01-27 22:24:54 +05301252 if (neigh->dead) {
1253 NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
1254 new = old;
1255 goto out;
1256 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001257 if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 (old & (NUD_NOARP | NUD_PERMANENT)))
1259 goto out;
1260
David Aherne997f8a2018-12-11 18:57:25 -07001261 ext_learn_change = neigh_update_ext_learned(neigh, flags, &notify);
Roopa Prabhu9ce33e42018-04-24 13:49:34 -07001262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 if (!(new & NUD_VALID)) {
1264 neigh_del_timer(neigh);
1265 if (old & NUD_CONNECTED)
1266 neigh_suspect(neigh);
David Ahern9c29a2f2018-12-11 18:57:21 -07001267 neigh->nud_state = new;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 notify = old & NUD_VALID;
Roopa Prabhud2fb4fb2018-10-20 18:09:31 -07001270 if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
Timo Teras5ef12d92009-06-11 04:16:28 -07001271 (new & NUD_FAILED)) {
1272 neigh_invalidate(neigh);
1273 notify = 1;
1274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 goto out;
1276 }
1277
1278 /* Compare new lladdr with cached one */
1279 if (!dev->addr_len) {
1280 /* First case: device needs no address. */
1281 lladdr = neigh->ha;
1282 } else if (lladdr) {
1283 /* The second case: if something is already cached
1284 and a new address is proposed:
1285 - compare new & old
1286 - if they are different, check override flag
1287 */
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001288 if ((old & NUD_VALID) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 !memcmp(lladdr, neigh->ha, dev->addr_len))
1290 lladdr = neigh->ha;
1291 } else {
1292 /* No address is supplied; if we know something,
1293 use it, otherwise discard the request.
1294 */
1295 err = -EINVAL;
David Ahern7a35a502018-12-05 20:02:29 -08001296 if (!(old & NUD_VALID)) {
1297 NL_SET_ERR_MSG(extack, "No link layer address given");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 lladdr = neigh->ha;
1301 }
1302
Vasily Khoruzhickf0e0d042018-09-13 11:12:03 -07001303 /* Update confirmed timestamp for neighbour entry after we
1304 * received ARP packet even if it doesn't change IP to MAC binding.
1305 */
1306 if (new & NUD_CONNECTED)
1307 neigh->confirmed = jiffies;
1308
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 /* If entry was valid and address is not changed,
1310 do not change entry state, if new one is STALE.
1311 */
1312 err = 0;
1313 update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
1314 if (old & NUD_VALID) {
1315 if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
1316 update_isrouter = 0;
1317 if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
1318 (old & NUD_CONNECTED)) {
1319 lladdr = neigh->ha;
1320 new = NUD_STALE;
1321 } else
1322 goto out;
1323 } else {
Julian Anastasov0e7bbcc2016-07-27 09:56:50 +03001324 if (lladdr == neigh->ha && new == NUD_STALE &&
1325 !(flags & NEIGH_UPDATE_F_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 new = old;
1327 }
1328 }
1329
Vasily Khoruzhickf0e0d042018-09-13 11:12:03 -07001330 /* Update timestamp only once we know we will make a change to the
Ihar Hrachyshka77d71232017-05-16 08:44:24 -07001331 * neighbour entry. Otherwise we risk to move the locktime window with
1332 * noop updates and ignore relevant ARP updates.
1333 */
Vasily Khoruzhickf0e0d042018-09-13 11:12:03 -07001334 if (new != old || lladdr != neigh->ha)
Ihar Hrachyshka77d71232017-05-16 08:44:24 -07001335 neigh->updated = jiffies;
Ihar Hrachyshka77d71232017-05-16 08:44:24 -07001336
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 if (new != old) {
1338 neigh_del_timer(neigh);
Erik Kline765c9c62015-05-18 19:44:41 +09001339 if (new & NUD_PROBE)
1340 atomic_set(&neigh->probes, 0);
Pavel Emelyanova43d8992007-12-20 15:49:05 -08001341 if (new & NUD_IN_TIMER)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001342 neigh_add_timer(neigh, (jiffies +
1343 ((new & NUD_REACHABLE) ?
David S. Miller667347f2005-09-27 12:07:44 -07001344 neigh->parms->reachable_time :
1345 0)));
David Ahern9c29a2f2018-12-11 18:57:21 -07001346 neigh->nud_state = new;
Bob Gilligan53385d22013-12-15 13:39:56 -08001347 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 }
1349
1350 if (lladdr != neigh->ha) {
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001351 write_seqlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 memcpy(&neigh->ha, lladdr, dev->addr_len);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001353 write_sequnlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 neigh_update_hhs(neigh);
1355 if (!(new & NUD_CONNECTED))
1356 neigh->confirmed = jiffies -
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001357 (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 }
1360 if (new == old)
1361 goto out;
1362 if (new & NUD_CONNECTED)
1363 neigh_connect(neigh);
1364 else
1365 neigh_suspect(neigh);
1366 if (!(old & NUD_VALID)) {
1367 struct sk_buff *skb;
1368
1369 /* Again: avoid dead loop if something went wrong */
1370
1371 while (neigh->nud_state & NUD_VALID &&
1372 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
David S. Miller69cce1d2011-07-17 23:09:49 -07001373 struct dst_entry *dst = skb_dst(skb);
1374 struct neighbour *n2, *n1 = neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 write_unlock_bh(&neigh->lock);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001376
1377 rcu_read_lock();
David S. Miller13a43d92012-07-02 22:15:37 -07001378
1379 /* Why not just use 'neigh' as-is? The problem is that
1380 * things such as shaper, eql, and sch_teql can end up
1381 * using alternative, different, neigh objects to output
1382 * the packet in the output path. So what we need to do
1383 * here is re-lookup the top-level neigh in the path so
1384 * we can reinject the packet there.
1385 */
1386 n2 = NULL;
Tong Zhud47ec7a2021-03-19 14:33:37 -04001387 if (dst && dst->obsolete != DST_OBSOLETE_DEAD) {
David S. Miller13a43d92012-07-02 22:15:37 -07001388 n2 = dst_neigh_lookup_skb(dst, skb);
1389 if (n2)
1390 n1 = n2;
1391 }
David S. Miller8f40b162011-07-17 13:34:11 -07001392 n1->output(n1, skb);
David S. Miller13a43d92012-07-02 22:15:37 -07001393 if (n2)
1394 neigh_release(n2);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001395 rcu_read_unlock();
1396
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 write_lock_bh(&neigh->lock);
1398 }
Eric Dumazetc9ab4d82013-06-28 02:37:42 -07001399 __skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001400 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 }
1402out:
Roopa Prabhufc6e8072018-09-22 21:26:20 -07001403 if (update_isrouter)
1404 neigh_update_is_router(neigh, flags, &notify);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 write_unlock_bh(&neigh->lock);
Tom Tucker8d717402006-07-30 20:43:36 -07001406
David Aherne997f8a2018-12-11 18:57:25 -07001407 if (((new ^ old) & NUD_PERMANENT) || ext_learn_change)
David Ahern9c29a2f2018-12-11 18:57:21 -07001408 neigh_update_gc_list(neigh);
1409
Tom Tucker8d717402006-07-30 20:43:36 -07001410 if (notify)
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07001411 neigh_update_notify(neigh, nlmsg_pid);
Thomas Grafd961db32007-08-08 23:12:56 -07001412
Roopa Prabhu56dd18a2019-02-14 09:15:11 -08001413 trace_neigh_update_done(neigh, err);
1414
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 return err;
1416}
David Ahern7a35a502018-12-05 20:02:29 -08001417
1418int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
1419 u32 flags, u32 nlmsg_pid)
1420{
1421 return __neigh_update(neigh, lladdr, new, flags, nlmsg_pid, NULL);
1422}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001423EXPORT_SYMBOL(neigh_update);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424
Jiri Benc7e980562013-12-11 13:48:20 +01001425/* Update the neigh to listen temporarily for probe responses, even if it is
1426 * in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
1427 */
1428void __neigh_set_probe_once(struct neighbour *neigh)
1429{
Julian Anastasov2c51a972015-06-16 22:56:39 +03001430 if (neigh->dead)
1431 return;
Jiri Benc7e980562013-12-11 13:48:20 +01001432 neigh->updated = jiffies;
1433 if (!(neigh->nud_state & NUD_FAILED))
1434 return;
Duan Jiong2176d5d2014-05-09 13:16:48 +08001435 neigh->nud_state = NUD_INCOMPLETE;
1436 atomic_set(&neigh->probes, neigh_max_probes(neigh));
Jiri Benc7e980562013-12-11 13:48:20 +01001437 neigh_add_timer(neigh,
Hangbin Liu19e16d22020-04-01 14:46:20 +08001438 jiffies + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
1439 HZ/100));
Jiri Benc7e980562013-12-11 13:48:20 +01001440}
1441EXPORT_SYMBOL(__neigh_set_probe_once);
1442
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443struct neighbour *neigh_event_ns(struct neigh_table *tbl,
1444 u8 *lladdr, void *saddr,
1445 struct net_device *dev)
1446{
1447 struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
1448 lladdr || !dev->addr_len);
1449 if (neigh)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001450 neigh_update(neigh, lladdr, NUD_STALE,
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07001451 NEIGH_UPDATE_F_OVERRIDE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 return neigh;
1453}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001454EXPORT_SYMBOL(neigh_event_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455
Eric Dumazet34d101d2010-10-11 09:16:57 -07001456/* called with read_lock_bh(&n->lock); */
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -06001457static void neigh_hh_init(struct neighbour *n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458{
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -06001459 struct net_device *dev = n->dev;
1460 __be16 prot = n->tbl->protocol;
David S. Millerf6b72b622011-07-14 07:53:20 -07001461 struct hh_cache *hh = &n->hh;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001462
1463 write_lock_bh(&n->lock);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001464
David S. Millerf6b72b622011-07-14 07:53:20 -07001465 /* Only one thread can come in here and initialize the
1466 * hh_cache entry.
1467 */
David S. Millerb23b5452011-07-16 17:45:02 -07001468 if (!hh->hh_len)
1469 dev->header_ops->cache(n, hh, prot);
David S. Millerf6b72b622011-07-14 07:53:20 -07001470
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001471 write_unlock_bh(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472}
1473
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474/* Slow and careful. */
1475
David S. Miller8f40b162011-07-17 13:34:11 -07001476int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 int rc = 0;
1479
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 if (!neigh_event_send(neigh, skb)) {
1481 int err;
1482 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001483 unsigned int seq;
Eric Dumazet34d101d2010-10-11 09:16:57 -07001484
Eric Dumazetc305c6ae2019-11-07 18:29:11 -08001485 if (dev->header_ops->cache && !READ_ONCE(neigh->hh.hh_len))
Eric W. Biedermanbdf53c52015-03-02 00:13:22 -06001486 neigh_hh_init(neigh);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001487
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001488 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001489 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001490 seq = read_seqbegin(&neigh->ha_lock);
1491 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1492 neigh->ha, NULL, skb->len);
1493 } while (read_seqretry(&neigh->ha_lock, seq));
Eric Dumazet34d101d2010-10-11 09:16:57 -07001494
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001496 rc = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 else
1498 goto out_kfree_skb;
1499 }
1500out:
1501 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502out_kfree_skb:
1503 rc = -EINVAL;
1504 kfree_skb(skb);
1505 goto out;
1506}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001507EXPORT_SYMBOL(neigh_resolve_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508
1509/* As fast as possible without hh cache */
1510
David S. Miller8f40b162011-07-17 13:34:11 -07001511int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001514 unsigned int seq;
David S. Miller8f40b162011-07-17 13:34:11 -07001515 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001517 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001518 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001519 seq = read_seqbegin(&neigh->ha_lock);
1520 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1521 neigh->ha, NULL, skb->len);
1522 } while (read_seqretry(&neigh->ha_lock, seq));
1523
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001525 err = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 else {
1527 err = -EINVAL;
1528 kfree_skb(skb);
1529 }
1530 return err;
1531}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001532EXPORT_SYMBOL(neigh_connected_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533
David S. Miller8f40b162011-07-17 13:34:11 -07001534int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
1535{
1536 return dev_queue_xmit(skb);
1537}
1538EXPORT_SYMBOL(neigh_direct_output);
1539
Kees Cooke99e88a2017-10-16 14:43:17 -07001540static void neigh_proxy_process(struct timer_list *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541{
Kees Cooke99e88a2017-10-16 14:43:17 -07001542 struct neigh_table *tbl = from_timer(tbl, t, proxy_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 long sched_next = 0;
1544 unsigned long now = jiffies;
David S. Millerf72051b2008-09-23 01:11:18 -07001545 struct sk_buff *skb, *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546
1547 spin_lock(&tbl->proxy_queue.lock);
1548
David S. Millerf72051b2008-09-23 01:11:18 -07001549 skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1550 long tdif = NEIGH_CB(skb)->sched_next - now;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 if (tdif <= 0) {
David S. Millerf72051b2008-09-23 01:11:18 -07001553 struct net_device *dev = skb->dev;
Eric Dumazet20e60742011-08-22 19:32:42 +00001554
David S. Millerf72051b2008-09-23 01:11:18 -07001555 __skb_unlink(skb, &tbl->proxy_queue);
Eric Dumazet20e60742011-08-22 19:32:42 +00001556 if (tbl->proxy_redo && netif_running(dev)) {
1557 rcu_read_lock();
David S. Millerf72051b2008-09-23 01:11:18 -07001558 tbl->proxy_redo(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001559 rcu_read_unlock();
1560 } else {
David S. Millerf72051b2008-09-23 01:11:18 -07001561 kfree_skb(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001562 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563
1564 dev_put(dev);
1565 } else if (!sched_next || tdif < sched_next)
1566 sched_next = tdif;
1567 }
1568 del_timer(&tbl->proxy_timer);
1569 if (sched_next)
1570 mod_timer(&tbl->proxy_timer, jiffies + sched_next);
1571 spin_unlock(&tbl->proxy_queue.lock);
1572}
1573
1574void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
1575 struct sk_buff *skb)
1576{
weichenchena533b702020-12-25 13:44:45 +08001577 unsigned long sched_next = jiffies +
1578 prandom_u32_max(NEIGH_VAR(p, PROXY_DELAY));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001580 if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 kfree_skb(skb);
1582 return;
1583 }
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001584
1585 NEIGH_CB(skb)->sched_next = sched_next;
1586 NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
1588 spin_lock(&tbl->proxy_queue.lock);
1589 if (del_timer(&tbl->proxy_timer)) {
1590 if (time_before(tbl->proxy_timer.expires, sched_next))
1591 sched_next = tbl->proxy_timer.expires;
1592 }
Eric Dumazetadf30902009-06-02 05:19:30 +00001593 skb_dst_drop(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 dev_hold(skb->dev);
1595 __skb_queue_tail(&tbl->proxy_queue, skb);
1596 mod_timer(&tbl->proxy_timer, sched_next);
1597 spin_unlock(&tbl->proxy_queue.lock);
1598}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001599EXPORT_SYMBOL(pneigh_enqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001601static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
Eric W. Biederman426b5302008-01-24 00:13:18 -08001602 struct net *net, int ifindex)
1603{
1604 struct neigh_parms *p;
1605
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001606 list_for_each_entry(p, &tbl->parms_list, list) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09001607 if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
Gao feng170d6f92013-06-20 10:01:33 +08001608 (!p->dev && !ifindex && net_eq(net, &init_net)))
Eric W. Biederman426b5302008-01-24 00:13:18 -08001609 return p;
1610 }
1611
1612 return NULL;
1613}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
1615struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1616 struct neigh_table *tbl)
1617{
Gao fengcf89d6b2013-06-20 10:01:32 +08001618 struct neigh_parms *p;
Stephen Hemminger00829822008-11-20 20:14:53 -08001619 struct net *net = dev_net(dev);
1620 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
Gao fengcf89d6b2013-06-20 10:01:32 +08001622 p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 if (p) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 p->tbl = tbl;
Reshetova, Elena63439442017-06-30 13:07:56 +03001625 refcount_set(&p->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 p->reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001627 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001628 dev_hold(dev);
1629 p->dev = dev;
Eric W. Biedermanefd7ef12015-03-11 23:04:08 -05001630 write_pnet(&p->net, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 p->sysctl_table = NULL;
Veaceslav Falico63134802013-08-02 19:07:38 +02001632
1633 if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
Veaceslav Falico63134802013-08-02 19:07:38 +02001634 dev_put(dev);
1635 kfree(p);
1636 return NULL;
1637 }
1638
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 write_lock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001640 list_add(&p->list, &tbl->parms.list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 write_unlock_bh(&tbl->lock);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01001642
1643 neigh_parms_data_state_cleanall(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 }
1645 return p;
1646}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001647EXPORT_SYMBOL(neigh_parms_alloc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
1649static void neigh_rcu_free_parms(struct rcu_head *head)
1650{
1651 struct neigh_parms *parms =
1652 container_of(head, struct neigh_parms, rcu_head);
1653
1654 neigh_parms_put(parms);
1655}
1656
1657void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
1658{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 if (!parms || parms == &tbl->parms)
1660 return;
1661 write_lock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001662 list_del(&parms->list);
1663 parms->dead = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 write_unlock_bh(&tbl->lock);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001665 if (parms->dev)
1666 dev_put(parms->dev);
1667 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001669EXPORT_SYMBOL(neigh_parms_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
Denis V. Lunev06f05112008-01-24 00:30:58 -08001671static void neigh_parms_destroy(struct neigh_parms *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672{
1673 kfree(parms);
1674}
1675
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001676static struct lock_class_key neigh_table_proxy_queue_class;
1677
WANG Congd7480fd2014-11-10 15:59:36 -08001678static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
1679
1680void neigh_table_init(int index, struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681{
1682 unsigned long now = jiffies;
1683 unsigned long phsize;
1684
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001685 INIT_LIST_HEAD(&tbl->parms_list);
David Ahern58956312018-12-07 12:24:57 -08001686 INIT_LIST_HEAD(&tbl->gc_list);
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01001687 list_add(&tbl->parms.list, &tbl->parms_list);
Eric Dumazete42ea982008-11-12 00:54:54 -08001688 write_pnet(&tbl->parms.net, &init_net);
Reshetova, Elena63439442017-06-30 13:07:56 +03001689 refcount_set(&tbl->parms.refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 tbl->parms.reachable_time =
Jiri Pirko1f9248e2013-12-07 19:26:53 +01001691 neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 tbl->stats = alloc_percpu(struct neigh_statistics);
1694 if (!tbl->stats)
1695 panic("cannot create neighbour cache statistics");
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001696
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697#ifdef CONFIG_PROC_FS
Christoph Hellwig71a50532018-04-15 10:16:41 +02001698 if (!proc_create_seq_data(tbl->id, 0, init_net.proc_net_stat,
1699 &neigh_stat_seq_ops, tbl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 panic("cannot create neighbour proc dir entry");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701#endif
1702
David S. Millercd089332011-07-11 01:28:12 -07001703 RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704
1705 phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
Andrew Morton77d04bd2006-04-07 14:52:59 -07001706 tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001708 if (!tbl->nht || !tbl->phash_buckets)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 panic("cannot allocate neighbour cache hashes");
1710
YOSHIFUJI Hideaki / 吉藤英明08433ef2013-01-24 00:44:23 +00001711 if (!tbl->entry_size)
1712 tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
1713 tbl->key_len, NEIGH_PRIV_ALIGN);
1714 else
1715 WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
1716
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 rwlock_init(&tbl->lock);
Tejun Heo203b42f2012-08-21 13:18:23 -07001718 INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
viresh kumarf6180022014-01-22 12:23:33 +05301719 queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
1720 tbl->parms.reachable_time);
Kees Cooke99e88a2017-10-16 14:43:17 -07001721 timer_setup(&tbl->proxy_timer, neigh_proxy_process, 0);
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001722 skb_queue_head_init_class(&tbl->proxy_queue,
1723 &neigh_table_proxy_queue_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724
1725 tbl->last_flush = now;
1726 tbl->last_rand = now + tbl->parms.reachable_time * 20;
Simon Kelleybd89efc2006-05-12 14:56:08 -07001727
WANG Congd7480fd2014-11-10 15:59:36 -08001728 neigh_tables[index] = tbl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001730EXPORT_SYMBOL(neigh_table_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731
WANG Congd7480fd2014-11-10 15:59:36 -08001732int neigh_table_clear(int index, struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733{
WANG Congd7480fd2014-11-10 15:59:36 -08001734 neigh_tables[index] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 /* It is not clean... Fix it to unload IPv6 module safely */
Tejun Heoa5c30b32010-10-19 06:04:42 +00001736 cancel_delayed_work_sync(&tbl->gc_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 del_timer_sync(&tbl->proxy_timer);
1738 pneigh_queue_purge(&tbl->proxy_queue);
1739 neigh_ifdown(tbl, NULL);
1740 if (atomic_read(&tbl->entries))
Joe Perchese005d192012-05-16 19:58:40 +00001741 pr_crit("neighbour leakage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742
Eric Dumazet6193d2b2011-01-19 22:02:47 +00001743 call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
1744 neigh_hash_free_rcu);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001745 tbl->nht = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746
1747 kfree(tbl->phash_buckets);
1748 tbl->phash_buckets = NULL;
1749
Alexey Dobriyan3f192b52007-11-05 21:28:13 -08001750 remove_proc_entry(tbl->id, init_net.proc_net_stat);
1751
Kirill Korotaev3fcde742006-09-01 01:34:10 -07001752 free_percpu(tbl->stats);
1753 tbl->stats = NULL;
1754
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 return 0;
1756}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001757EXPORT_SYMBOL(neigh_table_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758
WANG Congd7480fd2014-11-10 15:59:36 -08001759static struct neigh_table *neigh_find_table(int family)
1760{
1761 struct neigh_table *tbl = NULL;
1762
1763 switch (family) {
1764 case AF_INET:
1765 tbl = neigh_tables[NEIGH_ARP_TABLE];
1766 break;
1767 case AF_INET6:
1768 tbl = neigh_tables[NEIGH_ND_TABLE];
1769 break;
1770 case AF_DECnet:
1771 tbl = neigh_tables[NEIGH_DN_TABLE];
1772 break;
1773 }
1774
1775 return tbl;
1776}
1777
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08001778const struct nla_policy nda_policy[NDA_MAX+1] = {
Roopa Prabhu1274e1c2020-05-21 22:26:14 -07001779 [NDA_UNSPEC] = { .strict_start_type = NDA_NH_ID },
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08001780 [NDA_DST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
1781 [NDA_LLADDR] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
1782 [NDA_CACHEINFO] = { .len = sizeof(struct nda_cacheinfo) },
1783 [NDA_PROBES] = { .type = NLA_U32 },
1784 [NDA_VLAN] = { .type = NLA_U16 },
1785 [NDA_PORT] = { .type = NLA_U16 },
1786 [NDA_VNI] = { .type = NLA_U32 },
1787 [NDA_IFINDEX] = { .type = NLA_U32 },
1788 [NDA_MASTER] = { .type = NLA_U32 },
David Aherna9cd3432018-12-19 20:02:36 -08001789 [NDA_PROTOCOL] = { .type = NLA_U8 },
Roopa Prabhu1274e1c2020-05-21 22:26:14 -07001790 [NDA_NH_ID] = { .type = NLA_U32 },
Nikolay Aleksandrov899426b2020-06-23 23:47:16 +03001791 [NDA_FDB_EXT_ATTRS] = { .type = NLA_NESTED },
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08001792};
1793
David Ahernc21ef3e2017-04-16 09:48:24 -07001794static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
1795 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001797 struct net *net = sock_net(skb->sk);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001798 struct ndmsg *ndm;
1799 struct nlattr *dst_attr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 struct neigh_table *tbl;
WANG Congd7480fd2014-11-10 15:59:36 -08001801 struct neighbour *neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 struct net_device *dev = NULL;
Thomas Grafa14a49d2006-08-07 17:53:08 -07001803 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804
Eric Dumazet110b2492010-10-04 04:27:36 +00001805 ASSERT_RTNL();
Thomas Grafa14a49d2006-08-07 17:53:08 -07001806 if (nlmsg_len(nlh) < sizeof(*ndm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 goto out;
1808
Thomas Grafa14a49d2006-08-07 17:53:08 -07001809 dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
David Ahern7a35a502018-12-05 20:02:29 -08001810 if (!dst_attr) {
1811 NL_SET_ERR_MSG(extack, "Network address not specified");
Thomas Grafa14a49d2006-08-07 17:53:08 -07001812 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001813 }
Thomas Grafa14a49d2006-08-07 17:53:08 -07001814
1815 ndm = nlmsg_data(nlh);
1816 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001817 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001818 if (dev == NULL) {
1819 err = -ENODEV;
1820 goto out;
1821 }
1822 }
1823
WANG Congd7480fd2014-11-10 15:59:36 -08001824 tbl = neigh_find_table(ndm->ndm_family);
1825 if (tbl == NULL)
1826 return -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827
David Ahern7a35a502018-12-05 20:02:29 -08001828 if (nla_len(dst_attr) < (int)tbl->key_len) {
1829 NL_SET_ERR_MSG(extack, "Invalid network address");
WANG Congd7480fd2014-11-10 15:59:36 -08001830 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832
WANG Congd7480fd2014-11-10 15:59:36 -08001833 if (ndm->ndm_flags & NTF_PROXY) {
1834 err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
Eric Dumazet110b2492010-10-04 04:27:36 +00001835 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 }
WANG Congd7480fd2014-11-10 15:59:36 -08001837
1838 if (dev == NULL)
1839 goto out;
1840
1841 neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1842 if (neigh == NULL) {
1843 err = -ENOENT;
1844 goto out;
1845 }
1846
David Ahern7a35a502018-12-05 20:02:29 -08001847 err = __neigh_update(neigh, NULL, NUD_FAILED,
1848 NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN,
1849 NETLINK_CB(skb).portid, extack);
Sowmini Varadhan50710342017-06-02 09:01:49 -07001850 write_lock_bh(&tbl->lock);
WANG Congd7480fd2014-11-10 15:59:36 -08001851 neigh_release(neigh);
Sowmini Varadhan50710342017-06-02 09:01:49 -07001852 neigh_remove_one(neigh, tbl);
1853 write_unlock_bh(&tbl->lock);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001854
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855out:
1856 return err;
1857}
1858
David Ahernc21ef3e2017-04-16 09:48:24 -07001859static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
1860 struct netlink_ext_ack *extack)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861{
Roopa Prabhuf7aa74e2018-09-22 21:26:19 -07001862 int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE |
1863 NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001864 struct net *net = sock_net(skb->sk);
Thomas Graf5208deb2006-08-07 17:55:40 -07001865 struct ndmsg *ndm;
1866 struct nlattr *tb[NDA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 struct neigh_table *tbl;
1868 struct net_device *dev = NULL;
WANG Congd7480fd2014-11-10 15:59:36 -08001869 struct neighbour *neigh;
1870 void *dst, *lladdr;
David Aherndf9b0e32018-12-15 14:09:06 -08001871 u8 protocol = 0;
Thomas Graf5208deb2006-08-07 17:55:40 -07001872 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
Eric Dumazet110b2492010-10-04 04:27:36 +00001874 ASSERT_RTNL();
Johannes Berg8cb08172019-04-26 14:07:28 +02001875 err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX,
1876 nda_policy, extack);
Thomas Graf5208deb2006-08-07 17:55:40 -07001877 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 goto out;
1879
Thomas Graf5208deb2006-08-07 17:55:40 -07001880 err = -EINVAL;
David Ahern7a35a502018-12-05 20:02:29 -08001881 if (!tb[NDA_DST]) {
1882 NL_SET_ERR_MSG(extack, "Network address not specified");
Thomas Graf5208deb2006-08-07 17:55:40 -07001883 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001884 }
Thomas Graf5208deb2006-08-07 17:55:40 -07001885
1886 ndm = nlmsg_data(nlh);
1887 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001888 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Graf5208deb2006-08-07 17:55:40 -07001889 if (dev == NULL) {
1890 err = -ENODEV;
1891 goto out;
1892 }
1893
David Ahern7a35a502018-12-05 20:02:29 -08001894 if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) {
1895 NL_SET_ERR_MSG(extack, "Invalid link address");
Eric Dumazet110b2492010-10-04 04:27:36 +00001896 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001897 }
Thomas Graf5208deb2006-08-07 17:55:40 -07001898 }
1899
WANG Congd7480fd2014-11-10 15:59:36 -08001900 tbl = neigh_find_table(ndm->ndm_family);
1901 if (tbl == NULL)
1902 return -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
David Ahern7a35a502018-12-05 20:02:29 -08001904 if (nla_len(tb[NDA_DST]) < (int)tbl->key_len) {
1905 NL_SET_ERR_MSG(extack, "Invalid network address");
WANG Congd7480fd2014-11-10 15:59:36 -08001906 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001907 }
1908
WANG Congd7480fd2014-11-10 15:59:36 -08001909 dst = nla_data(tb[NDA_DST]);
1910 lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911
David Aherna9cd3432018-12-19 20:02:36 -08001912 if (tb[NDA_PROTOCOL])
David Aherndf9b0e32018-12-15 14:09:06 -08001913 protocol = nla_get_u8(tb[NDA_PROTOCOL]);
David Aherndf9b0e32018-12-15 14:09:06 -08001914
WANG Congd7480fd2014-11-10 15:59:36 -08001915 if (ndm->ndm_flags & NTF_PROXY) {
1916 struct pneigh_entry *pn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917
WANG Congd7480fd2014-11-10 15:59:36 -08001918 err = -ENOBUFS;
1919 pn = pneigh_lookup(tbl, net, dst, dev, 1);
1920 if (pn) {
1921 pn->flags = ndm->ndm_flags;
David Aherndf9b0e32018-12-15 14:09:06 -08001922 if (protocol)
1923 pn->protocol = protocol;
Eric Biederman0c5c2d32009-03-04 00:03:08 -08001924 err = 0;
WANG Congd7480fd2014-11-10 15:59:36 -08001925 }
Eric Dumazet110b2492010-10-04 04:27:36 +00001926 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 }
1928
David Ahern7a35a502018-12-05 20:02:29 -08001929 if (!dev) {
1930 NL_SET_ERR_MSG(extack, "Device not specified");
WANG Congd7480fd2014-11-10 15:59:36 -08001931 goto out;
David Ahern7a35a502018-12-05 20:02:29 -08001932 }
WANG Congd7480fd2014-11-10 15:59:36 -08001933
David Ahernb8fb1ab2019-04-16 17:31:43 -07001934 if (tbl->allow_add && !tbl->allow_add(dev, extack)) {
1935 err = -EINVAL;
1936 goto out;
1937 }
1938
WANG Congd7480fd2014-11-10 15:59:36 -08001939 neigh = neigh_lookup(tbl, dst, dev);
1940 if (neigh == NULL) {
David Aherne997f8a2018-12-11 18:57:25 -07001941 bool exempt_from_gc;
1942
WANG Congd7480fd2014-11-10 15:59:36 -08001943 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
1944 err = -ENOENT;
1945 goto out;
1946 }
1947
David Aherne997f8a2018-12-11 18:57:25 -07001948 exempt_from_gc = ndm->ndm_state & NUD_PERMANENT ||
1949 ndm->ndm_flags & NTF_EXT_LEARNED;
1950 neigh = ___neigh_create(tbl, dst, dev, exempt_from_gc, true);
WANG Congd7480fd2014-11-10 15:59:36 -08001951 if (IS_ERR(neigh)) {
1952 err = PTR_ERR(neigh);
1953 goto out;
1954 }
1955 } else {
1956 if (nlh->nlmsg_flags & NLM_F_EXCL) {
1957 err = -EEXIST;
1958 neigh_release(neigh);
1959 goto out;
1960 }
1961
1962 if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
Roopa Prabhuf7aa74e2018-09-22 21:26:19 -07001963 flags &= ~(NEIGH_UPDATE_F_OVERRIDE |
1964 NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
WANG Congd7480fd2014-11-10 15:59:36 -08001965 }
1966
Roman Mashak38212bb2020-05-01 21:34:18 -04001967 if (protocol)
1968 neigh->protocol = protocol;
1969
Roopa Prabhu9ce33e42018-04-24 13:49:34 -07001970 if (ndm->ndm_flags & NTF_EXT_LEARNED)
1971 flags |= NEIGH_UPDATE_F_EXT_LEARNED;
1972
Roopa Prabhuf7aa74e2018-09-22 21:26:19 -07001973 if (ndm->ndm_flags & NTF_ROUTER)
1974 flags |= NEIGH_UPDATE_F_ISROUTER;
1975
WANG Congd7480fd2014-11-10 15:59:36 -08001976 if (ndm->ndm_flags & NTF_USE) {
1977 neigh_event_send(neigh, NULL);
1978 err = 0;
1979 } else
David Ahern7a35a502018-12-05 20:02:29 -08001980 err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
1981 NETLINK_CB(skb).portid, extack);
David Aherndf9b0e32018-12-15 14:09:06 -08001982
WANG Congd7480fd2014-11-10 15:59:36 -08001983 neigh_release(neigh);
1984
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985out:
1986 return err;
1987}
1988
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001989static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1990{
Thomas Grafca860fb2006-08-07 18:00:18 -07001991 struct nlattr *nest;
1992
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001993 nest = nla_nest_start_noflag(skb, NDTA_PARMS);
Thomas Grafca860fb2006-08-07 18:00:18 -07001994 if (nest == NULL)
1995 return -ENOBUFS;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001996
David S. Miller9a6308d2012-04-01 20:06:28 -04001997 if ((parms->dev &&
1998 nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
Reshetova, Elena63439442017-06-30 13:07:56 +03001999 nla_put_u32(skb, NDTPA_REFCNT, refcount_read(&parms->refcnt)) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002000 nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
2001 NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04002002 /* approximative value for deprecated QUEUE_LEN (in packets) */
2003 nla_put_u32(skb, NDTPA_QUEUE_LEN,
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002004 NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
2005 nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
2006 nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
2007 nla_put_u32(skb, NDTPA_UCAST_PROBES,
2008 NEIGH_VAR(parms, UCAST_PROBES)) ||
2009 nla_put_u32(skb, NDTPA_MCAST_PROBES,
2010 NEIGH_VAR(parms, MCAST_PROBES)) ||
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +09002011 nla_put_u32(skb, NDTPA_MCAST_REPROBES,
2012 NEIGH_VAR(parms, MCAST_REPROBES)) ||
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002013 nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time,
2014 NDTPA_PAD) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04002015 nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002016 NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002017 nla_put_msecs(skb, NDTPA_GC_STALETIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002018 NEIGH_VAR(parms, GC_STALETIME), NDTPA_PAD) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04002019 nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002020 NEIGH_VAR(parms, DELAY_PROBE_TIME), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002021 nla_put_msecs(skb, NDTPA_RETRANS_TIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002022 NEIGH_VAR(parms, RETRANS_TIME), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002023 nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002024 NEIGH_VAR(parms, ANYCAST_DELAY), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002025 nla_put_msecs(skb, NDTPA_PROXY_DELAY,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002026 NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) ||
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002027 nla_put_msecs(skb, NDTPA_LOCKTIME,
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002028 NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD))
David S. Miller9a6308d2012-04-01 20:06:28 -04002029 goto nla_put_failure;
Thomas Grafca860fb2006-08-07 18:00:18 -07002030 return nla_nest_end(skb, nest);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002031
Thomas Grafca860fb2006-08-07 18:00:18 -07002032nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07002033 nla_nest_cancel(skb, nest);
2034 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002035}
2036
Thomas Grafca860fb2006-08-07 18:00:18 -07002037static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
2038 u32 pid, u32 seq, int type, int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002039{
2040 struct nlmsghdr *nlh;
2041 struct ndtmsg *ndtmsg;
2042
Thomas Grafca860fb2006-08-07 18:00:18 -07002043 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2044 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002045 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002046
Thomas Grafca860fb2006-08-07 18:00:18 -07002047 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002048
2049 read_lock_bh(&tbl->lock);
2050 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002051 ndtmsg->ndtm_pad1 = 0;
2052 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002053
David S. Miller9a6308d2012-04-01 20:06:28 -04002054 if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
Nicolas Dichtel2175d872016-04-22 17:31:21 +02002055 nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval, NDTA_PAD) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04002056 nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
2057 nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
2058 nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
2059 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002060 {
2061 unsigned long now = jiffies;
Eric Dumazet9d027e32019-11-05 14:11:49 -08002062 long flush_delta = now - tbl->last_flush;
2063 long rand_delta = now - tbl->last_rand;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002064 struct neigh_hash_table *nht;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002065 struct ndt_config ndc = {
2066 .ndtc_key_len = tbl->key_len,
2067 .ndtc_entry_size = tbl->entry_size,
2068 .ndtc_entries = atomic_read(&tbl->entries),
2069 .ndtc_last_flush = jiffies_to_msecs(flush_delta),
2070 .ndtc_last_rand = jiffies_to_msecs(rand_delta),
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002071 .ndtc_proxy_qlen = tbl->proxy_queue.qlen,
2072 };
2073
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002074 rcu_read_lock_bh();
2075 nht = rcu_dereference_bh(tbl->nht);
David S. Miller2c2aba62011-12-28 15:06:58 -05002076 ndc.ndtc_hash_rnd = nht->hash_rnd[0];
David S. Millercd089332011-07-11 01:28:12 -07002077 ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002078 rcu_read_unlock_bh();
2079
David S. Miller9a6308d2012-04-01 20:06:28 -04002080 if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
2081 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002082 }
2083
2084 {
2085 int cpu;
2086 struct ndt_stats ndst;
2087
2088 memset(&ndst, 0, sizeof(ndst));
2089
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07002090 for_each_possible_cpu(cpu) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002091 struct neigh_statistics *st;
2092
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002093 st = per_cpu_ptr(tbl->stats, cpu);
2094 ndst.ndts_allocs += st->allocs;
2095 ndst.ndts_destroys += st->destroys;
2096 ndst.ndts_hash_grows += st->hash_grows;
2097 ndst.ndts_res_failed += st->res_failed;
2098 ndst.ndts_lookups += st->lookups;
2099 ndst.ndts_hits += st->hits;
2100 ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast;
2101 ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast;
2102 ndst.ndts_periodic_gc_runs += st->periodic_gc_runs;
2103 ndst.ndts_forced_gc_runs += st->forced_gc_runs;
Rick Jonesfb811392015-08-07 11:10:37 -07002104 ndst.ndts_table_fulls += st->table_fulls;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002105 }
2106
Nicolas Dichtelb6763382016-04-26 10:06:17 +02002107 if (nla_put_64bit(skb, NDTA_STATS, sizeof(ndst), &ndst,
2108 NDTA_PAD))
David S. Miller9a6308d2012-04-01 20:06:28 -04002109 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002110 }
2111
2112 BUG_ON(tbl->parms.dev);
2113 if (neightbl_fill_parms(skb, &tbl->parms) < 0)
Thomas Grafca860fb2006-08-07 18:00:18 -07002114 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002115
2116 read_unlock_bh(&tbl->lock);
Johannes Berg053c0952015-01-16 22:09:00 +01002117 nlmsg_end(skb, nlh);
2118 return 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002119
Thomas Grafca860fb2006-08-07 18:00:18 -07002120nla_put_failure:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002121 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08002122 nlmsg_cancel(skb, nlh);
2123 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002124}
2125
Thomas Grafca860fb2006-08-07 18:00:18 -07002126static int neightbl_fill_param_info(struct sk_buff *skb,
2127 struct neigh_table *tbl,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002128 struct neigh_parms *parms,
Thomas Grafca860fb2006-08-07 18:00:18 -07002129 u32 pid, u32 seq, int type,
2130 unsigned int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002131{
2132 struct ndtmsg *ndtmsg;
2133 struct nlmsghdr *nlh;
2134
Thomas Grafca860fb2006-08-07 18:00:18 -07002135 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
2136 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002137 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002138
Thomas Grafca860fb2006-08-07 18:00:18 -07002139 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002140
2141 read_lock_bh(&tbl->lock);
2142 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002143 ndtmsg->ndtm_pad1 = 0;
2144 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002145
Thomas Grafca860fb2006-08-07 18:00:18 -07002146 if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
2147 neightbl_fill_parms(skb, parms) < 0)
2148 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002149
2150 read_unlock_bh(&tbl->lock);
Johannes Berg053c0952015-01-16 22:09:00 +01002151 nlmsg_end(skb, nlh);
2152 return 0;
Thomas Grafca860fb2006-08-07 18:00:18 -07002153errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002154 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08002155 nlmsg_cancel(skb, nlh);
2156 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002157}
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002158
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002159static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07002160 [NDTA_NAME] = { .type = NLA_STRING },
2161 [NDTA_THRESH1] = { .type = NLA_U32 },
2162 [NDTA_THRESH2] = { .type = NLA_U32 },
2163 [NDTA_THRESH3] = { .type = NLA_U32 },
2164 [NDTA_GC_INTERVAL] = { .type = NLA_U64 },
2165 [NDTA_PARMS] = { .type = NLA_NESTED },
2166};
2167
Patrick McHardyef7c79e2007-06-05 12:38:30 -07002168static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07002169 [NDTPA_IFINDEX] = { .type = NLA_U32 },
2170 [NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
2171 [NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
2172 [NDTPA_APP_PROBES] = { .type = NLA_U32 },
2173 [NDTPA_UCAST_PROBES] = { .type = NLA_U32 },
2174 [NDTPA_MCAST_PROBES] = { .type = NLA_U32 },
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +09002175 [NDTPA_MCAST_REPROBES] = { .type = NLA_U32 },
Thomas Graf6b3f8672006-08-07 17:58:53 -07002176 [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 },
2177 [NDTPA_GC_STALETIME] = { .type = NLA_U64 },
2178 [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 },
2179 [NDTPA_RETRANS_TIME] = { .type = NLA_U64 },
2180 [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
2181 [NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
2182 [NDTPA_LOCKTIME] = { .type = NLA_U64 },
2183};
2184
David Ahernc21ef3e2017-04-16 09:48:24 -07002185static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
2186 struct netlink_ext_ack *extack)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002187{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002188 struct net *net = sock_net(skb->sk);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002189 struct neigh_table *tbl;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002190 struct ndtmsg *ndtmsg;
2191 struct nlattr *tb[NDTA_MAX+1];
WANG Congd7480fd2014-11-10 15:59:36 -08002192 bool found = false;
2193 int err, tidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002194
Johannes Berg8cb08172019-04-26 14:07:28 +02002195 err = nlmsg_parse_deprecated(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
2196 nl_neightbl_policy, extack);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002197 if (err < 0)
2198 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002199
Thomas Graf6b3f8672006-08-07 17:58:53 -07002200 if (tb[NDTA_NAME] == NULL) {
2201 err = -EINVAL;
2202 goto errout;
2203 }
2204
2205 ndtmsg = nlmsg_data(nlh);
WANG Congd7480fd2014-11-10 15:59:36 -08002206
2207 for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
2208 tbl = neigh_tables[tidx];
2209 if (!tbl)
2210 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002211 if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
2212 continue;
WANG Congd7480fd2014-11-10 15:59:36 -08002213 if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) {
2214 found = true;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002215 break;
WANG Congd7480fd2014-11-10 15:59:36 -08002216 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002217 }
2218
WANG Congd7480fd2014-11-10 15:59:36 -08002219 if (!found)
2220 return -ENOENT;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002221
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002222 /*
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002223 * We acquire tbl->lock to be nice to the periodic timers and
2224 * make sure they always see a consistent set of values.
2225 */
2226 write_lock_bh(&tbl->lock);
2227
Thomas Graf6b3f8672006-08-07 17:58:53 -07002228 if (tb[NDTA_PARMS]) {
2229 struct nlattr *tbp[NDTPA_MAX+1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002230 struct neigh_parms *p;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002231 int i, ifindex = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002232
Johannes Berg8cb08172019-04-26 14:07:28 +02002233 err = nla_parse_nested_deprecated(tbp, NDTPA_MAX,
2234 tb[NDTA_PARMS],
2235 nl_ntbl_parm_policy, extack);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002236 if (err < 0)
2237 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002238
Thomas Graf6b3f8672006-08-07 17:58:53 -07002239 if (tbp[NDTPA_IFINDEX])
2240 ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002241
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07002242 p = lookup_neigh_parms(tbl, net, ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002243 if (p == NULL) {
2244 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002245 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002246 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002247
Thomas Graf6b3f8672006-08-07 17:58:53 -07002248 for (i = 1; i <= NDTPA_MAX; i++) {
2249 if (tbp[i] == NULL)
2250 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002251
Thomas Graf6b3f8672006-08-07 17:58:53 -07002252 switch (i) {
2253 case NDTPA_QUEUE_LEN:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002254 NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
2255 nla_get_u32(tbp[i]) *
2256 SKB_TRUESIZE(ETH_FRAME_LEN));
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002257 break;
2258 case NDTPA_QUEUE_LENBYTES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002259 NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
2260 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002261 break;
2262 case NDTPA_PROXY_QLEN:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002263 NEIGH_VAR_SET(p, PROXY_QLEN,
2264 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002265 break;
2266 case NDTPA_APP_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002267 NEIGH_VAR_SET(p, APP_PROBES,
2268 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002269 break;
2270 case NDTPA_UCAST_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002271 NEIGH_VAR_SET(p, UCAST_PROBES,
2272 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002273 break;
2274 case NDTPA_MCAST_PROBES:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002275 NEIGH_VAR_SET(p, MCAST_PROBES,
2276 nla_get_u32(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002277 break;
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +09002278 case NDTPA_MCAST_REPROBES:
2279 NEIGH_VAR_SET(p, MCAST_REPROBES,
2280 nla_get_u32(tbp[i]));
2281 break;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002282 case NDTPA_BASE_REACHABLE_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002283 NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
2284 nla_get_msecs(tbp[i]));
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01002285 /* update reachable_time as well, otherwise, the change will
2286 * only be effective after the next time neigh_periodic_work
2287 * decides to recompute it (can be multiple minutes)
2288 */
2289 p->reachable_time =
2290 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002291 break;
2292 case NDTPA_GC_STALETIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002293 NEIGH_VAR_SET(p, GC_STALETIME,
2294 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002295 break;
2296 case NDTPA_DELAY_PROBE_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002297 NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
2298 nla_get_msecs(tbp[i]));
Ido Schimmel2a4501a2016-07-05 11:27:42 +02002299 call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002300 break;
2301 case NDTPA_RETRANS_TIME:
Jiri Pirko1f9248e2013-12-07 19:26:53 +01002302 NEIGH_VAR_SET(p, RETRANS_TIME,
2303 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002304 break;
2305 case NDTPA_ANYCAST_DELAY:
Jiri Pirko39774582014-01-14 15:46:07 +01002306 NEIGH_VAR_SET(p, ANYCAST_DELAY,
2307 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002308 break;
2309 case NDTPA_PROXY_DELAY:
Jiri Pirko39774582014-01-14 15:46:07 +01002310 NEIGH_VAR_SET(p, PROXY_DELAY,
2311 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002312 break;
2313 case NDTPA_LOCKTIME:
Jiri Pirko39774582014-01-14 15:46:07 +01002314 NEIGH_VAR_SET(p, LOCKTIME,
2315 nla_get_msecs(tbp[i]));
Thomas Graf6b3f8672006-08-07 17:58:53 -07002316 break;
2317 }
2318 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002319 }
2320
Gao fengdc25c672013-06-20 10:01:34 +08002321 err = -ENOENT;
2322 if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
2323 tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
2324 !net_eq(net, &init_net))
2325 goto errout_tbl_lock;
2326
Thomas Graf6b3f8672006-08-07 17:58:53 -07002327 if (tb[NDTA_THRESH1])
2328 tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
2329
2330 if (tb[NDTA_THRESH2])
2331 tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
2332
2333 if (tb[NDTA_THRESH3])
2334 tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
2335
2336 if (tb[NDTA_GC_INTERVAL])
2337 tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2338
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002339 err = 0;
2340
Thomas Graf6b3f8672006-08-07 17:58:53 -07002341errout_tbl_lock:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002342 write_unlock_bh(&tbl->lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002343errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002344 return err;
2345}
2346
David Ahern9632d472018-10-07 20:16:37 -07002347static int neightbl_valid_dump_info(const struct nlmsghdr *nlh,
2348 struct netlink_ext_ack *extack)
2349{
2350 struct ndtmsg *ndtm;
2351
2352 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) {
2353 NL_SET_ERR_MSG(extack, "Invalid header for neighbor table dump request");
2354 return -EINVAL;
2355 }
2356
2357 ndtm = nlmsg_data(nlh);
2358 if (ndtm->ndtm_pad1 || ndtm->ndtm_pad2) {
2359 NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor table dump request");
2360 return -EINVAL;
2361 }
2362
2363 if (nlmsg_attrlen(nlh, sizeof(*ndtm))) {
2364 NL_SET_ERR_MSG(extack, "Invalid data after header in neighbor table dump request");
2365 return -EINVAL;
2366 }
2367
2368 return 0;
2369}
2370
Thomas Grafc8822a42007-03-22 11:50:06 -07002371static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002372{
David Ahern9632d472018-10-07 20:16:37 -07002373 const struct nlmsghdr *nlh = cb->nlh;
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002374 struct net *net = sock_net(skb->sk);
Thomas Grafca860fb2006-08-07 18:00:18 -07002375 int family, tidx, nidx = 0;
2376 int tbl_skip = cb->args[0];
2377 int neigh_skip = cb->args[1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002378 struct neigh_table *tbl;
2379
David Ahern9632d472018-10-07 20:16:37 -07002380 if (cb->strict_check) {
2381 int err = neightbl_valid_dump_info(nlh, cb->extack);
2382
2383 if (err < 0)
2384 return err;
2385 }
2386
2387 family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002388
WANG Congd7480fd2014-11-10 15:59:36 -08002389 for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002390 struct neigh_parms *p;
2391
WANG Congd7480fd2014-11-10 15:59:36 -08002392 tbl = neigh_tables[tidx];
2393 if (!tbl)
2394 continue;
2395
Thomas Grafca860fb2006-08-07 18:00:18 -07002396 if (tidx < tbl_skip || (family && tbl->family != family))
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002397 continue;
2398
Eric W. Biederman15e47302012-09-07 20:12:54 +00002399 if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
David Ahern9632d472018-10-07 20:16:37 -07002400 nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
David S. Miller7b46a642015-01-18 23:36:08 -05002401 NLM_F_MULTI) < 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002402 break;
2403
Nicolas Dichtel75fbfd32014-10-29 19:29:31 +01002404 nidx = 0;
2405 p = list_next_entry(&tbl->parms, list);
2406 list_for_each_entry_from(p, &tbl->parms_list, list) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002407 if (!net_eq(neigh_parms_net(p), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002408 continue;
2409
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002410 if (nidx < neigh_skip)
2411 goto next;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002412
Thomas Grafca860fb2006-08-07 18:00:18 -07002413 if (neightbl_fill_param_info(skb, tbl, p,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002414 NETLINK_CB(cb->skb).portid,
David Ahern9632d472018-10-07 20:16:37 -07002415 nlh->nlmsg_seq,
Thomas Grafca860fb2006-08-07 18:00:18 -07002416 RTM_NEWNEIGHTBL,
David S. Miller7b46a642015-01-18 23:36:08 -05002417 NLM_F_MULTI) < 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002418 goto out;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002419 next:
2420 nidx++;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002421 }
2422
Thomas Grafca860fb2006-08-07 18:00:18 -07002423 neigh_skip = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002424 }
2425out:
Thomas Grafca860fb2006-08-07 18:00:18 -07002426 cb->args[0] = tidx;
2427 cb->args[1] = nidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002428
2429 return skb->len;
2430}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431
Thomas Graf8b8aec52006-08-07 17:56:37 -07002432static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
2433 u32 pid, u32 seq, int type, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434{
2435 unsigned long now = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 struct nda_cacheinfo ci;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002437 struct nlmsghdr *nlh;
2438 struct ndmsg *ndm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439
Thomas Graf8b8aec52006-08-07 17:56:37 -07002440 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2441 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002442 return -EMSGSIZE;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002443
2444 ndm = nlmsg_data(nlh);
2445 ndm->ndm_family = neigh->ops->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002446 ndm->ndm_pad1 = 0;
2447 ndm->ndm_pad2 = 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002448 ndm->ndm_flags = neigh->flags;
2449 ndm->ndm_type = neigh->type;
2450 ndm->ndm_ifindex = neigh->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
David S. Miller9a6308d2012-04-01 20:06:28 -04002452 if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
2453 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002454
2455 read_lock_bh(&neigh->lock);
2456 ndm->ndm_state = neigh->nud_state;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00002457 if (neigh->nud_state & NUD_VALID) {
2458 char haddr[MAX_ADDR_LEN];
2459
2460 neigh_ha_snapshot(haddr, neigh, neigh->dev);
2461 if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
2462 read_unlock_bh(&neigh->lock);
2463 goto nla_put_failure;
2464 }
Thomas Graf8b8aec52006-08-07 17:56:37 -07002465 }
2466
Stephen Hemmingerb9f5f522008-06-03 16:03:15 -07002467 ci.ndm_used = jiffies_to_clock_t(now - neigh->used);
2468 ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2469 ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated);
Reshetova, Elena9f237432017-06-30 13:07:55 +03002470 ci.ndm_refcnt = refcount_read(&neigh->refcnt) - 1;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002471 read_unlock_bh(&neigh->lock);
2472
David S. Miller9a6308d2012-04-01 20:06:28 -04002473 if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
2474 nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
2475 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002476
David Aherndf9b0e32018-12-15 14:09:06 -08002477 if (neigh->protocol && nla_put_u8(skb, NDA_PROTOCOL, neigh->protocol))
2478 goto nla_put_failure;
2479
Johannes Berg053c0952015-01-16 22:09:00 +01002480 nlmsg_end(skb, nlh);
2481 return 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002482
2483nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002484 nlmsg_cancel(skb, nlh);
2485 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486}
2487
Tony Zelenoff84920c12012-01-26 22:28:58 +00002488static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
2489 u32 pid, u32 seq, int type, unsigned int flags,
2490 struct neigh_table *tbl)
2491{
2492 struct nlmsghdr *nlh;
2493 struct ndmsg *ndm;
2494
2495 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2496 if (nlh == NULL)
2497 return -EMSGSIZE;
2498
2499 ndm = nlmsg_data(nlh);
2500 ndm->ndm_family = tbl->family;
2501 ndm->ndm_pad1 = 0;
2502 ndm->ndm_pad2 = 0;
2503 ndm->ndm_flags = pn->flags | NTF_PROXY;
Jun Zhao545469f2014-07-26 00:38:59 +08002504 ndm->ndm_type = RTN_UNICAST;
Konstantin Khlebnikov6adc5fd2015-12-01 01:14:48 +03002505 ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002506 ndm->ndm_state = NUD_NONE;
2507
David S. Miller9a6308d2012-04-01 20:06:28 -04002508 if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
2509 goto nla_put_failure;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002510
David Aherndf9b0e32018-12-15 14:09:06 -08002511 if (pn->protocol && nla_put_u8(skb, NDA_PROTOCOL, pn->protocol))
2512 goto nla_put_failure;
2513
Johannes Berg053c0952015-01-16 22:09:00 +01002514 nlmsg_end(skb, nlh);
2515 return 0;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002516
2517nla_put_failure:
2518 nlmsg_cancel(skb, nlh);
2519 return -EMSGSIZE;
2520}
2521
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07002522static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid)
Thomas Grafd961db32007-08-08 23:12:56 -07002523{
2524 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07002525 __neigh_notify(neigh, RTM_NEWNEIGH, 0, nlmsg_pid);
Thomas Grafd961db32007-08-08 23:12:56 -07002526}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527
David Ahern21fdd092015-09-29 09:32:03 -07002528static bool neigh_master_filtered(struct net_device *dev, int master_idx)
2529{
2530 struct net_device *master;
2531
2532 if (!master_idx)
2533 return false;
2534
Eric Dumazetaab456d2018-10-26 09:33:27 -07002535 master = dev ? netdev_master_upper_dev_get(dev) : NULL;
David Ahern21fdd092015-09-29 09:32:03 -07002536 if (!master || master->ifindex != master_idx)
2537 return true;
2538
2539 return false;
2540}
2541
David Ahern16660f02015-10-03 11:43:46 -07002542static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx)
2543{
Eric Dumazetaab456d2018-10-26 09:33:27 -07002544 if (filter_idx && (!dev || dev->ifindex != filter_idx))
David Ahern16660f02015-10-03 11:43:46 -07002545 return true;
2546
2547 return false;
2548}
2549
David Ahern6f52f802018-10-03 15:33:12 -07002550struct neigh_dump_filter {
2551 int master_idx;
2552 int dev_idx;
2553};
2554
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
David Ahern6f52f802018-10-03 15:33:12 -07002556 struct netlink_callback *cb,
2557 struct neigh_dump_filter *filter)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558{
Eric Dumazet767e97e2010-10-06 17:49:21 -07002559 struct net *net = sock_net(skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 struct neighbour *n;
2561 int rc, h, s_h = cb->args[1];
2562 int idx, s_idx = idx = cb->args[2];
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002563 struct neigh_hash_table *nht;
David Ahern21fdd092015-09-29 09:32:03 -07002564 unsigned int flags = NLM_F_MULTI;
David Ahern21fdd092015-09-29 09:32:03 -07002565
David Ahern6f52f802018-10-03 15:33:12 -07002566 if (filter->dev_idx || filter->master_idx)
2567 flags |= NLM_F_DUMP_FILTERED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002569 rcu_read_lock_bh();
2570 nht = rcu_dereference_bh(tbl->nht);
2571
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002572 for (h = s_h; h < (1 << nht->hash_shift); h++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 if (h > s_h)
2574 s_idx = 0;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002575 for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2576 n != NULL;
2577 n = rcu_dereference_bh(n->next)) {
Zhang Shengju18502ac2016-11-30 11:24:42 +08002578 if (idx < s_idx || !net_eq(dev_net(n->dev), net))
2579 goto next;
David Ahern6f52f802018-10-03 15:33:12 -07002580 if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
2581 neigh_master_filtered(n->dev, filter->master_idx))
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002582 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002583 if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 cb->nlh->nlmsg_seq,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07002585 RTM_NEWNEIGH,
David Ahern21fdd092015-09-29 09:32:03 -07002586 flags) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 rc = -1;
2588 goto out;
2589 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002590next:
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002591 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 }
2594 rc = skb->len;
2595out:
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002596 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 cb->args[1] = h;
2598 cb->args[2] = idx;
2599 return rc;
2600}
2601
Tony Zelenoff84920c12012-01-26 22:28:58 +00002602static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
David Ahern6f52f802018-10-03 15:33:12 -07002603 struct netlink_callback *cb,
2604 struct neigh_dump_filter *filter)
Tony Zelenoff84920c12012-01-26 22:28:58 +00002605{
2606 struct pneigh_entry *n;
2607 struct net *net = sock_net(skb->sk);
2608 int rc, h, s_h = cb->args[3];
2609 int idx, s_idx = idx = cb->args[4];
David Ahern6f52f802018-10-03 15:33:12 -07002610 unsigned int flags = NLM_F_MULTI;
2611
2612 if (filter->dev_idx || filter->master_idx)
2613 flags |= NLM_F_DUMP_FILTERED;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002614
2615 read_lock_bh(&tbl->lock);
2616
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002617 for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
Tony Zelenoff84920c12012-01-26 22:28:58 +00002618 if (h > s_h)
2619 s_idx = 0;
2620 for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
Zhang Shengju18502ac2016-11-30 11:24:42 +08002621 if (idx < s_idx || pneigh_net(n) != net)
Tony Zelenoff84920c12012-01-26 22:28:58 +00002622 goto next;
David Ahern6f52f802018-10-03 15:33:12 -07002623 if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
2624 neigh_master_filtered(n->dev, filter->master_idx))
2625 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002626 if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Tony Zelenoff84920c12012-01-26 22:28:58 +00002627 cb->nlh->nlmsg_seq,
David Ahern6f52f802018-10-03 15:33:12 -07002628 RTM_NEWNEIGH, flags, tbl) < 0) {
Tony Zelenoff84920c12012-01-26 22:28:58 +00002629 read_unlock_bh(&tbl->lock);
2630 rc = -1;
2631 goto out;
2632 }
2633 next:
2634 idx++;
2635 }
2636 }
2637
2638 read_unlock_bh(&tbl->lock);
2639 rc = skb->len;
2640out:
2641 cb->args[3] = h;
2642 cb->args[4] = idx;
2643 return rc;
2644
2645}
2646
David Ahern51183d22018-10-07 20:16:36 -07002647static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
2648 bool strict_check,
2649 struct neigh_dump_filter *filter,
2650 struct netlink_ext_ack *extack)
2651{
2652 struct nlattr *tb[NDA_MAX + 1];
2653 int err, i;
2654
2655 if (strict_check) {
2656 struct ndmsg *ndm;
2657
2658 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
2659 NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request");
2660 return -EINVAL;
2661 }
2662
2663 ndm = nlmsg_data(nlh);
2664 if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_ifindex ||
David Ahernc0fde872018-12-19 16:54:38 -08002665 ndm->ndm_state || ndm->ndm_type) {
David Ahern51183d22018-10-07 20:16:36 -07002666 NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request");
2667 return -EINVAL;
2668 }
2669
David Ahernc0fde872018-12-19 16:54:38 -08002670 if (ndm->ndm_flags & ~NTF_PROXY) {
2671 NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor dump request");
2672 return -EINVAL;
2673 }
2674
Johannes Berg8cb08172019-04-26 14:07:28 +02002675 err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg),
2676 tb, NDA_MAX, nda_policy,
2677 extack);
David Ahern51183d22018-10-07 20:16:36 -07002678 } else {
Johannes Berg8cb08172019-04-26 14:07:28 +02002679 err = nlmsg_parse_deprecated(nlh, sizeof(struct ndmsg), tb,
2680 NDA_MAX, nda_policy, extack);
David Ahern51183d22018-10-07 20:16:36 -07002681 }
2682 if (err < 0)
2683 return err;
2684
2685 for (i = 0; i <= NDA_MAX; ++i) {
2686 if (!tb[i])
2687 continue;
2688
2689 /* all new attributes should require strict_check */
2690 switch (i) {
2691 case NDA_IFINDEX:
David Ahern51183d22018-10-07 20:16:36 -07002692 filter->dev_idx = nla_get_u32(tb[i]);
2693 break;
2694 case NDA_MASTER:
David Ahern51183d22018-10-07 20:16:36 -07002695 filter->master_idx = nla_get_u32(tb[i]);
2696 break;
2697 default:
2698 if (strict_check) {
2699 NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request");
2700 return -EINVAL;
2701 }
2702 }
2703 }
2704
2705 return 0;
2706}
2707
Thomas Grafc8822a42007-03-22 11:50:06 -07002708static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709{
David Ahern6f52f802018-10-03 15:33:12 -07002710 const struct nlmsghdr *nlh = cb->nlh;
2711 struct neigh_dump_filter filter = {};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 struct neigh_table *tbl;
2713 int t, family, s_t;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002714 int proxy = 0;
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002715 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
David Ahern6f52f802018-10-03 15:33:12 -07002717 family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002718
2719 /* check for full ndmsg structure presence, family member is
2720 * the same for both structures
2721 */
David Ahern6f52f802018-10-03 15:33:12 -07002722 if (nlmsg_len(nlh) >= sizeof(struct ndmsg) &&
2723 ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY)
Tony Zelenoff84920c12012-01-26 22:28:58 +00002724 proxy = 1;
2725
David Ahern51183d22018-10-07 20:16:36 -07002726 err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack);
2727 if (err < 0 && cb->strict_check)
2728 return err;
2729
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 s_t = cb->args[0];
2731
WANG Congd7480fd2014-11-10 15:59:36 -08002732 for (t = 0; t < NEIGH_NR_TABLES; t++) {
2733 tbl = neigh_tables[t];
2734
2735 if (!tbl)
2736 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 if (t < s_t || (family && tbl->family != family))
2738 continue;
2739 if (t > s_t)
2740 memset(&cb->args[1], 0, sizeof(cb->args) -
2741 sizeof(cb->args[0]));
Tony Zelenoff84920c12012-01-26 22:28:58 +00002742 if (proxy)
David Ahern6f52f802018-10-03 15:33:12 -07002743 err = pneigh_dump_table(tbl, skb, cb, &filter);
Tony Zelenoff84920c12012-01-26 22:28:58 +00002744 else
David Ahern6f52f802018-10-03 15:33:12 -07002745 err = neigh_dump_table(tbl, skb, cb, &filter);
Eric Dumazet4bd6683b2012-06-07 04:58:35 +00002746 if (err < 0)
2747 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749
2750 cb->args[0] = t;
2751 return skb->len;
2752}
2753
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08002754static int neigh_valid_get_req(const struct nlmsghdr *nlh,
2755 struct neigh_table **tbl,
2756 void **dst, int *dev_idx, u8 *ndm_flags,
2757 struct netlink_ext_ack *extack)
2758{
2759 struct nlattr *tb[NDA_MAX + 1];
2760 struct ndmsg *ndm;
2761 int err, i;
2762
2763 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
2764 NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request");
2765 return -EINVAL;
2766 }
2767
2768 ndm = nlmsg_data(nlh);
2769 if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_state ||
2770 ndm->ndm_type) {
2771 NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request");
2772 return -EINVAL;
2773 }
2774
2775 if (ndm->ndm_flags & ~NTF_PROXY) {
2776 NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request");
2777 return -EINVAL;
2778 }
2779
Johannes Berg8cb08172019-04-26 14:07:28 +02002780 err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb,
2781 NDA_MAX, nda_policy, extack);
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08002782 if (err < 0)
2783 return err;
2784
2785 *ndm_flags = ndm->ndm_flags;
2786 *dev_idx = ndm->ndm_ifindex;
2787 *tbl = neigh_find_table(ndm->ndm_family);
2788 if (*tbl == NULL) {
2789 NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
2790 return -EAFNOSUPPORT;
2791 }
2792
2793 for (i = 0; i <= NDA_MAX; ++i) {
2794 if (!tb[i])
2795 continue;
2796
2797 switch (i) {
2798 case NDA_DST:
2799 if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
2800 NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
2801 return -EINVAL;
2802 }
2803 *dst = nla_data(tb[i]);
2804 break;
2805 default:
2806 NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
2807 return -EINVAL;
2808 }
2809 }
2810
2811 return 0;
2812}
2813
2814static inline size_t neigh_nlmsg_size(void)
2815{
2816 return NLMSG_ALIGN(sizeof(struct ndmsg))
2817 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2818 + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2819 + nla_total_size(sizeof(struct nda_cacheinfo))
2820 + nla_total_size(4) /* NDA_PROBES */
2821 + nla_total_size(1); /* NDA_PROTOCOL */
2822}
2823
2824static int neigh_get_reply(struct net *net, struct neighbour *neigh,
2825 u32 pid, u32 seq)
2826{
2827 struct sk_buff *skb;
2828 int err = 0;
2829
2830 skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL);
2831 if (!skb)
2832 return -ENOBUFS;
2833
2834 err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0);
2835 if (err) {
2836 kfree_skb(skb);
2837 goto errout;
2838 }
2839
2840 err = rtnl_unicast(skb, net, pid);
2841errout:
2842 return err;
2843}
2844
2845static inline size_t pneigh_nlmsg_size(void)
2846{
2847 return NLMSG_ALIGN(sizeof(struct ndmsg))
Colin Ian King463561e2018-12-20 16:50:50 +00002848 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08002849 + nla_total_size(1); /* NDA_PROTOCOL */
2850}
2851
2852static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh,
2853 u32 pid, u32 seq, struct neigh_table *tbl)
2854{
2855 struct sk_buff *skb;
2856 int err = 0;
2857
2858 skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL);
2859 if (!skb)
2860 return -ENOBUFS;
2861
2862 err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl);
2863 if (err) {
2864 kfree_skb(skb);
2865 goto errout;
2866 }
2867
2868 err = rtnl_unicast(skb, net, pid);
2869errout:
2870 return err;
2871}
2872
2873static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
2874 struct netlink_ext_ack *extack)
2875{
2876 struct net *net = sock_net(in_skb->sk);
2877 struct net_device *dev = NULL;
2878 struct neigh_table *tbl = NULL;
2879 struct neighbour *neigh;
2880 void *dst = NULL;
2881 u8 ndm_flags = 0;
2882 int dev_idx = 0;
2883 int err;
2884
2885 err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags,
2886 extack);
2887 if (err < 0)
2888 return err;
2889
2890 if (dev_idx) {
2891 dev = __dev_get_by_index(net, dev_idx);
2892 if (!dev) {
2893 NL_SET_ERR_MSG(extack, "Unknown device ifindex");
2894 return -ENODEV;
2895 }
2896 }
2897
2898 if (!dst) {
2899 NL_SET_ERR_MSG(extack, "Network address not specified");
2900 return -EINVAL;
2901 }
2902
2903 if (ndm_flags & NTF_PROXY) {
2904 struct pneigh_entry *pn;
2905
2906 pn = pneigh_lookup(tbl, net, dst, dev, 0);
2907 if (!pn) {
2908 NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found");
2909 return -ENOENT;
2910 }
2911 return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid,
2912 nlh->nlmsg_seq, tbl);
2913 }
2914
2915 if (!dev) {
2916 NL_SET_ERR_MSG(extack, "No device specified");
2917 return -EINVAL;
2918 }
2919
2920 neigh = neigh_lookup(tbl, dst, dev);
2921 if (!neigh) {
2922 NL_SET_ERR_MSG(extack, "Neighbour entry not found");
2923 return -ENOENT;
2924 }
2925
2926 err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid,
2927 nlh->nlmsg_seq);
2928
2929 neigh_release(neigh);
2930
2931 return err;
2932}
2933
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
2935{
2936 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002937 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002939 rcu_read_lock_bh();
2940 nht = rcu_dereference_bh(tbl->nht);
2941
Eric Dumazet767e97e2010-10-06 17:49:21 -07002942 read_lock(&tbl->lock); /* avoid resizes */
David S. Millercd089332011-07-11 01:28:12 -07002943 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 struct neighbour *n;
2945
Eric Dumazet767e97e2010-10-06 17:49:21 -07002946 for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
2947 n != NULL;
2948 n = rcu_dereference_bh(n->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 cb(n, cookie);
2950 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002951 read_unlock(&tbl->lock);
2952 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953}
2954EXPORT_SYMBOL(neigh_for_each);
2955
2956/* The tbl->lock must be held as a writer and BH disabled. */
2957void __neigh_for_each_release(struct neigh_table *tbl,
2958 int (*cb)(struct neighbour *))
2959{
2960 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002961 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002963 nht = rcu_dereference_protected(tbl->nht,
2964 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -07002965 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002966 struct neighbour *n;
2967 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002969 np = &nht->hash_buckets[chain];
Eric Dumazet767e97e2010-10-06 17:49:21 -07002970 while ((n = rcu_dereference_protected(*np,
2971 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 int release;
2973
2974 write_lock(&n->lock);
2975 release = cb(n);
2976 if (release) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002977 rcu_assign_pointer(*np,
2978 rcu_dereference_protected(n->next,
2979 lockdep_is_held(&tbl->lock)));
David Ahern58956312018-12-07 12:24:57 -08002980 neigh_mark_dead(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 } else
2982 np = &n->next;
2983 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -07002984 if (release)
2985 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 }
2987 }
2988}
2989EXPORT_SYMBOL(__neigh_for_each_release);
2990
Eric W. Biedermanb79bda32015-03-07 16:25:56 -06002991int neigh_xmit(int index, struct net_device *dev,
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06002992 const void *addr, struct sk_buff *skb)
2993{
Eric W. Biedermanb79bda32015-03-07 16:25:56 -06002994 int err = -EAFNOSUPPORT;
2995 if (likely(index < NEIGH_NR_TABLES)) {
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06002996 struct neigh_table *tbl;
2997 struct neighbour *neigh;
2998
Eric W. Biedermanb79bda32015-03-07 16:25:56 -06002999 tbl = neigh_tables[index];
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003000 if (!tbl)
3001 goto out;
David Barrosob560f032016-06-28 11:16:43 +03003002 rcu_read_lock_bh();
David Ahern4b2a2bf2019-05-01 18:18:42 -07003003 if (index == NEIGH_ARP_TABLE) {
3004 u32 key = *((u32 *)addr);
3005
3006 neigh = __ipv4_neigh_lookup_noref(dev, key);
3007 } else {
3008 neigh = __neigh_lookup_noref(tbl, addr, dev);
3009 }
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003010 if (!neigh)
3011 neigh = __neigh_create(tbl, addr, dev, false);
3012 err = PTR_ERR(neigh);
David Barrosob560f032016-06-28 11:16:43 +03003013 if (IS_ERR(neigh)) {
3014 rcu_read_unlock_bh();
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003015 goto out_kfree_skb;
David Barrosob560f032016-06-28 11:16:43 +03003016 }
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003017 err = neigh->output(neigh, skb);
David Barrosob560f032016-06-28 11:16:43 +03003018 rcu_read_unlock_bh();
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003019 }
Eric W. Biedermanb79bda32015-03-07 16:25:56 -06003020 else if (index == NEIGH_LINK_TABLE) {
3021 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
3022 addr, NULL, skb->len);
3023 if (err < 0)
3024 goto out_kfree_skb;
3025 err = dev_queue_xmit(skb);
3026 }
Eric W. Biederman4fd3d7d2015-03-03 17:11:16 -06003027out:
3028 return err;
3029out_kfree_skb:
3030 kfree_skb(skb);
3031 goto out;
3032}
3033EXPORT_SYMBOL(neigh_xmit);
3034
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035#ifdef CONFIG_PROC_FS
3036
3037static struct neighbour *neigh_get_first(struct seq_file *seq)
3038{
3039 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09003040 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003041 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 struct neighbour *n = NULL;
Colin Ian Kingf530eed2019-07-26 10:46:11 +01003043 int bucket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044
3045 state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
David S. Millercd089332011-07-11 01:28:12 -07003046 for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07003047 n = rcu_dereference_bh(nht->hash_buckets[bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048
3049 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09003050 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08003051 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 if (state->neigh_sub_iter) {
3053 loff_t fakep = 0;
3054 void *v;
3055
3056 v = state->neigh_sub_iter(state, n, &fakep);
3057 if (!v)
3058 goto next;
3059 }
3060 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
3061 break;
3062 if (n->nud_state & ~NUD_NOARP)
3063 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07003064next:
3065 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 }
3067
3068 if (n)
3069 break;
3070 }
3071 state->bucket = bucket;
3072
3073 return n;
3074}
3075
3076static struct neighbour *neigh_get_next(struct seq_file *seq,
3077 struct neighbour *n,
3078 loff_t *pos)
3079{
3080 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09003081 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003082 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083
3084 if (state->neigh_sub_iter) {
3085 void *v = state->neigh_sub_iter(state, n, pos);
3086 if (v)
3087 return n;
3088 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07003089 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090
3091 while (1) {
3092 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09003093 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08003094 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 if (state->neigh_sub_iter) {
3096 void *v = state->neigh_sub_iter(state, n, pos);
3097 if (v)
3098 return n;
3099 goto next;
3100 }
3101 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
3102 break;
3103
3104 if (n->nud_state & ~NUD_NOARP)
3105 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07003106next:
3107 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 }
3109
3110 if (n)
3111 break;
3112
David S. Millercd089332011-07-11 01:28:12 -07003113 if (++state->bucket >= (1 << nht->hash_shift))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 break;
3115
Eric Dumazet767e97e2010-10-06 17:49:21 -07003116 n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 }
3118
3119 if (n && pos)
3120 --(*pos);
3121 return n;
3122}
3123
3124static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
3125{
3126 struct neighbour *n = neigh_get_first(seq);
3127
3128 if (n) {
Chris Larson745e2032008-08-03 01:10:55 -07003129 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 while (*pos) {
3131 n = neigh_get_next(seq, n, pos);
3132 if (!n)
3133 break;
3134 }
3135 }
3136 return *pos ? NULL : n;
3137}
3138
3139static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
3140{
3141 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09003142 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 struct neigh_table *tbl = state->tbl;
3144 struct pneigh_entry *pn = NULL;
Yang Li48de7c02021-05-08 18:03:05 +08003145 int bucket;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146
3147 state->flags |= NEIGH_SEQ_IS_PNEIGH;
3148 for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
3149 pn = tbl->phash_buckets[bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09003150 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08003151 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 if (pn)
3153 break;
3154 }
3155 state->bucket = bucket;
3156
3157 return pn;
3158}
3159
3160static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
3161 struct pneigh_entry *pn,
3162 loff_t *pos)
3163{
3164 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09003165 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 struct neigh_table *tbl = state->tbl;
3167
Jorge Boncompte [DTI2]df07a942011-11-25 13:24:49 -05003168 do {
3169 pn = pn->next;
3170 } while (pn && !net_eq(pneigh_net(pn), net));
3171
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 while (!pn) {
3173 if (++state->bucket > PNEIGH_HASHMASK)
3174 break;
3175 pn = tbl->phash_buckets[state->bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09003176 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08003177 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 if (pn)
3179 break;
3180 }
3181
3182 if (pn && pos)
3183 --(*pos);
3184
3185 return pn;
3186}
3187
3188static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
3189{
3190 struct pneigh_entry *pn = pneigh_get_first(seq);
3191
3192 if (pn) {
Chris Larson745e2032008-08-03 01:10:55 -07003193 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 while (*pos) {
3195 pn = pneigh_get_next(seq, pn, pos);
3196 if (!pn)
3197 break;
3198 }
3199 }
3200 return *pos ? NULL : pn;
3201}
3202
3203static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
3204{
3205 struct neigh_seq_state *state = seq->private;
3206 void *rc;
Chris Larson745e2032008-08-03 01:10:55 -07003207 loff_t idxpos = *pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208
Chris Larson745e2032008-08-03 01:10:55 -07003209 rc = neigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
Chris Larson745e2032008-08-03 01:10:55 -07003211 rc = pneigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212
3213 return rc;
3214}
3215
3216void *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 -07003217 __acquires(tbl->lock)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003218 __acquires(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219{
3220 struct neigh_seq_state *state = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221
3222 state->tbl = tbl;
3223 state->bucket = 0;
3224 state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
3225
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003226 rcu_read_lock_bh();
3227 state->nht = rcu_dereference_bh(tbl->nht);
Eric Dumazetf3e92cb2019-06-15 16:28:48 -07003228 read_lock(&tbl->lock);
Eric Dumazet767e97e2010-10-06 17:49:21 -07003229
Chris Larson745e2032008-08-03 01:10:55 -07003230 return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231}
3232EXPORT_SYMBOL(neigh_seq_start);
3233
3234void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
3235{
3236 struct neigh_seq_state *state;
3237 void *rc;
3238
3239 if (v == SEQ_START_TOKEN) {
Chris Larsonbff69732008-08-03 01:02:41 -07003240 rc = neigh_get_first(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 goto out;
3242 }
3243
3244 state = seq->private;
3245 if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
3246 rc = neigh_get_next(seq, v, NULL);
3247 if (rc)
3248 goto out;
3249 if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
3250 rc = pneigh_get_first(seq);
3251 } else {
3252 BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
3253 rc = pneigh_get_next(seq, v, NULL);
3254 }
3255out:
3256 ++(*pos);
3257 return rc;
3258}
3259EXPORT_SYMBOL(neigh_seq_next);
3260
3261void neigh_seq_stop(struct seq_file *seq, void *v)
Eric Dumazetf3e92cb2019-06-15 16:28:48 -07003262 __releases(tbl->lock)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003263 __releases(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264{
Eric Dumazetf3e92cb2019-06-15 16:28:48 -07003265 struct neigh_seq_state *state = seq->private;
3266 struct neigh_table *tbl = state->tbl;
3267
3268 read_unlock(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00003269 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270}
3271EXPORT_SYMBOL(neigh_seq_stop);
3272
3273/* statistics via seq_file */
3274
3275static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
3276{
Christoph Hellwig71a50532018-04-15 10:16:41 +02003277 struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 int cpu;
3279
3280 if (*pos == 0)
3281 return SEQ_START_TOKEN;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09003282
Rusty Russell0f23174a2008-12-29 12:23:42 +00003283 for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 if (!cpu_possible(cpu))
3285 continue;
3286 *pos = cpu+1;
3287 return per_cpu_ptr(tbl->stats, cpu);
3288 }
3289 return NULL;
3290}
3291
3292static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
3293{
Christoph Hellwig71a50532018-04-15 10:16:41 +02003294 struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 int cpu;
3296
Rusty Russell0f23174a2008-12-29 12:23:42 +00003297 for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 if (!cpu_possible(cpu))
3299 continue;
3300 *pos = cpu+1;
3301 return per_cpu_ptr(tbl->stats, cpu);
3302 }
Vasily Averin1e3f9f02020-01-23 10:11:28 +03003303 (*pos)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304 return NULL;
3305}
3306
3307static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
3308{
3309
3310}
3311
3312static int neigh_stat_seq_show(struct seq_file *seq, void *v)
3313{
Christoph Hellwig71a50532018-04-15 10:16:41 +02003314 struct neigh_table *tbl = PDE_DATA(file_inode(seq->file));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 struct neigh_statistics *st = v;
3316
3317 if (v == SEQ_START_TOKEN) {
Rick Jonesfb811392015-08-07 11:10:37 -07003318 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 -07003319 return 0;
3320 }
3321
3322 seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
Rick Jonesfb811392015-08-07 11:10:37 -07003323 "%08lx %08lx %08lx %08lx %08lx %08lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 atomic_read(&tbl->entries),
3325
3326 st->allocs,
3327 st->destroys,
3328 st->hash_grows,
3329
3330 st->lookups,
3331 st->hits,
3332
3333 st->res_failed,
3334
3335 st->rcv_probes_mcast,
3336 st->rcv_probes_ucast,
3337
3338 st->periodic_gc_runs,
Neil Horman9a6d2762008-07-16 20:50:49 -07003339 st->forced_gc_runs,
Rick Jonesfb811392015-08-07 11:10:37 -07003340 st->unres_discards,
3341 st->table_fulls
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 );
3343
3344 return 0;
3345}
3346
Stephen Hemmingerf6908082007-03-12 14:34:29 -07003347static const struct seq_operations neigh_stat_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 .start = neigh_stat_seq_start,
3349 .next = neigh_stat_seq_next,
3350 .stop = neigh_stat_seq_stop,
3351 .show = neigh_stat_seq_show,
3352};
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353#endif /* CONFIG_PROC_FS */
3354
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07003355static void __neigh_notify(struct neighbour *n, int type, int flags,
3356 u32 pid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09003358 struct net *net = dev_net(n->dev);
Thomas Graf8b8aec52006-08-07 17:56:37 -07003359 struct sk_buff *skb;
Thomas Grafb8673312006-08-15 00:33:14 -07003360 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361
Thomas Graf339bf982006-11-10 14:10:15 -08003362 skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
Thomas Graf8b8aec52006-08-07 17:56:37 -07003363 if (skb == NULL)
Thomas Grafb8673312006-08-15 00:33:14 -07003364 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07003366 err = neigh_fill_info(skb, n, pid, 0, type, flags);
Patrick McHardy26932562007-01-31 23:16:40 -08003367 if (err < 0) {
3368 /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
3369 WARN_ON(err == -EMSGSIZE);
3370 kfree_skb(skb);
3371 goto errout;
3372 }
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08003373 rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
3374 return;
Thomas Grafb8673312006-08-15 00:33:14 -07003375errout:
3376 if (err < 0)
Eric W. Biederman426b5302008-01-24 00:13:18 -08003377 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
Thomas Grafb8673312006-08-15 00:33:14 -07003378}
3379
3380void neigh_app_ns(struct neighbour *n)
3381{
Roopa Prabhu7b8f7a42017-03-19 22:01:28 -07003382 __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003384EXPORT_SYMBOL(neigh_app_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385
3386#ifdef CONFIG_SYSCTL
Cong Wangb93196d2012-12-06 10:04:04 +08003387static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388
Joe Perchesfe2c6332013-06-11 23:04:25 -07003389static int proc_unres_qlen(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003390 void *buffer, size_t *lenp, loff_t *ppos)
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003391{
3392 int size, ret;
Joe Perchesfe2c6332013-06-11 23:04:25 -07003393 struct ctl_table tmp = *ctl;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003394
Matteo Croceeec48442019-07-18 15:58:50 -07003395 tmp.extra1 = SYSCTL_ZERO;
Shan Weice46cc62012-12-04 18:49:15 +00003396 tmp.extra2 = &unres_qlen_max;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003397 tmp.data = &size;
Shan Weice46cc62012-12-04 18:49:15 +00003398
3399 size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
3400 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
3401
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003402 if (write && !ret)
3403 *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
3404 return ret;
3405}
3406
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003407static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
3408 int family)
3409{
Jiri Pirkobba24892013-12-07 19:26:57 +01003410 switch (family) {
3411 case AF_INET:
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003412 return __in_dev_arp_parms_get_rcu(dev);
Jiri Pirkobba24892013-12-07 19:26:57 +01003413 case AF_INET6:
3414 return __in6_dev_nd_parms_get_rcu(dev);
3415 }
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003416 return NULL;
3417}
3418
3419static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
3420 int index)
3421{
3422 struct net_device *dev;
3423 int family = neigh_parms_family(p);
3424
3425 rcu_read_lock();
3426 for_each_netdev_rcu(net, dev) {
3427 struct neigh_parms *dst_p =
3428 neigh_get_dev_parms_rcu(dev, family);
3429
3430 if (dst_p && !test_bit(index, dst_p->data_state))
3431 dst_p->data[index] = p->data[index];
3432 }
3433 rcu_read_unlock();
3434}
3435
3436static void neigh_proc_update(struct ctl_table *ctl, int write)
3437{
3438 struct net_device *dev = ctl->extra1;
3439 struct neigh_parms *p = ctl->extra2;
Jiri Pirko77d47af2013-12-10 23:55:07 +01003440 struct net *net = neigh_parms_net(p);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003441 int index = (int *) ctl->data - p->data;
3442
3443 if (!write)
3444 return;
3445
3446 set_bit(index, p->data_state);
Marcus Huewe7627ae62017-02-15 01:00:36 +01003447 if (index == NEIGH_VAR_DELAY_PROBE_TIME)
3448 call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003449 if (!dev) /* NULL dev means this is default value */
3450 neigh_copy_dflt_parms(net, p, index);
3451}
3452
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003453static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003454 void *buffer, size_t *lenp,
3455 loff_t *ppos)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003456{
3457 struct ctl_table tmp = *ctl;
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003458 int ret;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003459
Matteo Croceeec48442019-07-18 15:58:50 -07003460 tmp.extra1 = SYSCTL_ZERO;
3461 tmp.extra2 = SYSCTL_INT_MAX;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003462
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003463 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
3464 neigh_proc_update(ctl, write);
3465 return ret;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003466}
3467
Christoph Hellwig32927392020-04-24 08:43:38 +02003468int neigh_proc_dointvec(struct ctl_table *ctl, int write, void *buffer,
3469 size_t *lenp, loff_t *ppos)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003470{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003471 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
3472
3473 neigh_proc_update(ctl, write);
3474 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003475}
3476EXPORT_SYMBOL(neigh_proc_dointvec);
3477
Christoph Hellwig32927392020-04-24 08:43:38 +02003478int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, void *buffer,
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003479 size_t *lenp, loff_t *ppos)
3480{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003481 int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
3482
3483 neigh_proc_update(ctl, write);
3484 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003485}
3486EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
3487
3488static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003489 void *buffer, size_t *lenp,
3490 loff_t *ppos)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003491{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003492 int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
3493
3494 neigh_proc_update(ctl, write);
3495 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003496}
3497
3498int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003499 void *buffer, size_t *lenp, loff_t *ppos)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003500{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003501 int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
3502
3503 neigh_proc_update(ctl, write);
3504 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003505}
3506EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
3507
3508static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003509 void *buffer, size_t *lenp,
3510 loff_t *ppos)
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003511{
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003512 int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
3513
3514 neigh_proc_update(ctl, write);
3515 return ret;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003516}
3517
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01003518static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
Christoph Hellwig32927392020-04-24 08:43:38 +02003519 void *buffer, size_t *lenp,
3520 loff_t *ppos)
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01003521{
3522 struct neigh_parms *p = ctl->extra2;
3523 int ret;
3524
3525 if (strcmp(ctl->procname, "base_reachable_time") == 0)
3526 ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
3527 else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0)
3528 ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
3529 else
3530 ret = -1;
3531
3532 if (write && ret == 0) {
3533 /* update reachable_time as well, otherwise, the change will
3534 * only be effective after the next time neigh_periodic_work
3535 * decides to recompute it
3536 */
3537 p->reachable_time =
3538 neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
3539 }
3540 return ret;
3541}
3542
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003543#define NEIGH_PARMS_DATA_OFFSET(index) \
3544 (&((struct neigh_parms *) 0)->data[index])
3545
3546#define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
3547 [NEIGH_VAR_ ## attr] = { \
3548 .procname = name, \
3549 .data = NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
3550 .maxlen = sizeof(int), \
3551 .mode = mval, \
3552 .proc_handler = proc, \
3553 }
3554
3555#define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
3556 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
3557
3558#define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003559 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003560
3561#define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003562 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003563
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003564#define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003565 NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003566
3567#define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003568 NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen)
Eric W. Biederman54716e32010-02-14 03:27:03 +00003569
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570static struct neigh_sysctl_table {
3571 struct ctl_table_header *sysctl_header;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003572 struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
Brian Haleyab32ea52006-09-22 14:15:41 -07003573} neigh_sysctl_template __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 .neigh_vars = {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003575 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
3576 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
3577 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
YOSHIFUJI Hideaki/吉藤英明8da86462015-03-19 22:41:46 +09003578 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_REPROBES, "mcast_resolicit"),
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003579 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
3580 NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
3581 NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
3582 NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
3583 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
3584 NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
3585 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
3586 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
3587 NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
3588 NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
3589 NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
3590 NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003591 [NEIGH_VAR_GC_INTERVAL] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 .procname = "gc_interval",
3593 .maxlen = sizeof(int),
3594 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08003595 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003597 [NEIGH_VAR_GC_THRESH1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 .procname = "gc_thresh1",
3599 .maxlen = sizeof(int),
3600 .mode = 0644,
Matteo Croceeec48442019-07-18 15:58:50 -07003601 .extra1 = SYSCTL_ZERO,
3602 .extra2 = SYSCTL_INT_MAX,
Francesco Fusco555445c2013-07-24 10:39:06 +02003603 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003605 [NEIGH_VAR_GC_THRESH2] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 .procname = "gc_thresh2",
3607 .maxlen = sizeof(int),
3608 .mode = 0644,
Matteo Croceeec48442019-07-18 15:58:50 -07003609 .extra1 = SYSCTL_ZERO,
3610 .extra2 = SYSCTL_INT_MAX,
Francesco Fusco555445c2013-07-24 10:39:06 +02003611 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003613 [NEIGH_VAR_GC_THRESH3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 .procname = "gc_thresh3",
3615 .maxlen = sizeof(int),
3616 .mode = 0644,
Matteo Croceeec48442019-07-18 15:58:50 -07003617 .extra1 = SYSCTL_ZERO,
3618 .extra2 = SYSCTL_INT_MAX,
Francesco Fusco555445c2013-07-24 10:39:06 +02003619 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11003621 {},
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 },
3623};
3624
3625int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
Jiri Pirko73af6142013-12-07 19:26:55 +01003626 proc_handler *handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627{
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003628 int i;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003629 struct neigh_sysctl_table *t;
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003630 const char *dev_name_source;
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003631 char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
Jiri Pirko73af6142013-12-07 19:26:55 +01003632 char *p_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003634 t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 if (!t)
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003636 goto err;
3637
Jiri Pirkob194c1f2014-02-21 14:52:57 +01003638 for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
Jiri Pirko1f9248e2013-12-07 19:26:53 +01003639 t->neigh_vars[i].data += (long) p;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003640 t->neigh_vars[i].extra1 = dev;
Jiri Pirko1d4c8c22013-12-07 19:26:56 +01003641 t->neigh_vars[i].extra2 = p;
Jiri Pirkocb5b09c2013-12-07 19:26:54 +01003642 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643
3644 if (dev) {
3645 dev_name_source = dev->name;
Eric W. Biedermand12af672007-10-18 03:05:25 -07003646 /* Terminate the table early */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003647 memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
3648 sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 } else {
Mathias Krause9ecf07a2014-07-12 22:36:44 +02003650 struct neigh_table *tbl = p->tbl;
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003651 dev_name_source = "default";
Mathias Krause9ecf07a2014-07-12 22:36:44 +02003652 t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval;
3653 t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1;
3654 t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2;
3655 t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 }
3657
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08003658 if (handler) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 /* RetransTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003660 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 /* ReachableTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003662 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 /* RetransTime (in milliseconds)*/
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003664 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 /* ReachableTime (in milliseconds) */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00003666 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
Jean-Francois Remy4bf69802015-01-14 04:22:39 +01003667 } else {
3668 /* Those handlers will update p->reachable_time after
3669 * base_reachable_time(_ms) is set to ensure the new timer starts being
3670 * applied after the next neighbour update instead of waiting for
3671 * neigh_periodic_work to update its value (can be multiple minutes)
3672 * So any handler that replaces them should do this as well
3673 */
3674 /* ReachableTime */
3675 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler =
3676 neigh_proc_base_reachable_time;
3677 /* ReachableTime (in milliseconds) */
3678 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler =
3679 neigh_proc_base_reachable_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 }
3681
Eric W. Biederman464dc802012-11-16 03:02:59 +00003682 /* Don't export sysctls to unprivileged users */
3683 if (neigh_parms_net(p)->user_ns != &init_user_ns)
3684 t->neigh_vars[0].procname = NULL;
3685
Jiri Pirko73af6142013-12-07 19:26:55 +01003686 switch (neigh_parms_family(p)) {
3687 case AF_INET:
3688 p_name = "ipv4";
3689 break;
3690 case AF_INET6:
3691 p_name = "ipv6";
3692 break;
3693 default:
3694 BUG();
3695 }
3696
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003697 snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
3698 p_name, dev_name_source);
Denis V. Lunev4ab438f2008-02-28 20:48:01 -08003699 t->sysctl_header =
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003700 register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003701 if (!t->sysctl_header)
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003702 goto free;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003703
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 p->sysctl_table = t;
3705 return 0;
3706
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003707free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 kfree(t);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003709err:
3710 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003712EXPORT_SYMBOL(neigh_sysctl_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713
3714void neigh_sysctl_unregister(struct neigh_parms *p)
3715{
3716 if (p->sysctl_table) {
3717 struct neigh_sysctl_table *t = p->sysctl_table;
3718 p->sysctl_table = NULL;
Eric W. Biederman5dd3df12012-04-19 13:24:33 +00003719 unregister_net_sysctl_table(t->sysctl_header);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 kfree(t);
3721 }
3722}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003723EXPORT_SYMBOL(neigh_sysctl_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724
3725#endif /* CONFIG_SYSCTL */
3726
Thomas Grafc8822a42007-03-22 11:50:06 -07003727static int __init neigh_init(void)
3728{
Florian Westphalb97bac62017-08-09 20:41:48 +02003729 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
3730 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
Roopa Prabhu82cbb5c2018-12-19 12:51:38 -08003731 rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0);
Thomas Grafc8822a42007-03-22 11:50:06 -07003732
Greg Rosec7ac8672011-06-10 01:27:09 +00003733 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
Florian Westphalb97bac62017-08-09 20:41:48 +02003734 0);
3735 rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, 0);
Thomas Grafc8822a42007-03-22 11:50:06 -07003736
3737 return 0;
3738}
3739
3740subsys_initcall(neigh_init);