blob: 3863b8f639c50827dfdf4a0c6c26bd6284f39f58 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Generic address resolution entity
3 *
4 * Authors:
5 * Pedro Roque <roque@di.fc.ul.pt>
6 * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 *
13 * Fixes:
14 * Vitaly E. Lavrov releasing NULL neighbor in neigh_add.
15 * Harald Welte Add neighbour cache statistics like rtstat
16 */
17
Joe Perchese005d192012-05-16 19:58:40 +000018#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090020#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/types.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/socket.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/netdevice.h>
26#include <linux/proc_fs.h>
27#ifdef CONFIG_SYSCTL
28#include <linux/sysctl.h>
29#endif
30#include <linux/times.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020031#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <net/neighbour.h>
33#include <net/dst.h>
34#include <net/sock.h>
Tom Tucker8d717402006-07-30 20:43:36 -070035#include <net/netevent.h>
Thomas Grafa14a49d2006-08-07 17:53:08 -070036#include <net/netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/rtnetlink.h>
38#include <linux/random.h>
Paulo Marques543537b2005-06-23 00:09:02 -070039#include <linux/string.h>
vignesh babuc3609d52007-08-24 22:27:55 -070040#include <linux/log2.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#define NEIGH_DEBUG 1
43
44#define NEIGH_PRINTK(x...) printk(x)
45#define NEIGH_NOPRINTK(x...) do { ; } while(0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#define NEIGH_PRINTK1 NEIGH_NOPRINTK
47#define NEIGH_PRINTK2 NEIGH_NOPRINTK
48
49#if NEIGH_DEBUG >= 1
50#undef NEIGH_PRINTK1
51#define NEIGH_PRINTK1 NEIGH_PRINTK
52#endif
53#if NEIGH_DEBUG >= 2
54#undef NEIGH_PRINTK2
55#define NEIGH_PRINTK2 NEIGH_PRINTK
56#endif
57
58#define PNEIGH_HASHMASK 0xF
59
60static void neigh_timer_handler(unsigned long arg);
Thomas Grafd961db32007-08-08 23:12:56 -070061static void __neigh_notify(struct neighbour *n, int type, int flags);
62static void neigh_update_notify(struct neighbour *neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65static struct neigh_table *neigh_tables;
Amos Waterland45fc3b12005-09-24 16:53:16 -070066#ifdef CONFIG_PROC_FS
Arjan van de Ven9a321442007-02-12 00:55:35 -080067static const struct file_operations neigh_stat_seq_fops;
Amos Waterland45fc3b12005-09-24 16:53:16 -070068#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70/*
71 Neighbour hash table buckets are protected with rwlock tbl->lock.
72
73 - All the scans/updates to hash buckets MUST be made under this lock.
74 - NOTHING clever should be made under this lock: no callbacks
75 to protocol backends, no attempts to send something to network.
76 It will result in deadlocks, if backend/driver wants to use neighbour
77 cache.
78 - If the entry requires some non-trivial actions, increase
79 its reference count and release table lock.
80
81 Neighbour entries are protected:
82 - with reference count.
83 - with rwlock neigh->lock
84
85 Reference count prevents destruction.
86
87 neigh->lock mainly serializes ll address data and its validity state.
88 However, the same lock is used to protect another entry fields:
89 - timer
90 - resolution queue
91
92 Again, nothing clever shall be made under neigh->lock,
93 the most complicated procedure, which we allow is dev->hard_header.
94 It is supposed, that dev->hard_header is simplistic and does
95 not make callbacks to neighbour tables.
96
97 The last lock is neigh_tbl_lock. It is pure SMP lock, protecting
98 list of neighbour tables. This list is used only in process context,
99 */
100
101static DEFINE_RWLOCK(neigh_tbl_lock);
102
David S. Miller8f40b162011-07-17 13:34:11 -0700103static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104{
105 kfree_skb(skb);
106 return -ENETDOWN;
107}
108
Thomas Graf4f494552007-08-08 23:12:36 -0700109static void neigh_cleanup_and_release(struct neighbour *neigh)
110{
111 if (neigh->parms->neigh_cleanup)
112 neigh->parms->neigh_cleanup(neigh);
113
Thomas Grafd961db32007-08-08 23:12:56 -0700114 __neigh_notify(neigh, RTM_DELNEIGH, 0);
Thomas Graf4f494552007-08-08 23:12:36 -0700115 neigh_release(neigh);
116}
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118/*
119 * It is random distribution in the interval (1/2)*base...(3/2)*base.
120 * It corresponds to default IPv6 settings and is not overridable,
121 * because it is really reasonable choice.
122 */
123
124unsigned long neigh_rand_reach_time(unsigned long base)
125{
Eric Dumazeta02cec22010-09-22 20:43:57 +0000126 return base ? (net_random() % base) + (base >> 1) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900128EXPORT_SYMBOL(neigh_rand_reach_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130
131static int neigh_forced_gc(struct neigh_table *tbl)
132{
133 int shrunk = 0;
134 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000135 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137 NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
138
139 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000140 nht = rcu_dereference_protected(tbl->nht,
141 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700142 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700143 struct neighbour *n;
144 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000146 np = &nht->hash_buckets[i];
Eric Dumazet767e97e2010-10-06 17:49:21 -0700147 while ((n = rcu_dereference_protected(*np,
148 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 /* Neighbour record may be discarded if:
150 * - nobody refers to it.
151 * - it is not permanent
152 */
153 write_lock(&n->lock);
154 if (atomic_read(&n->refcnt) == 1 &&
155 !(n->nud_state & NUD_PERMANENT)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700156 rcu_assign_pointer(*np,
157 rcu_dereference_protected(n->next,
158 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 n->dead = 1;
160 shrunk = 1;
161 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700162 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 continue;
164 }
165 write_unlock(&n->lock);
166 np = &n->next;
167 }
168 }
169
170 tbl->last_flush = jiffies;
171
172 write_unlock_bh(&tbl->lock);
173
174 return shrunk;
175}
176
Pavel Emelyanova43d8992007-12-20 15:49:05 -0800177static void neigh_add_timer(struct neighbour *n, unsigned long when)
178{
179 neigh_hold(n);
180 if (unlikely(mod_timer(&n->timer, when))) {
181 printk("NEIGH: BUG, double timer add, state is %x\n",
182 n->nud_state);
183 dump_stack();
184 }
185}
186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187static int neigh_del_timer(struct neighbour *n)
188{
189 if ((n->nud_state & NUD_IN_TIMER) &&
190 del_timer(&n->timer)) {
191 neigh_release(n);
192 return 1;
193 }
194 return 0;
195}
196
197static void pneigh_queue_purge(struct sk_buff_head *list)
198{
199 struct sk_buff *skb;
200
201 while ((skb = skb_dequeue(list)) != NULL) {
202 dev_put(skb->dev);
203 kfree_skb(skb);
204 }
205}
206
Herbert Xu49636bb2005-10-23 17:18:00 +1000207static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208{
209 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000210 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000212 nht = rcu_dereference_protected(tbl->nht,
213 lockdep_is_held(&tbl->lock));
214
David S. Millercd089332011-07-11 01:28:12 -0700215 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700216 struct neighbour *n;
217 struct neighbour __rcu **np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Eric Dumazet767e97e2010-10-06 17:49:21 -0700219 while ((n = rcu_dereference_protected(*np,
220 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 if (dev && n->dev != dev) {
222 np = &n->next;
223 continue;
224 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700225 rcu_assign_pointer(*np,
226 rcu_dereference_protected(n->next,
227 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 write_lock(&n->lock);
229 neigh_del_timer(n);
230 n->dead = 1;
231
232 if (atomic_read(&n->refcnt) != 1) {
233 /* The most unpleasant situation.
234 We must destroy neighbour entry,
235 but someone still uses it.
236
237 The destroy will be delayed until
238 the last user releases us, but
239 we must kill timers etc. and move
240 it to safe state.
241 */
242 skb_queue_purge(&n->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000243 n->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 n->output = neigh_blackhole;
245 if (n->nud_state & NUD_VALID)
246 n->nud_state = NUD_NOARP;
247 else
248 n->nud_state = NUD_NONE;
249 NEIGH_PRINTK2("neigh %p is stray.\n", n);
250 }
251 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700252 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 }
254 }
Herbert Xu49636bb2005-10-23 17:18:00 +1000255}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
Herbert Xu49636bb2005-10-23 17:18:00 +1000257void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
258{
259 write_lock_bh(&tbl->lock);
260 neigh_flush_dev(tbl, dev);
261 write_unlock_bh(&tbl->lock);
262}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900263EXPORT_SYMBOL(neigh_changeaddr);
Herbert Xu49636bb2005-10-23 17:18:00 +1000264
265int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
266{
267 write_lock_bh(&tbl->lock);
268 neigh_flush_dev(tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 pneigh_ifdown(tbl, dev);
270 write_unlock_bh(&tbl->lock);
271
272 del_timer_sync(&tbl->proxy_timer);
273 pneigh_queue_purge(&tbl->proxy_queue);
274 return 0;
275}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900276EXPORT_SYMBOL(neigh_ifdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
David Miller596b9b62011-07-25 00:01:25 +0000278static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
280 struct neighbour *n = NULL;
281 unsigned long now = jiffies;
282 int entries;
283
284 entries = atomic_inc_return(&tbl->entries) - 1;
285 if (entries >= tbl->gc_thresh3 ||
286 (entries >= tbl->gc_thresh2 &&
287 time_after(now, tbl->last_flush + 5 * HZ))) {
288 if (!neigh_forced_gc(tbl) &&
289 entries >= tbl->gc_thresh3)
290 goto out_entries;
291 }
292
YOSHIFUJI Hideaki / 吉藤英明08433ef2013-01-24 00:44:23 +0000293 n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 if (!n)
295 goto out_entries;
296
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 skb_queue_head_init(&n->arp_queue);
298 rwlock_init(&n->lock);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +0000299 seqlock_init(&n->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 n->updated = n->used = now;
301 n->nud_state = NUD_NONE;
302 n->output = neigh_blackhole;
David S. Millerf6b72b62011-07-14 07:53:20 -0700303 seqlock_init(&n->hh.hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 n->parms = neigh_parms_clone(&tbl->parms);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800305 setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
307 NEIGH_CACHE_STAT_INC(tbl, allocs);
308 n->tbl = tbl;
309 atomic_set(&n->refcnt, 1);
310 n->dead = 1;
311out:
312 return n;
313
314out_entries:
315 atomic_dec(&tbl->entries);
316 goto out;
317}
318
David S. Miller2c2aba62011-12-28 15:06:58 -0500319static void neigh_get_hash_rnd(u32 *x)
320{
321 get_random_bytes(x, sizeof(*x));
322 *x |= 1;
323}
324
David S. Millercd089332011-07-11 01:28:12 -0700325static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
David S. Millercd089332011-07-11 01:28:12 -0700327 size_t size = (1 << shift) * sizeof(struct neighbour *);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000328 struct neigh_hash_table *ret;
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000329 struct neighbour __rcu **buckets;
David S. Miller2c2aba62011-12-28 15:06:58 -0500330 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000332 ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
333 if (!ret)
334 return NULL;
335 if (size <= PAGE_SIZE)
336 buckets = kzalloc(size, GFP_ATOMIC);
337 else
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000338 buckets = (struct neighbour __rcu **)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000339 __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
340 get_order(size));
341 if (!buckets) {
342 kfree(ret);
343 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 }
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000345 ret->hash_buckets = buckets;
David S. Millercd089332011-07-11 01:28:12 -0700346 ret->hash_shift = shift;
David S. Miller2c2aba62011-12-28 15:06:58 -0500347 for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
348 neigh_get_hash_rnd(&ret->hash_rnd[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 return ret;
350}
351
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000352static void neigh_hash_free_rcu(struct rcu_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000354 struct neigh_hash_table *nht = container_of(head,
355 struct neigh_hash_table,
356 rcu);
David S. Millercd089332011-07-11 01:28:12 -0700357 size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000358 struct neighbour __rcu **buckets = nht->hash_buckets;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
360 if (size <= PAGE_SIZE)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000361 kfree(buckets);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 else
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000363 free_pages((unsigned long)buckets, get_order(size));
364 kfree(nht);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365}
366
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000367static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
David S. Millercd089332011-07-11 01:28:12 -0700368 unsigned long new_shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000370 unsigned int i, hash;
371 struct neigh_hash_table *new_nht, *old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
373 NEIGH_CACHE_STAT_INC(tbl, hash_grows);
374
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000375 old_nht = rcu_dereference_protected(tbl->nht,
376 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700377 new_nht = neigh_hash_alloc(new_shift);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000378 if (!new_nht)
379 return old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
David S. Millercd089332011-07-11 01:28:12 -0700381 for (i = 0; i < (1 << old_nht->hash_shift); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 struct neighbour *n, *next;
383
Eric Dumazet767e97e2010-10-06 17:49:21 -0700384 for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
385 lockdep_is_held(&tbl->lock));
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000386 n != NULL;
387 n = next) {
388 hash = tbl->hash(n->primary_key, n->dev,
389 new_nht->hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
David S. Millercd089332011-07-11 01:28:12 -0700391 hash >>= (32 - new_nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700392 next = rcu_dereference_protected(n->next,
393 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
Eric Dumazet767e97e2010-10-06 17:49:21 -0700395 rcu_assign_pointer(n->next,
396 rcu_dereference_protected(
397 new_nht->hash_buckets[hash],
398 lockdep_is_held(&tbl->lock)));
399 rcu_assign_pointer(new_nht->hash_buckets[hash], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 }
401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000403 rcu_assign_pointer(tbl->nht, new_nht);
404 call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
405 return new_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406}
407
408struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
409 struct net_device *dev)
410{
411 struct neighbour *n;
412 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800413 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000414 struct neigh_hash_table *nht;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900415
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 NEIGH_CACHE_STAT_INC(tbl, lookups);
417
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000418 rcu_read_lock_bh();
419 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700420 hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700421
422 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
423 n != NULL;
424 n = rcu_dereference_bh(n->next)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700426 if (!atomic_inc_not_zero(&n->refcnt))
427 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 NEIGH_CACHE_STAT_INC(tbl, hits);
429 break;
430 }
431 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700432
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000433 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 return n;
435}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900436EXPORT_SYMBOL(neigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
Eric W. Biederman426b5302008-01-24 00:13:18 -0800438struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
439 const void *pkey)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440{
441 struct neighbour *n;
442 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800443 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000444 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
446 NEIGH_CACHE_STAT_INC(tbl, lookups);
447
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000448 rcu_read_lock_bh();
449 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700450 hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700451
452 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
453 n != NULL;
454 n = rcu_dereference_bh(n->next)) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800455 if (!memcmp(n->primary_key, pkey, key_len) &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900456 net_eq(dev_net(n->dev), net)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700457 if (!atomic_inc_not_zero(&n->refcnt))
458 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 NEIGH_CACHE_STAT_INC(tbl, hits);
460 break;
461 }
462 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700463
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000464 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 return n;
466}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900467EXPORT_SYMBOL(neigh_lookup_nodev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
David S. Millera263b302012-07-02 02:02:15 -0700469struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
470 struct net_device *dev, bool want_ref)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471{
472 u32 hash_val;
473 int key_len = tbl->key_len;
474 int error;
David Miller596b9b62011-07-25 00:01:25 +0000475 struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000476 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477
478 if (!n) {
479 rc = ERR_PTR(-ENOBUFS);
480 goto out;
481 }
482
483 memcpy(n->primary_key, pkey, key_len);
484 n->dev = dev;
485 dev_hold(dev);
486
487 /* Protocol specific setup. */
488 if (tbl->constructor && (error = tbl->constructor(n)) < 0) {
489 rc = ERR_PTR(error);
490 goto out_neigh_release;
491 }
492
David Millerda6a8fa2011-07-25 00:01:38 +0000493 if (dev->netdev_ops->ndo_neigh_construct) {
494 error = dev->netdev_ops->ndo_neigh_construct(n);
495 if (error < 0) {
496 rc = ERR_PTR(error);
497 goto out_neigh_release;
498 }
499 }
500
David S. Miller447f2192011-12-19 15:04:41 -0500501 /* Device specific setup. */
502 if (n->parms->neigh_setup &&
503 (error = n->parms->neigh_setup(n)) < 0) {
504 rc = ERR_PTR(error);
505 goto out_neigh_release;
506 }
507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 n->confirmed = jiffies - (n->parms->base_reachable_time << 1);
509
510 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000511 nht = rcu_dereference_protected(tbl->nht,
512 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
David S. Millercd089332011-07-11 01:28:12 -0700514 if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
515 nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
David S. Millercd089332011-07-11 01:28:12 -0700517 hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
519 if (n->parms->dead) {
520 rc = ERR_PTR(-EINVAL);
521 goto out_tbl_unlock;
522 }
523
Eric Dumazet767e97e2010-10-06 17:49:21 -0700524 for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
525 lockdep_is_held(&tbl->lock));
526 n1 != NULL;
527 n1 = rcu_dereference_protected(n1->next,
528 lockdep_is_held(&tbl->lock))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
David S. Millera263b302012-07-02 02:02:15 -0700530 if (want_ref)
531 neigh_hold(n1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 rc = n1;
533 goto out_tbl_unlock;
534 }
535 }
536
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 n->dead = 0;
David S. Millera263b302012-07-02 02:02:15 -0700538 if (want_ref)
539 neigh_hold(n);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700540 rcu_assign_pointer(n->next,
541 rcu_dereference_protected(nht->hash_buckets[hash_val],
542 lockdep_is_held(&tbl->lock)));
543 rcu_assign_pointer(nht->hash_buckets[hash_val], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 write_unlock_bh(&tbl->lock);
545 NEIGH_PRINTK2("neigh %p is created.\n", n);
546 rc = n;
547out:
548 return rc;
549out_tbl_unlock:
550 write_unlock_bh(&tbl->lock);
551out_neigh_release:
552 neigh_release(n);
553 goto out;
554}
David S. Millera263b302012-07-02 02:02:15 -0700555EXPORT_SYMBOL(__neigh_create);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900557static u32 pneigh_hash(const void *pkey, int key_len)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700558{
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700559 u32 hash_val = *(u32 *)(pkey + key_len - 4);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700560 hash_val ^= (hash_val >> 16);
561 hash_val ^= hash_val >> 8;
562 hash_val ^= hash_val >> 4;
563 hash_val &= PNEIGH_HASHMASK;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900564 return hash_val;
565}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700566
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900567static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
568 struct net *net,
569 const void *pkey,
570 int key_len,
571 struct net_device *dev)
572{
573 while (n) {
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700574 if (!memcmp(n->key, pkey, key_len) &&
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900575 net_eq(pneigh_net(n), net) &&
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700576 (n->dev == dev || !n->dev))
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900577 return n;
578 n = n->next;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700579 }
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900580 return NULL;
581}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700582
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900583struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
584 struct net *net, const void *pkey, struct net_device *dev)
585{
586 int key_len = tbl->key_len;
587 u32 hash_val = pneigh_hash(pkey, key_len);
588
589 return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
590 net, pkey, key_len, dev);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700591}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900592EXPORT_SYMBOL_GPL(__pneigh_lookup);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700593
Eric W. Biederman426b5302008-01-24 00:13:18 -0800594struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
595 struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 struct net_device *dev, int creat)
597{
598 struct pneigh_entry *n;
599 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900600 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
602 read_lock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900603 n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
604 net, pkey, key_len, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 read_unlock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900606
607 if (n || !creat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 goto out;
609
Pavel Emelyanov4ae28942007-10-15 12:54:15 -0700610 ASSERT_RTNL();
611
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
613 if (!n)
614 goto out;
615
Eric Dumazete42ea982008-11-12 00:54:54 -0800616 write_pnet(&n->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 memcpy(n->key, pkey, key_len);
618 n->dev = dev;
619 if (dev)
620 dev_hold(dev);
621
622 if (tbl->pconstructor && tbl->pconstructor(n)) {
623 if (dev)
624 dev_put(dev);
Denis V. Lunevda12f732008-02-20 00:26:16 -0800625 release_net(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 kfree(n);
627 n = NULL;
628 goto out;
629 }
630
631 write_lock_bh(&tbl->lock);
632 n->next = tbl->phash_buckets[hash_val];
633 tbl->phash_buckets[hash_val] = n;
634 write_unlock_bh(&tbl->lock);
635out:
636 return n;
637}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900638EXPORT_SYMBOL(pneigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639
640
Eric W. Biederman426b5302008-01-24 00:13:18 -0800641int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 struct net_device *dev)
643{
644 struct pneigh_entry *n, **np;
645 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900646 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 write_lock_bh(&tbl->lock);
649 for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
650 np = &n->next) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800651 if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900652 net_eq(pneigh_net(n), net)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 *np = n->next;
654 write_unlock_bh(&tbl->lock);
655 if (tbl->pdestructor)
656 tbl->pdestructor(n);
657 if (n->dev)
658 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900659 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 kfree(n);
661 return 0;
662 }
663 }
664 write_unlock_bh(&tbl->lock);
665 return -ENOENT;
666}
667
668static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
669{
670 struct pneigh_entry *n, **np;
671 u32 h;
672
673 for (h = 0; h <= PNEIGH_HASHMASK; h++) {
674 np = &tbl->phash_buckets[h];
675 while ((n = *np) != NULL) {
676 if (!dev || n->dev == dev) {
677 *np = n->next;
678 if (tbl->pdestructor)
679 tbl->pdestructor(n);
680 if (n->dev)
681 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900682 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 kfree(n);
684 continue;
685 }
686 np = &n->next;
687 }
688 }
689 return -ENOENT;
690}
691
Denis V. Lunev06f05112008-01-24 00:30:58 -0800692static void neigh_parms_destroy(struct neigh_parms *parms);
693
694static inline void neigh_parms_put(struct neigh_parms *parms)
695{
696 if (atomic_dec_and_test(&parms->refcnt))
697 neigh_parms_destroy(parms);
698}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
700/*
701 * neighbour must already be out of the table;
702 *
703 */
704void neigh_destroy(struct neighbour *neigh)
705{
David Millerda6a8fa2011-07-25 00:01:38 +0000706 struct net_device *dev = neigh->dev;
707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
709
710 if (!neigh->dead) {
Joe Perchese005d192012-05-16 19:58:40 +0000711 pr_warn("Destroying alive neighbour %p\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 dump_stack();
713 return;
714 }
715
716 if (neigh_del_timer(neigh))
Joe Perchese005d192012-05-16 19:58:40 +0000717 pr_warn("Impossible event\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000720 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
David S. Miller447f2192011-12-19 15:04:41 -0500722 if (dev->netdev_ops->ndo_neigh_destroy)
723 dev->netdev_ops->ndo_neigh_destroy(neigh);
724
David Millerda6a8fa2011-07-25 00:01:38 +0000725 dev_put(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 neigh_parms_put(neigh->parms);
727
728 NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh);
729
730 atomic_dec(&neigh->tbl->entries);
David Miller5b8b0062011-07-25 00:01:22 +0000731 kfree_rcu(neigh, rcu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900733EXPORT_SYMBOL(neigh_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
735/* Neighbour state is suspicious;
736 disable fast path.
737
738 Called with write_locked neigh.
739 */
740static void neigh_suspect(struct neighbour *neigh)
741{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
743
744 neigh->output = neigh->ops->output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745}
746
747/* Neighbour state is OK;
748 enable fast path.
749
750 Called with write_locked neigh.
751 */
752static void neigh_connect(struct neighbour *neigh)
753{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 NEIGH_PRINTK2("neigh %p is connected.\n", neigh);
755
756 neigh->output = neigh->ops->connected_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757}
758
Eric Dumazete4c4e442009-07-30 03:15:07 +0000759static void neigh_periodic_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
Eric Dumazete4c4e442009-07-30 03:15:07 +0000761 struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700762 struct neighbour *n;
763 struct neighbour __rcu **np;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000764 unsigned int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000765 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
767 NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
768
Eric Dumazete4c4e442009-07-30 03:15:07 +0000769 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000770 nht = rcu_dereference_protected(tbl->nht,
771 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
YOSHIFUJI Hideaki / 吉藤英明27246802013-01-22 05:20:05 +0000773 if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
774 goto out;
775
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 /*
777 * periodically recompute ReachableTime from random function
778 */
779
Eric Dumazete4c4e442009-07-30 03:15:07 +0000780 if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 struct neigh_parms *p;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000782 tbl->last_rand = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 for (p = &tbl->parms; p; p = p->next)
784 p->reachable_time =
785 neigh_rand_reach_time(p->base_reachable_time);
786 }
787
David S. Millercd089332011-07-11 01:28:12 -0700788 for (i = 0 ; i < (1 << nht->hash_shift); i++) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000789 np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Eric Dumazet767e97e2010-10-06 17:49:21 -0700791 while ((n = rcu_dereference_protected(*np,
792 lockdep_is_held(&tbl->lock))) != NULL) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000793 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Eric Dumazete4c4e442009-07-30 03:15:07 +0000795 write_lock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
Eric Dumazete4c4e442009-07-30 03:15:07 +0000797 state = n->nud_state;
798 if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
799 write_unlock(&n->lock);
800 goto next_elt;
801 }
802
803 if (time_before(n->used, n->confirmed))
804 n->used = n->confirmed;
805
806 if (atomic_read(&n->refcnt) == 1 &&
807 (state == NUD_FAILED ||
808 time_after(jiffies, n->used + n->parms->gc_staletime))) {
809 *np = n->next;
810 n->dead = 1;
811 write_unlock(&n->lock);
812 neigh_cleanup_and_release(n);
813 continue;
814 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 write_unlock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817next_elt:
Eric Dumazete4c4e442009-07-30 03:15:07 +0000818 np = &n->next;
819 }
820 /*
821 * It's fine to release lock here, even if hash table
822 * grows while we are preempted.
823 */
824 write_unlock_bh(&tbl->lock);
825 cond_resched();
826 write_lock_bh(&tbl->lock);
Michel Machado84338a62012-02-21 16:04:13 -0500827 nht = rcu_dereference_protected(tbl->nht,
828 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 }
YOSHIFUJI Hideaki / 吉藤英明27246802013-01-22 05:20:05 +0000830out:
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900831 /* Cycle through all hash buckets every base_reachable_time/2 ticks.
832 * ARP entry timeouts range from 1/2 base_reachable_time to 3/2
833 * base_reachable_time.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 */
Eric Dumazete4c4e442009-07-30 03:15:07 +0000835 schedule_delayed_work(&tbl->gc_work,
836 tbl->parms.base_reachable_time >> 1);
837 write_unlock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838}
839
840static __inline__ int neigh_max_probes(struct neighbour *n)
841{
842 struct neigh_parms *p = n->parms;
Eric Dumazeta02cec22010-09-22 20:43:57 +0000843 return (n->nud_state & NUD_PROBE) ?
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 p->ucast_probes :
Eric Dumazeta02cec22010-09-22 20:43:57 +0000845 p->ucast_probes + p->app_probes + p->mcast_probes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846}
847
Timo Teras5ef12d92009-06-11 04:16:28 -0700848static void neigh_invalidate(struct neighbour *neigh)
Eric Dumazet0a141502010-03-09 19:40:54 +0000849 __releases(neigh->lock)
850 __acquires(neigh->lock)
Timo Teras5ef12d92009-06-11 04:16:28 -0700851{
852 struct sk_buff *skb;
853
854 NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
855 NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
856 neigh->updated = jiffies;
857
858 /* It is very thin place. report_unreachable is very complicated
859 routine. Particularly, it can hit the same neighbour entry!
860
861 So that, we try to be accurate and avoid dead loop. --ANK
862 */
863 while (neigh->nud_state == NUD_FAILED &&
864 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
865 write_unlock(&neigh->lock);
866 neigh->ops->error_report(neigh, skb);
867 write_lock(&neigh->lock);
868 }
869 skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000870 neigh->arp_queue_len_bytes = 0;
Timo Teras5ef12d92009-06-11 04:16:28 -0700871}
872
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000873static void neigh_probe(struct neighbour *neigh)
874 __releases(neigh->lock)
875{
876 struct sk_buff *skb = skb_peek(&neigh->arp_queue);
877 /* keep skb alive even if arp_queue overflows */
878 if (skb)
879 skb = skb_copy(skb, GFP_ATOMIC);
880 write_unlock(&neigh->lock);
881 neigh->ops->solicit(neigh, skb);
882 atomic_inc(&neigh->probes);
883 kfree_skb(skb);
884}
885
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886/* Called when a timer expires for a neighbour entry. */
887
888static void neigh_timer_handler(unsigned long arg)
889{
890 unsigned long now, next;
891 struct neighbour *neigh = (struct neighbour *)arg;
Eric Dumazet95c96172012-04-15 05:58:06 +0000892 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 int notify = 0;
894
895 write_lock(&neigh->lock);
896
897 state = neigh->nud_state;
898 now = jiffies;
899 next = now + HZ;
900
David S. Miller045f7b32011-11-01 17:45:55 -0400901 if (!(state & NUD_IN_TIMER))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903
904 if (state & NUD_REACHABLE) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900905 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 neigh->confirmed + neigh->parms->reachable_time)) {
907 NEIGH_PRINTK2("neigh %p is still alive.\n", neigh);
908 next = neigh->confirmed + neigh->parms->reachable_time;
909 } else if (time_before_eq(now,
910 neigh->used + neigh->parms->delay_probe_time)) {
911 NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
912 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800913 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 neigh_suspect(neigh);
915 next = now + neigh->parms->delay_probe_time;
916 } else {
917 NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
918 neigh->nud_state = NUD_STALE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800919 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 neigh_suspect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700921 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 }
923 } else if (state & NUD_DELAY) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900924 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 neigh->confirmed + neigh->parms->delay_probe_time)) {
926 NEIGH_PRINTK2("neigh %p is now reachable.\n", neigh);
927 neigh->nud_state = NUD_REACHABLE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800928 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 neigh_connect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700930 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 next = neigh->confirmed + neigh->parms->reachable_time;
932 } else {
933 NEIGH_PRINTK2("neigh %p is probed.\n", neigh);
934 neigh->nud_state = NUD_PROBE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800935 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 atomic_set(&neigh->probes, 0);
937 next = now + neigh->parms->retrans_time;
938 }
939 } else {
940 /* NUD_PROBE|NUD_INCOMPLETE */
941 next = now + neigh->parms->retrans_time;
942 }
943
944 if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
945 atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 neigh->nud_state = NUD_FAILED;
947 notify = 1;
Timo Teras5ef12d92009-06-11 04:16:28 -0700948 neigh_invalidate(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 }
950
951 if (neigh->nud_state & NUD_IN_TIMER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 if (time_before(next, jiffies + HZ/2))
953 next = jiffies + HZ/2;
Herbert Xu6fb99742005-10-23 16:37:48 +1000954 if (!mod_timer(&neigh->timer, next))
955 neigh_hold(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 }
957 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000958 neigh_probe(neigh);
David S. Miller9ff56602008-02-17 18:39:54 -0800959 } else {
David S. Miller69cc64d2008-02-11 21:45:44 -0800960out:
David S. Miller9ff56602008-02-17 18:39:54 -0800961 write_unlock(&neigh->lock);
962 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Thomas Grafd961db32007-08-08 23:12:56 -0700964 if (notify)
965 neigh_update_notify(neigh);
966
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 neigh_release(neigh);
968}
969
970int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
971{
972 int rc;
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000973 bool immediate_probe = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
975 write_lock_bh(&neigh->lock);
976
977 rc = 0;
978 if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
979 goto out_unlock_bh;
980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
982 if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000983 unsigned long next, now = jiffies;
984
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 atomic_set(&neigh->probes, neigh->parms->ucast_probes);
986 neigh->nud_state = NUD_INCOMPLETE;
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000987 neigh->updated = now;
988 next = now + max(neigh->parms->retrans_time, HZ/2);
989 neigh_add_timer(neigh, next);
990 immediate_probe = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 } else {
992 neigh->nud_state = NUD_FAILED;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800993 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 write_unlock_bh(&neigh->lock);
995
Wei Yongjunf3fbbe02009-02-25 00:37:32 +0000996 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 return 1;
998 }
999 } else if (neigh->nud_state & NUD_STALE) {
1000 NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -08001002 neigh->updated = jiffies;
David S. Miller667347f2005-09-27 12:07:44 -07001003 neigh_add_timer(neigh,
1004 jiffies + neigh->parms->delay_probe_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 }
1006
1007 if (neigh->nud_state == NUD_INCOMPLETE) {
1008 if (skb) {
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001009 while (neigh->arp_queue_len_bytes + skb->truesize >
1010 neigh->parms->queue_len_bytes) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 struct sk_buff *buff;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001012
David S. Millerf72051b2008-09-23 01:11:18 -07001013 buff = __skb_dequeue(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001014 if (!buff)
1015 break;
1016 neigh->arp_queue_len_bytes -= buff->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 kfree_skb(buff);
Neil Horman9a6d2762008-07-16 20:50:49 -07001018 NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 }
Eric Dumazeta4731132010-05-27 16:09:39 -07001020 skb_dst_force(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 __skb_queue_tail(&neigh->arp_queue, skb);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001022 neigh->arp_queue_len_bytes += skb->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 }
1024 rc = 1;
1025 }
1026out_unlock_bh:
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001027 if (immediate_probe)
1028 neigh_probe(neigh);
1029 else
1030 write_unlock(&neigh->lock);
1031 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 return rc;
1033}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001034EXPORT_SYMBOL(__neigh_event_send);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
David S. Millerf6b72b62011-07-14 07:53:20 -07001036static void neigh_update_hhs(struct neighbour *neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037{
1038 struct hh_cache *hh;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001039 void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
Doug Kehn91a72a72010-07-14 18:02:16 -07001040 = NULL;
1041
1042 if (neigh->dev->header_ops)
1043 update = neigh->dev->header_ops->cache_update;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
1045 if (update) {
David S. Millerf6b72b62011-07-14 07:53:20 -07001046 hh = &neigh->hh;
1047 if (hh->hh_len) {
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001048 write_seqlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 update(hh, neigh->dev, neigh->ha);
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001050 write_sequnlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 }
1052 }
1053}
1054
1055
1056
1057/* Generic update routine.
1058 -- lladdr is new lladdr or NULL, if it is not supplied.
1059 -- new is new state.
1060 -- flags
1061 NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
1062 if it is different.
1063 NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001064 lladdr instead of overriding it
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 if it is different.
1066 It also allows to retain current state
1067 if lladdr is unchanged.
1068 NEIGH_UPDATE_F_ADMIN means that the change is administrative.
1069
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001070 NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 NTF_ROUTER flag.
1072 NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
1073 a router.
1074
1075 Caller MUST hold reference count on the entry.
1076 */
1077
1078int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
1079 u32 flags)
1080{
1081 u8 old;
1082 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 int notify = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 struct net_device *dev;
1085 int update_isrouter = 0;
1086
1087 write_lock_bh(&neigh->lock);
1088
1089 dev = neigh->dev;
1090 old = neigh->nud_state;
1091 err = -EPERM;
1092
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001093 if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 (old & (NUD_NOARP | NUD_PERMANENT)))
1095 goto out;
1096
1097 if (!(new & NUD_VALID)) {
1098 neigh_del_timer(neigh);
1099 if (old & NUD_CONNECTED)
1100 neigh_suspect(neigh);
1101 neigh->nud_state = new;
1102 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 notify = old & NUD_VALID;
Timo Teras5ef12d92009-06-11 04:16:28 -07001104 if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
1105 (new & NUD_FAILED)) {
1106 neigh_invalidate(neigh);
1107 notify = 1;
1108 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 goto out;
1110 }
1111
1112 /* Compare new lladdr with cached one */
1113 if (!dev->addr_len) {
1114 /* First case: device needs no address. */
1115 lladdr = neigh->ha;
1116 } else if (lladdr) {
1117 /* The second case: if something is already cached
1118 and a new address is proposed:
1119 - compare new & old
1120 - if they are different, check override flag
1121 */
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001122 if ((old & NUD_VALID) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 !memcmp(lladdr, neigh->ha, dev->addr_len))
1124 lladdr = neigh->ha;
1125 } else {
1126 /* No address is supplied; if we know something,
1127 use it, otherwise discard the request.
1128 */
1129 err = -EINVAL;
1130 if (!(old & NUD_VALID))
1131 goto out;
1132 lladdr = neigh->ha;
1133 }
1134
1135 if (new & NUD_CONNECTED)
1136 neigh->confirmed = jiffies;
1137 neigh->updated = jiffies;
1138
1139 /* If entry was valid and address is not changed,
1140 do not change entry state, if new one is STALE.
1141 */
1142 err = 0;
1143 update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
1144 if (old & NUD_VALID) {
1145 if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
1146 update_isrouter = 0;
1147 if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
1148 (old & NUD_CONNECTED)) {
1149 lladdr = neigh->ha;
1150 new = NUD_STALE;
1151 } else
1152 goto out;
1153 } else {
1154 if (lladdr == neigh->ha && new == NUD_STALE &&
1155 ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||
1156 (old & NUD_CONNECTED))
1157 )
1158 new = old;
1159 }
1160 }
1161
1162 if (new != old) {
1163 neigh_del_timer(neigh);
Pavel Emelyanova43d8992007-12-20 15:49:05 -08001164 if (new & NUD_IN_TIMER)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001165 neigh_add_timer(neigh, (jiffies +
1166 ((new & NUD_REACHABLE) ?
David S. Miller667347f2005-09-27 12:07:44 -07001167 neigh->parms->reachable_time :
1168 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 neigh->nud_state = new;
1170 }
1171
1172 if (lladdr != neigh->ha) {
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001173 write_seqlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 memcpy(&neigh->ha, lladdr, dev->addr_len);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001175 write_sequnlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 neigh_update_hhs(neigh);
1177 if (!(new & NUD_CONNECTED))
1178 neigh->confirmed = jiffies -
1179 (neigh->parms->base_reachable_time << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 }
1182 if (new == old)
1183 goto out;
1184 if (new & NUD_CONNECTED)
1185 neigh_connect(neigh);
1186 else
1187 neigh_suspect(neigh);
1188 if (!(old & NUD_VALID)) {
1189 struct sk_buff *skb;
1190
1191 /* Again: avoid dead loop if something went wrong */
1192
1193 while (neigh->nud_state & NUD_VALID &&
1194 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
David S. Miller69cce1d2011-07-17 23:09:49 -07001195 struct dst_entry *dst = skb_dst(skb);
1196 struct neighbour *n2, *n1 = neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 write_unlock_bh(&neigh->lock);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001198
1199 rcu_read_lock();
David S. Miller13a43d92012-07-02 22:15:37 -07001200
1201 /* Why not just use 'neigh' as-is? The problem is that
1202 * things such as shaper, eql, and sch_teql can end up
1203 * using alternative, different, neigh objects to output
1204 * the packet in the output path. So what we need to do
1205 * here is re-lookup the top-level neigh in the path so
1206 * we can reinject the packet there.
1207 */
1208 n2 = NULL;
1209 if (dst) {
1210 n2 = dst_neigh_lookup_skb(dst, skb);
1211 if (n2)
1212 n1 = n2;
1213 }
David S. Miller8f40b162011-07-17 13:34:11 -07001214 n1->output(n1, skb);
David S. Miller13a43d92012-07-02 22:15:37 -07001215 if (n2)
1216 neigh_release(n2);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001217 rcu_read_unlock();
1218
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 write_lock_bh(&neigh->lock);
1220 }
1221 skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001222 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 }
1224out:
1225 if (update_isrouter) {
1226 neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?
1227 (neigh->flags | NTF_ROUTER) :
1228 (neigh->flags & ~NTF_ROUTER);
1229 }
1230 write_unlock_bh(&neigh->lock);
Tom Tucker8d717402006-07-30 20:43:36 -07001231
1232 if (notify)
Thomas Grafd961db32007-08-08 23:12:56 -07001233 neigh_update_notify(neigh);
1234
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 return err;
1236}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001237EXPORT_SYMBOL(neigh_update);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
1239struct neighbour *neigh_event_ns(struct neigh_table *tbl,
1240 u8 *lladdr, void *saddr,
1241 struct net_device *dev)
1242{
1243 struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
1244 lladdr || !dev->addr_len);
1245 if (neigh)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001246 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 NEIGH_UPDATE_F_OVERRIDE);
1248 return neigh;
1249}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001250EXPORT_SYMBOL(neigh_event_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
Eric Dumazet34d101d2010-10-11 09:16:57 -07001252/* called with read_lock_bh(&n->lock); */
David S. Millerf6b72b62011-07-14 07:53:20 -07001253static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 struct net_device *dev = dst->dev;
David S. Millerf6b72b62011-07-14 07:53:20 -07001256 __be16 prot = dst->ops->protocol;
1257 struct hh_cache *hh = &n->hh;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001258
1259 write_lock_bh(&n->lock);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001260
David S. Millerf6b72b62011-07-14 07:53:20 -07001261 /* Only one thread can come in here and initialize the
1262 * hh_cache entry.
1263 */
David S. Millerb23b5452011-07-16 17:45:02 -07001264 if (!hh->hh_len)
1265 dev->header_ops->cache(n, hh, prot);
David S. Millerf6b72b62011-07-14 07:53:20 -07001266
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001267 write_unlock_bh(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268}
1269
1270/* This function can be used in contexts, where only old dev_queue_xmit
Eric Dumazet767e97e2010-10-06 17:49:21 -07001271 * worked, f.e. if you want to override normal output path (eql, shaper),
1272 * but resolution is not made yet.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 */
1274
David S. Miller8f40b162011-07-17 13:34:11 -07001275int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276{
1277 struct net_device *dev = skb->dev;
1278
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001279 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
Stephen Hemminger0c4e8582007-10-09 01:36:32 -07001281 if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
1282 skb->len) < 0 &&
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001283 dev->header_ops->rebuild(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 return 0;
1285
1286 return dev_queue_xmit(skb);
1287}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001288EXPORT_SYMBOL(neigh_compat_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
1290/* Slow and careful. */
1291
David S. Miller8f40b162011-07-17 13:34:11 -07001292int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293{
Eric Dumazetadf30902009-06-02 05:19:30 +00001294 struct dst_entry *dst = skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 int rc = 0;
1296
David S. Miller8f40b162011-07-17 13:34:11 -07001297 if (!dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 goto discard;
1299
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 if (!neigh_event_send(neigh, skb)) {
1301 int err;
1302 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001303 unsigned int seq;
Eric Dumazet34d101d2010-10-11 09:16:57 -07001304
David S. Millerf6b72b62011-07-14 07:53:20 -07001305 if (dev->header_ops->cache && !neigh->hh.hh_len)
1306 neigh_hh_init(neigh, dst);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001307
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001308 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001309 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001310 seq = read_seqbegin(&neigh->ha_lock);
1311 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1312 neigh->ha, NULL, skb->len);
1313 } while (read_seqretry(&neigh->ha_lock, seq));
Eric Dumazet34d101d2010-10-11 09:16:57 -07001314
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001316 rc = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 else
1318 goto out_kfree_skb;
1319 }
1320out:
1321 return rc;
1322discard:
1323 NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
David S. Miller8f40b162011-07-17 13:34:11 -07001324 dst, neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325out_kfree_skb:
1326 rc = -EINVAL;
1327 kfree_skb(skb);
1328 goto out;
1329}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001330EXPORT_SYMBOL(neigh_resolve_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
1332/* As fast as possible without hh cache */
1333
David S. Miller8f40b162011-07-17 13:34:11 -07001334int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001337 unsigned int seq;
David S. Miller8f40b162011-07-17 13:34:11 -07001338 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001340 do {
ramesh.nagappa@gmail.come1f16502012-10-05 19:10:15 +00001341 __skb_pull(skb, skb_network_offset(skb));
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001342 seq = read_seqbegin(&neigh->ha_lock);
1343 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1344 neigh->ha, NULL, skb->len);
1345 } while (read_seqretry(&neigh->ha_lock, seq));
1346
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001348 err = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 else {
1350 err = -EINVAL;
1351 kfree_skb(skb);
1352 }
1353 return err;
1354}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001355EXPORT_SYMBOL(neigh_connected_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
David S. Miller8f40b162011-07-17 13:34:11 -07001357int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
1358{
1359 return dev_queue_xmit(skb);
1360}
1361EXPORT_SYMBOL(neigh_direct_output);
1362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363static void neigh_proxy_process(unsigned long arg)
1364{
1365 struct neigh_table *tbl = (struct neigh_table *)arg;
1366 long sched_next = 0;
1367 unsigned long now = jiffies;
David S. Millerf72051b2008-09-23 01:11:18 -07001368 struct sk_buff *skb, *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369
1370 spin_lock(&tbl->proxy_queue.lock);
1371
David S. Millerf72051b2008-09-23 01:11:18 -07001372 skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1373 long tdif = NEIGH_CB(skb)->sched_next - now;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 if (tdif <= 0) {
David S. Millerf72051b2008-09-23 01:11:18 -07001376 struct net_device *dev = skb->dev;
Eric Dumazet20e60742011-08-22 19:32:42 +00001377
David S. Millerf72051b2008-09-23 01:11:18 -07001378 __skb_unlink(skb, &tbl->proxy_queue);
Eric Dumazet20e60742011-08-22 19:32:42 +00001379 if (tbl->proxy_redo && netif_running(dev)) {
1380 rcu_read_lock();
David S. Millerf72051b2008-09-23 01:11:18 -07001381 tbl->proxy_redo(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001382 rcu_read_unlock();
1383 } else {
David S. Millerf72051b2008-09-23 01:11:18 -07001384 kfree_skb(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386
1387 dev_put(dev);
1388 } else if (!sched_next || tdif < sched_next)
1389 sched_next = tdif;
1390 }
1391 del_timer(&tbl->proxy_timer);
1392 if (sched_next)
1393 mod_timer(&tbl->proxy_timer, jiffies + sched_next);
1394 spin_unlock(&tbl->proxy_queue.lock);
1395}
1396
1397void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
1398 struct sk_buff *skb)
1399{
1400 unsigned long now = jiffies;
1401 unsigned long sched_next = now + (net_random() % p->proxy_delay);
1402
1403 if (tbl->proxy_queue.qlen > p->proxy_qlen) {
1404 kfree_skb(skb);
1405 return;
1406 }
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001407
1408 NEIGH_CB(skb)->sched_next = sched_next;
1409 NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
1411 spin_lock(&tbl->proxy_queue.lock);
1412 if (del_timer(&tbl->proxy_timer)) {
1413 if (time_before(tbl->proxy_timer.expires, sched_next))
1414 sched_next = tbl->proxy_timer.expires;
1415 }
Eric Dumazetadf30902009-06-02 05:19:30 +00001416 skb_dst_drop(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 dev_hold(skb->dev);
1418 __skb_queue_tail(&tbl->proxy_queue, skb);
1419 mod_timer(&tbl->proxy_timer, sched_next);
1420 spin_unlock(&tbl->proxy_queue.lock);
1421}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001422EXPORT_SYMBOL(pneigh_enqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001424static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
Eric W. Biederman426b5302008-01-24 00:13:18 -08001425 struct net *net, int ifindex)
1426{
1427 struct neigh_parms *p;
1428
1429 for (p = &tbl->parms; p; p = p->next) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09001430 if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
Eric W. Biederman426b5302008-01-24 00:13:18 -08001431 (!p->dev && !ifindex))
1432 return p;
1433 }
1434
1435 return NULL;
1436}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437
1438struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1439 struct neigh_table *tbl)
1440{
Eric W. Biederman426b5302008-01-24 00:13:18 -08001441 struct neigh_parms *p, *ref;
Stephen Hemminger00829822008-11-20 20:14:53 -08001442 struct net *net = dev_net(dev);
1443 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001445 ref = lookup_neigh_parms(tbl, net, 0);
Eric W. Biederman426b5302008-01-24 00:13:18 -08001446 if (!ref)
1447 return NULL;
1448
1449 p = kmemdup(ref, sizeof(*p), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 if (p) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 p->tbl = tbl;
1452 atomic_set(&p->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 p->reachable_time =
1454 neigh_rand_reach_time(p->base_reachable_time);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001455
Stephen Hemminger00829822008-11-20 20:14:53 -08001456 if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001457 kfree(p);
1458 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 }
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001460
1461 dev_hold(dev);
1462 p->dev = dev;
Eric Dumazete42ea982008-11-12 00:54:54 -08001463 write_pnet(&p->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 p->sysctl_table = NULL;
1465 write_lock_bh(&tbl->lock);
1466 p->next = tbl->parms.next;
1467 tbl->parms.next = p;
1468 write_unlock_bh(&tbl->lock);
1469 }
1470 return p;
1471}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001472EXPORT_SYMBOL(neigh_parms_alloc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473
1474static void neigh_rcu_free_parms(struct rcu_head *head)
1475{
1476 struct neigh_parms *parms =
1477 container_of(head, struct neigh_parms, rcu_head);
1478
1479 neigh_parms_put(parms);
1480}
1481
1482void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
1483{
1484 struct neigh_parms **p;
1485
1486 if (!parms || parms == &tbl->parms)
1487 return;
1488 write_lock_bh(&tbl->lock);
1489 for (p = &tbl->parms.next; *p; p = &(*p)->next) {
1490 if (*p == parms) {
1491 *p = parms->next;
1492 parms->dead = 1;
1493 write_unlock_bh(&tbl->lock);
David S. Millercecbb632008-01-20 16:39:03 -08001494 if (parms->dev)
1495 dev_put(parms->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
1497 return;
1498 }
1499 }
1500 write_unlock_bh(&tbl->lock);
1501 NEIGH_PRINTK1("neigh_parms_release: not found\n");
1502}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001503EXPORT_SYMBOL(neigh_parms_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504
Denis V. Lunev06f05112008-01-24 00:30:58 -08001505static void neigh_parms_destroy(struct neigh_parms *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506{
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +09001507 release_net(neigh_parms_net(parms));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 kfree(parms);
1509}
1510
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001511static struct lock_class_key neigh_table_proxy_queue_class;
1512
Hiroaki SHIMODAdcd2ba92012-04-13 07:34:44 +00001513static void neigh_table_init_no_netlink(struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514{
1515 unsigned long now = jiffies;
1516 unsigned long phsize;
1517
Eric Dumazete42ea982008-11-12 00:54:54 -08001518 write_pnet(&tbl->parms.net, &init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 atomic_set(&tbl->parms.refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 tbl->parms.reachable_time =
1521 neigh_rand_reach_time(tbl->parms.base_reachable_time);
1522
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 tbl->stats = alloc_percpu(struct neigh_statistics);
1524 if (!tbl->stats)
1525 panic("cannot create neighbour cache statistics");
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001526
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527#ifdef CONFIG_PROC_FS
Alexey Dobriyan9b739ba2008-11-11 16:47:44 -08001528 if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat,
1529 &neigh_stat_seq_fops, tbl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 panic("cannot create neighbour proc dir entry");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531#endif
1532
David S. Millercd089332011-07-11 01:28:12 -07001533 RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
1535 phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
Andrew Morton77d04bd2006-04-07 14:52:59 -07001536 tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001538 if (!tbl->nht || !tbl->phash_buckets)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 panic("cannot allocate neighbour cache hashes");
1540
YOSHIFUJI Hideaki / 吉藤英明08433ef2013-01-24 00:44:23 +00001541 if (!tbl->entry_size)
1542 tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
1543 tbl->key_len, NEIGH_PRIV_ALIGN);
1544 else
1545 WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
1546
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 rwlock_init(&tbl->lock);
Tejun Heo203b42f2012-08-21 13:18:23 -07001548 INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
Eric Dumazete4c4e442009-07-30 03:15:07 +00001549 schedule_delayed_work(&tbl->gc_work, tbl->parms.reachable_time);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001550 setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl);
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001551 skb_queue_head_init_class(&tbl->proxy_queue,
1552 &neigh_table_proxy_queue_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553
1554 tbl->last_flush = now;
1555 tbl->last_rand = now + tbl->parms.reachable_time * 20;
Simon Kelleybd89efc2006-05-12 14:56:08 -07001556}
1557
1558void neigh_table_init(struct neigh_table *tbl)
1559{
1560 struct neigh_table *tmp;
1561
1562 neigh_table_init_no_netlink(tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 write_lock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001564 for (tmp = neigh_tables; tmp; tmp = tmp->next) {
1565 if (tmp->family == tbl->family)
1566 break;
1567 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 tbl->next = neigh_tables;
1569 neigh_tables = tbl;
1570 write_unlock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001571
1572 if (unlikely(tmp)) {
Joe Perchese005d192012-05-16 19:58:40 +00001573 pr_err("Registering multiple tables for family %d\n",
1574 tbl->family);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001575 dump_stack();
1576 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001578EXPORT_SYMBOL(neigh_table_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
1580int neigh_table_clear(struct neigh_table *tbl)
1581{
1582 struct neigh_table **tp;
1583
1584 /* It is not clean... Fix it to unload IPv6 module safely */
Tejun Heoa5c30b32010-10-19 06:04:42 +00001585 cancel_delayed_work_sync(&tbl->gc_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 del_timer_sync(&tbl->proxy_timer);
1587 pneigh_queue_purge(&tbl->proxy_queue);
1588 neigh_ifdown(tbl, NULL);
1589 if (atomic_read(&tbl->entries))
Joe Perchese005d192012-05-16 19:58:40 +00001590 pr_crit("neighbour leakage\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 write_lock(&neigh_tbl_lock);
1592 for (tp = &neigh_tables; *tp; tp = &(*tp)->next) {
1593 if (*tp == tbl) {
1594 *tp = tbl->next;
1595 break;
1596 }
1597 }
1598 write_unlock(&neigh_tbl_lock);
1599
Eric Dumazet6193d2b2011-01-19 22:02:47 +00001600 call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
1601 neigh_hash_free_rcu);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001602 tbl->nht = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603
1604 kfree(tbl->phash_buckets);
1605 tbl->phash_buckets = NULL;
1606
Alexey Dobriyan3f192b52007-11-05 21:28:13 -08001607 remove_proc_entry(tbl->id, init_net.proc_net_stat);
1608
Kirill Korotaev3fcde742006-09-01 01:34:10 -07001609 free_percpu(tbl->stats);
1610 tbl->stats = NULL;
1611
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 return 0;
1613}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001614EXPORT_SYMBOL(neigh_table_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615
Thomas Grafc8822a42007-03-22 11:50:06 -07001616static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001618 struct net *net = sock_net(skb->sk);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001619 struct ndmsg *ndm;
1620 struct nlattr *dst_attr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 struct neigh_table *tbl;
1622 struct net_device *dev = NULL;
Thomas Grafa14a49d2006-08-07 17:53:08 -07001623 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624
Eric Dumazet110b2492010-10-04 04:27:36 +00001625 ASSERT_RTNL();
Thomas Grafa14a49d2006-08-07 17:53:08 -07001626 if (nlmsg_len(nlh) < sizeof(*ndm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 goto out;
1628
Thomas Grafa14a49d2006-08-07 17:53:08 -07001629 dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
1630 if (dst_attr == NULL)
1631 goto out;
1632
1633 ndm = nlmsg_data(nlh);
1634 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001635 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001636 if (dev == NULL) {
1637 err = -ENODEV;
1638 goto out;
1639 }
1640 }
1641
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 read_lock(&neigh_tbl_lock);
1643 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Grafa14a49d2006-08-07 17:53:08 -07001644 struct neighbour *neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
1646 if (tbl->family != ndm->ndm_family)
1647 continue;
1648 read_unlock(&neigh_tbl_lock);
1649
Thomas Grafa14a49d2006-08-07 17:53:08 -07001650 if (nla_len(dst_attr) < tbl->key_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001651 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652
1653 if (ndm->ndm_flags & NTF_PROXY) {
Eric W. Biederman426b5302008-01-24 00:13:18 -08001654 err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
Eric Dumazet110b2492010-10-04 04:27:36 +00001655 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 }
1657
Thomas Grafa14a49d2006-08-07 17:53:08 -07001658 if (dev == NULL)
Eric Dumazet110b2492010-10-04 04:27:36 +00001659 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
Thomas Grafa14a49d2006-08-07 17:53:08 -07001661 neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1662 if (neigh == NULL) {
1663 err = -ENOENT;
Eric Dumazet110b2492010-10-04 04:27:36 +00001664 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 }
Thomas Grafa14a49d2006-08-07 17:53:08 -07001666
1667 err = neigh_update(neigh, NULL, NUD_FAILED,
1668 NEIGH_UPDATE_F_OVERRIDE |
1669 NEIGH_UPDATE_F_ADMIN);
1670 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001671 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 }
1673 read_unlock(&neigh_tbl_lock);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001674 err = -EAFNOSUPPORT;
1675
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676out:
1677 return err;
1678}
1679
Thomas Grafc8822a42007-03-22 11:50:06 -07001680static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001682 struct net *net = sock_net(skb->sk);
Thomas Graf5208deb2006-08-07 17:55:40 -07001683 struct ndmsg *ndm;
1684 struct nlattr *tb[NDA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 struct neigh_table *tbl;
1686 struct net_device *dev = NULL;
Thomas Graf5208deb2006-08-07 17:55:40 -07001687 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688
Eric Dumazet110b2492010-10-04 04:27:36 +00001689 ASSERT_RTNL();
Thomas Graf5208deb2006-08-07 17:55:40 -07001690 err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
1691 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 goto out;
1693
Thomas Graf5208deb2006-08-07 17:55:40 -07001694 err = -EINVAL;
1695 if (tb[NDA_DST] == NULL)
1696 goto out;
1697
1698 ndm = nlmsg_data(nlh);
1699 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001700 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Graf5208deb2006-08-07 17:55:40 -07001701 if (dev == NULL) {
1702 err = -ENODEV;
1703 goto out;
1704 }
1705
1706 if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001707 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001708 }
1709
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 read_lock(&neigh_tbl_lock);
1711 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Graf5208deb2006-08-07 17:55:40 -07001712 int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
1713 struct neighbour *neigh;
1714 void *dst, *lladdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715
1716 if (tbl->family != ndm->ndm_family)
1717 continue;
1718 read_unlock(&neigh_tbl_lock);
1719
Thomas Graf5208deb2006-08-07 17:55:40 -07001720 if (nla_len(tb[NDA_DST]) < tbl->key_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001721 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001722 dst = nla_data(tb[NDA_DST]);
1723 lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724
1725 if (ndm->ndm_flags & NTF_PROXY) {
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001726 struct pneigh_entry *pn;
1727
1728 err = -ENOBUFS;
Eric W. Biederman426b5302008-01-24 00:13:18 -08001729 pn = pneigh_lookup(tbl, net, dst, dev, 1);
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001730 if (pn) {
1731 pn->flags = ndm->ndm_flags;
1732 err = 0;
1733 }
Eric Dumazet110b2492010-10-04 04:27:36 +00001734 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 }
1736
Thomas Graf5208deb2006-08-07 17:55:40 -07001737 if (dev == NULL)
Eric Dumazet110b2492010-10-04 04:27:36 +00001738 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001739
1740 neigh = neigh_lookup(tbl, dst, dev);
1741 if (neigh == NULL) {
1742 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
1743 err = -ENOENT;
Eric Dumazet110b2492010-10-04 04:27:36 +00001744 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001745 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001746
Thomas Graf5208deb2006-08-07 17:55:40 -07001747 neigh = __neigh_lookup_errno(tbl, dst, dev);
1748 if (IS_ERR(neigh)) {
1749 err = PTR_ERR(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001750 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001751 }
1752 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 if (nlh->nlmsg_flags & NLM_F_EXCL) {
1754 err = -EEXIST;
Thomas Graf5208deb2006-08-07 17:55:40 -07001755 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001756 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 }
Thomas Graf5208deb2006-08-07 17:55:40 -07001758
1759 if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
1760 flags &= ~NEIGH_UPDATE_F_OVERRIDE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 }
1762
Eric Biederman0c5c2d32009-03-04 00:03:08 -08001763 if (ndm->ndm_flags & NTF_USE) {
1764 neigh_event_send(neigh, NULL);
1765 err = 0;
1766 } else
1767 err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
Thomas Graf5208deb2006-08-07 17:55:40 -07001768 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001769 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 }
1771
1772 read_unlock(&neigh_tbl_lock);
Thomas Graf5208deb2006-08-07 17:55:40 -07001773 err = -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774out:
1775 return err;
1776}
1777
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001778static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1779{
Thomas Grafca860fb2006-08-07 18:00:18 -07001780 struct nlattr *nest;
1781
1782 nest = nla_nest_start(skb, NDTA_PARMS);
1783 if (nest == NULL)
1784 return -ENOBUFS;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001785
David S. Miller9a6308d2012-04-01 20:06:28 -04001786 if ((parms->dev &&
1787 nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
1788 nla_put_u32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)) ||
1789 nla_put_u32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes) ||
1790 /* approximative value for deprecated QUEUE_LEN (in packets) */
1791 nla_put_u32(skb, NDTPA_QUEUE_LEN,
Shan Weice46cc62012-12-04 18:49:15 +00001792 parms->queue_len_bytes / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
David S. Miller9a6308d2012-04-01 20:06:28 -04001793 nla_put_u32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen) ||
1794 nla_put_u32(skb, NDTPA_APP_PROBES, parms->app_probes) ||
1795 nla_put_u32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes) ||
1796 nla_put_u32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes) ||
1797 nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time) ||
1798 nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
1799 parms->base_reachable_time) ||
1800 nla_put_msecs(skb, NDTPA_GC_STALETIME, parms->gc_staletime) ||
1801 nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
1802 parms->delay_probe_time) ||
1803 nla_put_msecs(skb, NDTPA_RETRANS_TIME, parms->retrans_time) ||
1804 nla_put_msecs(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay) ||
1805 nla_put_msecs(skb, NDTPA_PROXY_DELAY, parms->proxy_delay) ||
1806 nla_put_msecs(skb, NDTPA_LOCKTIME, parms->locktime))
1807 goto nla_put_failure;
Thomas Grafca860fb2006-08-07 18:00:18 -07001808 return nla_nest_end(skb, nest);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001809
Thomas Grafca860fb2006-08-07 18:00:18 -07001810nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07001811 nla_nest_cancel(skb, nest);
1812 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001813}
1814
Thomas Grafca860fb2006-08-07 18:00:18 -07001815static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
1816 u32 pid, u32 seq, int type, int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001817{
1818 struct nlmsghdr *nlh;
1819 struct ndtmsg *ndtmsg;
1820
Thomas Grafca860fb2006-08-07 18:00:18 -07001821 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1822 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001823 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001824
Thomas Grafca860fb2006-08-07 18:00:18 -07001825 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001826
1827 read_lock_bh(&tbl->lock);
1828 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001829 ndtmsg->ndtm_pad1 = 0;
1830 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001831
David S. Miller9a6308d2012-04-01 20:06:28 -04001832 if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
1833 nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval) ||
1834 nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) ||
1835 nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) ||
1836 nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3))
1837 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001838 {
1839 unsigned long now = jiffies;
1840 unsigned int flush_delta = now - tbl->last_flush;
1841 unsigned int rand_delta = now - tbl->last_rand;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001842 struct neigh_hash_table *nht;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001843 struct ndt_config ndc = {
1844 .ndtc_key_len = tbl->key_len,
1845 .ndtc_entry_size = tbl->entry_size,
1846 .ndtc_entries = atomic_read(&tbl->entries),
1847 .ndtc_last_flush = jiffies_to_msecs(flush_delta),
1848 .ndtc_last_rand = jiffies_to_msecs(rand_delta),
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001849 .ndtc_proxy_qlen = tbl->proxy_queue.qlen,
1850 };
1851
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001852 rcu_read_lock_bh();
1853 nht = rcu_dereference_bh(tbl->nht);
David S. Miller2c2aba62011-12-28 15:06:58 -05001854 ndc.ndtc_hash_rnd = nht->hash_rnd[0];
David S. Millercd089332011-07-11 01:28:12 -07001855 ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001856 rcu_read_unlock_bh();
1857
David S. Miller9a6308d2012-04-01 20:06:28 -04001858 if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
1859 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001860 }
1861
1862 {
1863 int cpu;
1864 struct ndt_stats ndst;
1865
1866 memset(&ndst, 0, sizeof(ndst));
1867
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001868 for_each_possible_cpu(cpu) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001869 struct neigh_statistics *st;
1870
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001871 st = per_cpu_ptr(tbl->stats, cpu);
1872 ndst.ndts_allocs += st->allocs;
1873 ndst.ndts_destroys += st->destroys;
1874 ndst.ndts_hash_grows += st->hash_grows;
1875 ndst.ndts_res_failed += st->res_failed;
1876 ndst.ndts_lookups += st->lookups;
1877 ndst.ndts_hits += st->hits;
1878 ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast;
1879 ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast;
1880 ndst.ndts_periodic_gc_runs += st->periodic_gc_runs;
1881 ndst.ndts_forced_gc_runs += st->forced_gc_runs;
1882 }
1883
David S. Miller9a6308d2012-04-01 20:06:28 -04001884 if (nla_put(skb, NDTA_STATS, sizeof(ndst), &ndst))
1885 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001886 }
1887
1888 BUG_ON(tbl->parms.dev);
1889 if (neightbl_fill_parms(skb, &tbl->parms) < 0)
Thomas Grafca860fb2006-08-07 18:00:18 -07001890 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001891
1892 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001893 return nlmsg_end(skb, nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001894
Thomas Grafca860fb2006-08-07 18:00:18 -07001895nla_put_failure:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001896 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001897 nlmsg_cancel(skb, nlh);
1898 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001899}
1900
Thomas Grafca860fb2006-08-07 18:00:18 -07001901static int neightbl_fill_param_info(struct sk_buff *skb,
1902 struct neigh_table *tbl,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001903 struct neigh_parms *parms,
Thomas Grafca860fb2006-08-07 18:00:18 -07001904 u32 pid, u32 seq, int type,
1905 unsigned int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001906{
1907 struct ndtmsg *ndtmsg;
1908 struct nlmsghdr *nlh;
1909
Thomas Grafca860fb2006-08-07 18:00:18 -07001910 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1911 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001912 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001913
Thomas Grafca860fb2006-08-07 18:00:18 -07001914 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001915
1916 read_lock_bh(&tbl->lock);
1917 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001918 ndtmsg->ndtm_pad1 = 0;
1919 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001920
Thomas Grafca860fb2006-08-07 18:00:18 -07001921 if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
1922 neightbl_fill_parms(skb, parms) < 0)
1923 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001924
1925 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001926 return nlmsg_end(skb, nlh);
1927errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001928 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001929 nlmsg_cancel(skb, nlh);
1930 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001931}
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001932
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001933static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001934 [NDTA_NAME] = { .type = NLA_STRING },
1935 [NDTA_THRESH1] = { .type = NLA_U32 },
1936 [NDTA_THRESH2] = { .type = NLA_U32 },
1937 [NDTA_THRESH3] = { .type = NLA_U32 },
1938 [NDTA_GC_INTERVAL] = { .type = NLA_U64 },
1939 [NDTA_PARMS] = { .type = NLA_NESTED },
1940};
1941
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001942static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001943 [NDTPA_IFINDEX] = { .type = NLA_U32 },
1944 [NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
1945 [NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
1946 [NDTPA_APP_PROBES] = { .type = NLA_U32 },
1947 [NDTPA_UCAST_PROBES] = { .type = NLA_U32 },
1948 [NDTPA_MCAST_PROBES] = { .type = NLA_U32 },
1949 [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 },
1950 [NDTPA_GC_STALETIME] = { .type = NLA_U64 },
1951 [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 },
1952 [NDTPA_RETRANS_TIME] = { .type = NLA_U64 },
1953 [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
1954 [NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
1955 [NDTPA_LOCKTIME] = { .type = NLA_U64 },
1956};
1957
Thomas Grafc8822a42007-03-22 11:50:06 -07001958static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001959{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001960 struct net *net = sock_net(skb->sk);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001961 struct neigh_table *tbl;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001962 struct ndtmsg *ndtmsg;
1963 struct nlattr *tb[NDTA_MAX+1];
1964 int err;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001965
Thomas Graf6b3f8672006-08-07 17:58:53 -07001966 err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
1967 nl_neightbl_policy);
1968 if (err < 0)
1969 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001970
Thomas Graf6b3f8672006-08-07 17:58:53 -07001971 if (tb[NDTA_NAME] == NULL) {
1972 err = -EINVAL;
1973 goto errout;
1974 }
1975
1976 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001977 read_lock(&neigh_tbl_lock);
1978 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
1979 if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
1980 continue;
1981
Thomas Graf6b3f8672006-08-07 17:58:53 -07001982 if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001983 break;
1984 }
1985
1986 if (tbl == NULL) {
1987 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001988 goto errout_locked;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001989 }
1990
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001991 /*
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001992 * We acquire tbl->lock to be nice to the periodic timers and
1993 * make sure they always see a consistent set of values.
1994 */
1995 write_lock_bh(&tbl->lock);
1996
Thomas Graf6b3f8672006-08-07 17:58:53 -07001997 if (tb[NDTA_PARMS]) {
1998 struct nlattr *tbp[NDTPA_MAX+1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001999 struct neigh_parms *p;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002000 int i, ifindex = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002001
Thomas Graf6b3f8672006-08-07 17:58:53 -07002002 err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
2003 nl_ntbl_parm_policy);
2004 if (err < 0)
2005 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002006
Thomas Graf6b3f8672006-08-07 17:58:53 -07002007 if (tbp[NDTPA_IFINDEX])
2008 ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002009
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07002010 p = lookup_neigh_parms(tbl, net, ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002011 if (p == NULL) {
2012 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07002013 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002014 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002015
Thomas Graf6b3f8672006-08-07 17:58:53 -07002016 for (i = 1; i <= NDTPA_MAX; i++) {
2017 if (tbp[i] == NULL)
2018 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002019
Thomas Graf6b3f8672006-08-07 17:58:53 -07002020 switch (i) {
2021 case NDTPA_QUEUE_LEN:
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002022 p->queue_len_bytes = nla_get_u32(tbp[i]) *
2023 SKB_TRUESIZE(ETH_FRAME_LEN);
2024 break;
2025 case NDTPA_QUEUE_LENBYTES:
2026 p->queue_len_bytes = nla_get_u32(tbp[i]);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002027 break;
2028 case NDTPA_PROXY_QLEN:
2029 p->proxy_qlen = nla_get_u32(tbp[i]);
2030 break;
2031 case NDTPA_APP_PROBES:
2032 p->app_probes = nla_get_u32(tbp[i]);
2033 break;
2034 case NDTPA_UCAST_PROBES:
2035 p->ucast_probes = nla_get_u32(tbp[i]);
2036 break;
2037 case NDTPA_MCAST_PROBES:
2038 p->mcast_probes = nla_get_u32(tbp[i]);
2039 break;
2040 case NDTPA_BASE_REACHABLE_TIME:
2041 p->base_reachable_time = nla_get_msecs(tbp[i]);
2042 break;
2043 case NDTPA_GC_STALETIME:
2044 p->gc_staletime = nla_get_msecs(tbp[i]);
2045 break;
2046 case NDTPA_DELAY_PROBE_TIME:
2047 p->delay_probe_time = nla_get_msecs(tbp[i]);
2048 break;
2049 case NDTPA_RETRANS_TIME:
2050 p->retrans_time = nla_get_msecs(tbp[i]);
2051 break;
2052 case NDTPA_ANYCAST_DELAY:
2053 p->anycast_delay = nla_get_msecs(tbp[i]);
2054 break;
2055 case NDTPA_PROXY_DELAY:
2056 p->proxy_delay = nla_get_msecs(tbp[i]);
2057 break;
2058 case NDTPA_LOCKTIME:
2059 p->locktime = nla_get_msecs(tbp[i]);
2060 break;
2061 }
2062 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002063 }
2064
Thomas Graf6b3f8672006-08-07 17:58:53 -07002065 if (tb[NDTA_THRESH1])
2066 tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
2067
2068 if (tb[NDTA_THRESH2])
2069 tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
2070
2071 if (tb[NDTA_THRESH3])
2072 tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
2073
2074 if (tb[NDTA_GC_INTERVAL])
2075 tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2076
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002077 err = 0;
2078
Thomas Graf6b3f8672006-08-07 17:58:53 -07002079errout_tbl_lock:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002080 write_unlock_bh(&tbl->lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002081errout_locked:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002082 read_unlock(&neigh_tbl_lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002083errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002084 return err;
2085}
2086
Thomas Grafc8822a42007-03-22 11:50:06 -07002087static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002088{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002089 struct net *net = sock_net(skb->sk);
Thomas Grafca860fb2006-08-07 18:00:18 -07002090 int family, tidx, nidx = 0;
2091 int tbl_skip = cb->args[0];
2092 int neigh_skip = cb->args[1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002093 struct neigh_table *tbl;
2094
Thomas Grafca860fb2006-08-07 18:00:18 -07002095 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002096
2097 read_lock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07002098 for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002099 struct neigh_parms *p;
2100
Thomas Grafca860fb2006-08-07 18:00:18 -07002101 if (tidx < tbl_skip || (family && tbl->family != family))
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002102 continue;
2103
Eric W. Biederman15e47302012-09-07 20:12:54 +00002104 if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
Thomas Grafca860fb2006-08-07 18:00:18 -07002105 cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
2106 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002107 break;
2108
Eric W. Biederman426b5302008-01-24 00:13:18 -08002109 for (nidx = 0, p = tbl->parms.next; p; p = p->next) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002110 if (!net_eq(neigh_parms_net(p), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002111 continue;
2112
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002113 if (nidx < neigh_skip)
2114 goto next;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002115
Thomas Grafca860fb2006-08-07 18:00:18 -07002116 if (neightbl_fill_param_info(skb, tbl, p,
Eric W. Biederman15e47302012-09-07 20:12:54 +00002117 NETLINK_CB(cb->skb).portid,
Thomas Grafca860fb2006-08-07 18:00:18 -07002118 cb->nlh->nlmsg_seq,
2119 RTM_NEWNEIGHTBL,
2120 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002121 goto out;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002122 next:
2123 nidx++;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002124 }
2125
Thomas Grafca860fb2006-08-07 18:00:18 -07002126 neigh_skip = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002127 }
2128out:
2129 read_unlock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07002130 cb->args[0] = tidx;
2131 cb->args[1] = nidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002132
2133 return skb->len;
2134}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
Thomas Graf8b8aec52006-08-07 17:56:37 -07002136static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
2137 u32 pid, u32 seq, int type, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138{
2139 unsigned long now = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 struct nda_cacheinfo ci;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002141 struct nlmsghdr *nlh;
2142 struct ndmsg *ndm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143
Thomas Graf8b8aec52006-08-07 17:56:37 -07002144 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2145 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002146 return -EMSGSIZE;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002147
2148 ndm = nlmsg_data(nlh);
2149 ndm->ndm_family = neigh->ops->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002150 ndm->ndm_pad1 = 0;
2151 ndm->ndm_pad2 = 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002152 ndm->ndm_flags = neigh->flags;
2153 ndm->ndm_type = neigh->type;
2154 ndm->ndm_ifindex = neigh->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155
David S. Miller9a6308d2012-04-01 20:06:28 -04002156 if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
2157 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002158
2159 read_lock_bh(&neigh->lock);
2160 ndm->ndm_state = neigh->nud_state;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00002161 if (neigh->nud_state & NUD_VALID) {
2162 char haddr[MAX_ADDR_LEN];
2163
2164 neigh_ha_snapshot(haddr, neigh, neigh->dev);
2165 if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
2166 read_unlock_bh(&neigh->lock);
2167 goto nla_put_failure;
2168 }
Thomas Graf8b8aec52006-08-07 17:56:37 -07002169 }
2170
Stephen Hemmingerb9f5f522008-06-03 16:03:15 -07002171 ci.ndm_used = jiffies_to_clock_t(now - neigh->used);
2172 ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2173 ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002174 ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1;
2175 read_unlock_bh(&neigh->lock);
2176
David S. Miller9a6308d2012-04-01 20:06:28 -04002177 if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
2178 nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
2179 goto nla_put_failure;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002180
2181 return nlmsg_end(skb, nlh);
2182
2183nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002184 nlmsg_cancel(skb, nlh);
2185 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186}
2187
Tony Zelenoff84920c12012-01-26 22:28:58 +00002188static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
2189 u32 pid, u32 seq, int type, unsigned int flags,
2190 struct neigh_table *tbl)
2191{
2192 struct nlmsghdr *nlh;
2193 struct ndmsg *ndm;
2194
2195 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2196 if (nlh == NULL)
2197 return -EMSGSIZE;
2198
2199 ndm = nlmsg_data(nlh);
2200 ndm->ndm_family = tbl->family;
2201 ndm->ndm_pad1 = 0;
2202 ndm->ndm_pad2 = 0;
2203 ndm->ndm_flags = pn->flags | NTF_PROXY;
2204 ndm->ndm_type = NDA_DST;
2205 ndm->ndm_ifindex = pn->dev->ifindex;
2206 ndm->ndm_state = NUD_NONE;
2207
David S. Miller9a6308d2012-04-01 20:06:28 -04002208 if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
2209 goto nla_put_failure;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002210
2211 return nlmsg_end(skb, nlh);
2212
2213nla_put_failure:
2214 nlmsg_cancel(skb, nlh);
2215 return -EMSGSIZE;
2216}
2217
Thomas Grafd961db32007-08-08 23:12:56 -07002218static void neigh_update_notify(struct neighbour *neigh)
2219{
2220 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
2221 __neigh_notify(neigh, RTM_NEWNEIGH, 0);
2222}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223
2224static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2225 struct netlink_callback *cb)
2226{
Eric Dumazet767e97e2010-10-06 17:49:21 -07002227 struct net *net = sock_net(skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 struct neighbour *n;
2229 int rc, h, s_h = cb->args[1];
2230 int idx, s_idx = idx = cb->args[2];
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002231 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002233 rcu_read_lock_bh();
2234 nht = rcu_dereference_bh(tbl->nht);
2235
Eric Dumazet4bd66832012-06-07 04:58:35 +00002236 for (h = s_h; h < (1 << nht->hash_shift); h++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 if (h > s_h)
2238 s_idx = 0;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002239 for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2240 n != NULL;
2241 n = rcu_dereference_bh(n->next)) {
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002242 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002243 continue;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002244 if (idx < s_idx)
2245 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002246 if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 cb->nlh->nlmsg_seq,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07002248 RTM_NEWNEIGH,
2249 NLM_F_MULTI) <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 rc = -1;
2251 goto out;
2252 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002253next:
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002254 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 }
2257 rc = skb->len;
2258out:
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002259 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 cb->args[1] = h;
2261 cb->args[2] = idx;
2262 return rc;
2263}
2264
Tony Zelenoff84920c12012-01-26 22:28:58 +00002265static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2266 struct netlink_callback *cb)
2267{
2268 struct pneigh_entry *n;
2269 struct net *net = sock_net(skb->sk);
2270 int rc, h, s_h = cb->args[3];
2271 int idx, s_idx = idx = cb->args[4];
2272
2273 read_lock_bh(&tbl->lock);
2274
Eric Dumazet4bd66832012-06-07 04:58:35 +00002275 for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
Tony Zelenoff84920c12012-01-26 22:28:58 +00002276 if (h > s_h)
2277 s_idx = 0;
2278 for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
2279 if (dev_net(n->dev) != net)
2280 continue;
2281 if (idx < s_idx)
2282 goto next;
Eric W. Biederman15e47302012-09-07 20:12:54 +00002283 if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
Tony Zelenoff84920c12012-01-26 22:28:58 +00002284 cb->nlh->nlmsg_seq,
2285 RTM_NEWNEIGH,
2286 NLM_F_MULTI, tbl) <= 0) {
2287 read_unlock_bh(&tbl->lock);
2288 rc = -1;
2289 goto out;
2290 }
2291 next:
2292 idx++;
2293 }
2294 }
2295
2296 read_unlock_bh(&tbl->lock);
2297 rc = skb->len;
2298out:
2299 cb->args[3] = h;
2300 cb->args[4] = idx;
2301 return rc;
2302
2303}
2304
Thomas Grafc8822a42007-03-22 11:50:06 -07002305static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306{
2307 struct neigh_table *tbl;
2308 int t, family, s_t;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002309 int proxy = 0;
Eric Dumazet4bd66832012-06-07 04:58:35 +00002310 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311
2312 read_lock(&neigh_tbl_lock);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002313 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002314
2315 /* check for full ndmsg structure presence, family member is
2316 * the same for both structures
2317 */
2318 if (nlmsg_len(cb->nlh) >= sizeof(struct ndmsg) &&
2319 ((struct ndmsg *) nlmsg_data(cb->nlh))->ndm_flags == NTF_PROXY)
2320 proxy = 1;
2321
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 s_t = cb->args[0];
2323
Eric Dumazet4bd66832012-06-07 04:58:35 +00002324 for (tbl = neigh_tables, t = 0; tbl;
Tony Zelenoff84920c12012-01-26 22:28:58 +00002325 tbl = tbl->next, t++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 if (t < s_t || (family && tbl->family != family))
2327 continue;
2328 if (t > s_t)
2329 memset(&cb->args[1], 0, sizeof(cb->args) -
2330 sizeof(cb->args[0]));
Tony Zelenoff84920c12012-01-26 22:28:58 +00002331 if (proxy)
2332 err = pneigh_dump_table(tbl, skb, cb);
2333 else
2334 err = neigh_dump_table(tbl, skb, cb);
Eric Dumazet4bd66832012-06-07 04:58:35 +00002335 if (err < 0)
2336 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 }
2338 read_unlock(&neigh_tbl_lock);
2339
2340 cb->args[0] = t;
2341 return skb->len;
2342}
2343
2344void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
2345{
2346 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002347 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002349 rcu_read_lock_bh();
2350 nht = rcu_dereference_bh(tbl->nht);
2351
Eric Dumazet767e97e2010-10-06 17:49:21 -07002352 read_lock(&tbl->lock); /* avoid resizes */
David S. Millercd089332011-07-11 01:28:12 -07002353 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 struct neighbour *n;
2355
Eric Dumazet767e97e2010-10-06 17:49:21 -07002356 for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
2357 n != NULL;
2358 n = rcu_dereference_bh(n->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 cb(n, cookie);
2360 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002361 read_unlock(&tbl->lock);
2362 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363}
2364EXPORT_SYMBOL(neigh_for_each);
2365
2366/* The tbl->lock must be held as a writer and BH disabled. */
2367void __neigh_for_each_release(struct neigh_table *tbl,
2368 int (*cb)(struct neighbour *))
2369{
2370 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002371 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002373 nht = rcu_dereference_protected(tbl->nht,
2374 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -07002375 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002376 struct neighbour *n;
2377 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002379 np = &nht->hash_buckets[chain];
Eric Dumazet767e97e2010-10-06 17:49:21 -07002380 while ((n = rcu_dereference_protected(*np,
2381 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 int release;
2383
2384 write_lock(&n->lock);
2385 release = cb(n);
2386 if (release) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002387 rcu_assign_pointer(*np,
2388 rcu_dereference_protected(n->next,
2389 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 n->dead = 1;
2391 } else
2392 np = &n->next;
2393 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -07002394 if (release)
2395 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 }
2397 }
2398}
2399EXPORT_SYMBOL(__neigh_for_each_release);
2400
2401#ifdef CONFIG_PROC_FS
2402
2403static struct neighbour *neigh_get_first(struct seq_file *seq)
2404{
2405 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002406 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002407 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 struct neighbour *n = NULL;
2409 int bucket = state->bucket;
2410
2411 state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
David S. Millercd089332011-07-11 01:28:12 -07002412 for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002413 n = rcu_dereference_bh(nht->hash_buckets[bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414
2415 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002416 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002417 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 if (state->neigh_sub_iter) {
2419 loff_t fakep = 0;
2420 void *v;
2421
2422 v = state->neigh_sub_iter(state, n, &fakep);
2423 if (!v)
2424 goto next;
2425 }
2426 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2427 break;
2428 if (n->nud_state & ~NUD_NOARP)
2429 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002430next:
2431 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 }
2433
2434 if (n)
2435 break;
2436 }
2437 state->bucket = bucket;
2438
2439 return n;
2440}
2441
2442static struct neighbour *neigh_get_next(struct seq_file *seq,
2443 struct neighbour *n,
2444 loff_t *pos)
2445{
2446 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002447 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002448 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449
2450 if (state->neigh_sub_iter) {
2451 void *v = state->neigh_sub_iter(state, n, pos);
2452 if (v)
2453 return n;
2454 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002455 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456
2457 while (1) {
2458 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002459 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002460 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 if (state->neigh_sub_iter) {
2462 void *v = state->neigh_sub_iter(state, n, pos);
2463 if (v)
2464 return n;
2465 goto next;
2466 }
2467 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2468 break;
2469
2470 if (n->nud_state & ~NUD_NOARP)
2471 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002472next:
2473 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 }
2475
2476 if (n)
2477 break;
2478
David S. Millercd089332011-07-11 01:28:12 -07002479 if (++state->bucket >= (1 << nht->hash_shift))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 break;
2481
Eric Dumazet767e97e2010-10-06 17:49:21 -07002482 n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 }
2484
2485 if (n && pos)
2486 --(*pos);
2487 return n;
2488}
2489
2490static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
2491{
2492 struct neighbour *n = neigh_get_first(seq);
2493
2494 if (n) {
Chris Larson745e2032008-08-03 01:10:55 -07002495 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 while (*pos) {
2497 n = neigh_get_next(seq, n, pos);
2498 if (!n)
2499 break;
2500 }
2501 }
2502 return *pos ? NULL : n;
2503}
2504
2505static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
2506{
2507 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002508 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 struct neigh_table *tbl = state->tbl;
2510 struct pneigh_entry *pn = NULL;
2511 int bucket = state->bucket;
2512
2513 state->flags |= NEIGH_SEQ_IS_PNEIGH;
2514 for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
2515 pn = tbl->phash_buckets[bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002516 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002517 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 if (pn)
2519 break;
2520 }
2521 state->bucket = bucket;
2522
2523 return pn;
2524}
2525
2526static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
2527 struct pneigh_entry *pn,
2528 loff_t *pos)
2529{
2530 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002531 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 struct neigh_table *tbl = state->tbl;
2533
Jorge Boncompte [DTI2]df07a942011-11-25 13:24:49 -05002534 do {
2535 pn = pn->next;
2536 } while (pn && !net_eq(pneigh_net(pn), net));
2537
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 while (!pn) {
2539 if (++state->bucket > PNEIGH_HASHMASK)
2540 break;
2541 pn = tbl->phash_buckets[state->bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002542 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002543 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 if (pn)
2545 break;
2546 }
2547
2548 if (pn && pos)
2549 --(*pos);
2550
2551 return pn;
2552}
2553
2554static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
2555{
2556 struct pneigh_entry *pn = pneigh_get_first(seq);
2557
2558 if (pn) {
Chris Larson745e2032008-08-03 01:10:55 -07002559 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 while (*pos) {
2561 pn = pneigh_get_next(seq, pn, pos);
2562 if (!pn)
2563 break;
2564 }
2565 }
2566 return *pos ? NULL : pn;
2567}
2568
2569static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
2570{
2571 struct neigh_seq_state *state = seq->private;
2572 void *rc;
Chris Larson745e2032008-08-03 01:10:55 -07002573 loff_t idxpos = *pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574
Chris Larson745e2032008-08-03 01:10:55 -07002575 rc = neigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
Chris Larson745e2032008-08-03 01:10:55 -07002577 rc = pneigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578
2579 return rc;
2580}
2581
2582void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002583 __acquires(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584{
2585 struct neigh_seq_state *state = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
2587 state->tbl = tbl;
2588 state->bucket = 0;
2589 state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
2590
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002591 rcu_read_lock_bh();
2592 state->nht = rcu_dereference_bh(tbl->nht);
Eric Dumazet767e97e2010-10-06 17:49:21 -07002593
Chris Larson745e2032008-08-03 01:10:55 -07002594 return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595}
2596EXPORT_SYMBOL(neigh_seq_start);
2597
2598void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2599{
2600 struct neigh_seq_state *state;
2601 void *rc;
2602
2603 if (v == SEQ_START_TOKEN) {
Chris Larsonbff69732008-08-03 01:02:41 -07002604 rc = neigh_get_first(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 goto out;
2606 }
2607
2608 state = seq->private;
2609 if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
2610 rc = neigh_get_next(seq, v, NULL);
2611 if (rc)
2612 goto out;
2613 if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
2614 rc = pneigh_get_first(seq);
2615 } else {
2616 BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
2617 rc = pneigh_get_next(seq, v, NULL);
2618 }
2619out:
2620 ++(*pos);
2621 return rc;
2622}
2623EXPORT_SYMBOL(neigh_seq_next);
2624
2625void neigh_seq_stop(struct seq_file *seq, void *v)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002626 __releases(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627{
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002628 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629}
2630EXPORT_SYMBOL(neigh_seq_stop);
2631
2632/* statistics via seq_file */
2633
2634static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
2635{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002636 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 int cpu;
2638
2639 if (*pos == 0)
2640 return SEQ_START_TOKEN;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002641
Rusty Russell0f23174a2008-12-29 12:23:42 +00002642 for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 if (!cpu_possible(cpu))
2644 continue;
2645 *pos = cpu+1;
2646 return per_cpu_ptr(tbl->stats, cpu);
2647 }
2648 return NULL;
2649}
2650
2651static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2652{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002653 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 int cpu;
2655
Rusty Russell0f23174a2008-12-29 12:23:42 +00002656 for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 if (!cpu_possible(cpu))
2658 continue;
2659 *pos = cpu+1;
2660 return per_cpu_ptr(tbl->stats, cpu);
2661 }
2662 return NULL;
2663}
2664
2665static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
2666{
2667
2668}
2669
2670static int neigh_stat_seq_show(struct seq_file *seq, void *v)
2671{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002672 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 struct neigh_statistics *st = v;
2674
2675 if (v == SEQ_START_TOKEN) {
Neil Horman9a6d2762008-07-16 20:50:49 -07002676 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\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 return 0;
2678 }
2679
2680 seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
Neil Horman9a6d2762008-07-16 20:50:49 -07002681 "%08lx %08lx %08lx %08lx %08lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 atomic_read(&tbl->entries),
2683
2684 st->allocs,
2685 st->destroys,
2686 st->hash_grows,
2687
2688 st->lookups,
2689 st->hits,
2690
2691 st->res_failed,
2692
2693 st->rcv_probes_mcast,
2694 st->rcv_probes_ucast,
2695
2696 st->periodic_gc_runs,
Neil Horman9a6d2762008-07-16 20:50:49 -07002697 st->forced_gc_runs,
2698 st->unres_discards
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 );
2700
2701 return 0;
2702}
2703
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002704static const struct seq_operations neigh_stat_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 .start = neigh_stat_seq_start,
2706 .next = neigh_stat_seq_next,
2707 .stop = neigh_stat_seq_stop,
2708 .show = neigh_stat_seq_show,
2709};
2710
2711static int neigh_stat_seq_open(struct inode *inode, struct file *file)
2712{
2713 int ret = seq_open(file, &neigh_stat_seq_ops);
2714
2715 if (!ret) {
2716 struct seq_file *sf = file->private_data;
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002717 sf->private = PDE(inode)->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 }
2719 return ret;
2720};
2721
Arjan van de Ven9a321442007-02-12 00:55:35 -08002722static const struct file_operations neigh_stat_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 .owner = THIS_MODULE,
2724 .open = neigh_stat_seq_open,
2725 .read = seq_read,
2726 .llseek = seq_lseek,
2727 .release = seq_release,
2728};
2729
2730#endif /* CONFIG_PROC_FS */
2731
Thomas Graf339bf982006-11-10 14:10:15 -08002732static inline size_t neigh_nlmsg_size(void)
2733{
2734 return NLMSG_ALIGN(sizeof(struct ndmsg))
2735 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2736 + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2737 + nla_total_size(sizeof(struct nda_cacheinfo))
2738 + nla_total_size(4); /* NDA_PROBES */
2739}
2740
Thomas Grafb8673312006-08-15 00:33:14 -07002741static void __neigh_notify(struct neighbour *n, int type, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002743 struct net *net = dev_net(n->dev);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002744 struct sk_buff *skb;
Thomas Grafb8673312006-08-15 00:33:14 -07002745 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746
Thomas Graf339bf982006-11-10 14:10:15 -08002747 skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002748 if (skb == NULL)
Thomas Grafb8673312006-08-15 00:33:14 -07002749 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
Thomas Grafb8673312006-08-15 00:33:14 -07002751 err = neigh_fill_info(skb, n, 0, 0, type, flags);
Patrick McHardy26932562007-01-31 23:16:40 -08002752 if (err < 0) {
2753 /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
2754 WARN_ON(err == -EMSGSIZE);
2755 kfree_skb(skb);
2756 goto errout;
2757 }
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002758 rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
2759 return;
Thomas Grafb8673312006-08-15 00:33:14 -07002760errout:
2761 if (err < 0)
Eric W. Biederman426b5302008-01-24 00:13:18 -08002762 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
Thomas Grafb8673312006-08-15 00:33:14 -07002763}
2764
Thomas Grafd961db32007-08-08 23:12:56 -07002765#ifdef CONFIG_ARPD
Thomas Grafb8673312006-08-15 00:33:14 -07002766void neigh_app_ns(struct neighbour *n)
2767{
2768 __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09002770EXPORT_SYMBOL(neigh_app_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771#endif /* CONFIG_ARPD */
2772
2773#ifdef CONFIG_SYSCTL
Cong Wangb93196d2012-12-06 10:04:04 +08002774static int zero;
2775static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002777static int proc_unres_qlen(ctl_table *ctl, int write, void __user *buffer,
2778 size_t *lenp, loff_t *ppos)
2779{
2780 int size, ret;
2781 ctl_table tmp = *ctl;
2782
Shan Weice46cc62012-12-04 18:49:15 +00002783 tmp.extra1 = &zero;
2784 tmp.extra2 = &unres_qlen_max;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002785 tmp.data = &size;
Shan Weice46cc62012-12-04 18:49:15 +00002786
2787 size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
2788 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
2789
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002790 if (write && !ret)
2791 *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
2792 return ret;
2793}
2794
2795enum {
2796 NEIGH_VAR_MCAST_PROBE,
2797 NEIGH_VAR_UCAST_PROBE,
2798 NEIGH_VAR_APP_PROBE,
2799 NEIGH_VAR_RETRANS_TIME,
2800 NEIGH_VAR_BASE_REACHABLE_TIME,
2801 NEIGH_VAR_DELAY_PROBE_TIME,
2802 NEIGH_VAR_GC_STALETIME,
2803 NEIGH_VAR_QUEUE_LEN,
2804 NEIGH_VAR_QUEUE_LEN_BYTES,
2805 NEIGH_VAR_PROXY_QLEN,
2806 NEIGH_VAR_ANYCAST_DELAY,
2807 NEIGH_VAR_PROXY_DELAY,
2808 NEIGH_VAR_LOCKTIME,
2809 NEIGH_VAR_RETRANS_TIME_MS,
2810 NEIGH_VAR_BASE_REACHABLE_TIME_MS,
2811 NEIGH_VAR_GC_INTERVAL,
2812 NEIGH_VAR_GC_THRESH1,
2813 NEIGH_VAR_GC_THRESH2,
2814 NEIGH_VAR_GC_THRESH3,
2815 NEIGH_VAR_MAX
2816};
Eric W. Biederman54716e32010-02-14 03:27:03 +00002817
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818static struct neigh_sysctl_table {
2819 struct ctl_table_header *sysctl_header;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002820 struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
Brian Haleyab32ea52006-09-22 14:15:41 -07002821} neigh_sysctl_template __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 .neigh_vars = {
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002823 [NEIGH_VAR_MCAST_PROBE] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 .procname = "mcast_solicit",
2825 .maxlen = sizeof(int),
2826 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002827 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002829 [NEIGH_VAR_UCAST_PROBE] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 .procname = "ucast_solicit",
2831 .maxlen = sizeof(int),
2832 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002833 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002835 [NEIGH_VAR_APP_PROBE] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 .procname = "app_solicit",
2837 .maxlen = sizeof(int),
2838 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002839 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002841 [NEIGH_VAR_RETRANS_TIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 .procname = "retrans_time",
2843 .maxlen = sizeof(int),
2844 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002845 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002847 [NEIGH_VAR_BASE_REACHABLE_TIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 .procname = "base_reachable_time",
2849 .maxlen = sizeof(int),
2850 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002851 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002853 [NEIGH_VAR_DELAY_PROBE_TIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 .procname = "delay_first_probe_time",
2855 .maxlen = sizeof(int),
2856 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002857 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002859 [NEIGH_VAR_GC_STALETIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 .procname = "gc_stale_time",
2861 .maxlen = sizeof(int),
2862 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002863 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002865 [NEIGH_VAR_QUEUE_LEN] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 .procname = "unres_qlen",
2867 .maxlen = sizeof(int),
2868 .mode = 0644,
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002869 .proc_handler = proc_unres_qlen,
2870 },
2871 [NEIGH_VAR_QUEUE_LEN_BYTES] = {
2872 .procname = "unres_qlen_bytes",
2873 .maxlen = sizeof(int),
2874 .mode = 0644,
Shan Weice46cc62012-12-04 18:49:15 +00002875 .extra1 = &zero,
2876 .proc_handler = proc_dointvec_minmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002878 [NEIGH_VAR_PROXY_QLEN] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 .procname = "proxy_qlen",
2880 .maxlen = sizeof(int),
2881 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002882 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002884 [NEIGH_VAR_ANYCAST_DELAY] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 .procname = "anycast_delay",
2886 .maxlen = sizeof(int),
2887 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002888 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002890 [NEIGH_VAR_PROXY_DELAY] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 .procname = "proxy_delay",
2892 .maxlen = sizeof(int),
2893 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002894 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002896 [NEIGH_VAR_LOCKTIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 .procname = "locktime",
2898 .maxlen = sizeof(int),
2899 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002900 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002902 [NEIGH_VAR_RETRANS_TIME_MS] = {
Eric W. Biedermand12af672007-10-18 03:05:25 -07002903 .procname = "retrans_time_ms",
2904 .maxlen = sizeof(int),
2905 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002906 .proc_handler = proc_dointvec_ms_jiffies,
Eric W. Biedermand12af672007-10-18 03:05:25 -07002907 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002908 [NEIGH_VAR_BASE_REACHABLE_TIME_MS] = {
Eric W. Biedermand12af672007-10-18 03:05:25 -07002909 .procname = "base_reachable_time_ms",
2910 .maxlen = sizeof(int),
2911 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002912 .proc_handler = proc_dointvec_ms_jiffies,
Eric W. Biedermand12af672007-10-18 03:05:25 -07002913 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002914 [NEIGH_VAR_GC_INTERVAL] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 .procname = "gc_interval",
2916 .maxlen = sizeof(int),
2917 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002918 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002920 [NEIGH_VAR_GC_THRESH1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 .procname = "gc_thresh1",
2922 .maxlen = sizeof(int),
2923 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002924 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002926 [NEIGH_VAR_GC_THRESH2] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 .procname = "gc_thresh2",
2928 .maxlen = sizeof(int),
2929 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002930 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002932 [NEIGH_VAR_GC_THRESH3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 .procname = "gc_thresh3",
2934 .maxlen = sizeof(int),
2935 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002936 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002938 {},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 },
2940};
2941
2942int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
Eric W. Biederman54716e32010-02-14 03:27:03 +00002943 char *p_name, proc_handler *handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944{
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002945 struct neigh_sysctl_table *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 const char *dev_name_source = NULL;
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00002947 char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002949 t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 if (!t)
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002951 goto err;
2952
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002953 t->neigh_vars[NEIGH_VAR_MCAST_PROBE].data = &p->mcast_probes;
2954 t->neigh_vars[NEIGH_VAR_UCAST_PROBE].data = &p->ucast_probes;
2955 t->neigh_vars[NEIGH_VAR_APP_PROBE].data = &p->app_probes;
2956 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].data = &p->retrans_time;
2957 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].data = &p->base_reachable_time;
2958 t->neigh_vars[NEIGH_VAR_DELAY_PROBE_TIME].data = &p->delay_probe_time;
2959 t->neigh_vars[NEIGH_VAR_GC_STALETIME].data = &p->gc_staletime;
2960 t->neigh_vars[NEIGH_VAR_QUEUE_LEN].data = &p->queue_len_bytes;
2961 t->neigh_vars[NEIGH_VAR_QUEUE_LEN_BYTES].data = &p->queue_len_bytes;
2962 t->neigh_vars[NEIGH_VAR_PROXY_QLEN].data = &p->proxy_qlen;
2963 t->neigh_vars[NEIGH_VAR_ANYCAST_DELAY].data = &p->anycast_delay;
2964 t->neigh_vars[NEIGH_VAR_PROXY_DELAY].data = &p->proxy_delay;
2965 t->neigh_vars[NEIGH_VAR_LOCKTIME].data = &p->locktime;
2966 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].data = &p->retrans_time;
2967 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].data = &p->base_reachable_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968
2969 if (dev) {
2970 dev_name_source = dev->name;
Eric W. Biedermand12af672007-10-18 03:05:25 -07002971 /* Terminate the table early */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002972 memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
2973 sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 } else {
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00002975 dev_name_source = "default";
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002976 t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = (int *)(p + 1);
2977 t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = (int *)(p + 1) + 1;
2978 t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = (int *)(p + 1) + 2;
2979 t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = (int *)(p + 1) + 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 }
2981
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002983 if (handler) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 /* RetransTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002985 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
2986 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 /* ReachableTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002988 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
2989 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 /* RetransTime (in milliseconds)*/
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002991 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
2992 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 /* ReachableTime (in milliseconds) */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002994 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
2995 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 }
2997
Eric W. Biederman464dc802012-11-16 03:02:59 +00002998 /* Don't export sysctls to unprivileged users */
2999 if (neigh_parms_net(p)->user_ns != &init_user_ns)
3000 t->neigh_vars[0].procname = NULL;
3001
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003002 snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
3003 p_name, dev_name_source);
Denis V. Lunev4ab438f2008-02-28 20:48:01 -08003004 t->sysctl_header =
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003005 register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003006 if (!t->sysctl_header)
Eric W. Biederman8f40a1f2012-04-19 13:38:03 +00003007 goto free;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003008
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 p->sysctl_table = t;
3010 return 0;
3011
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003012free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 kfree(t);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11003014err:
3015 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003017EXPORT_SYMBOL(neigh_sysctl_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018
3019void neigh_sysctl_unregister(struct neigh_parms *p)
3020{
3021 if (p->sysctl_table) {
3022 struct neigh_sysctl_table *t = p->sysctl_table;
3023 p->sysctl_table = NULL;
Eric W. Biederman5dd3df12012-04-19 13:24:33 +00003024 unregister_net_sysctl_table(t->sysctl_header);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 kfree(t);
3026 }
3027}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09003028EXPORT_SYMBOL(neigh_sysctl_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
3030#endif /* CONFIG_SYSCTL */
3031
Thomas Grafc8822a42007-03-22 11:50:06 -07003032static int __init neigh_init(void)
3033{
Greg Rosec7ac8672011-06-10 01:27:09 +00003034 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, NULL);
3035 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, NULL);
3036 rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, NULL);
Thomas Grafc8822a42007-03-22 11:50:06 -07003037
Greg Rosec7ac8672011-06-10 01:27:09 +00003038 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
3039 NULL);
3040 rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, NULL);
Thomas Grafc8822a42007-03-22 11:50:06 -07003041
3042 return 0;
3043}
3044
3045subsys_initcall(neigh_init);
3046