blob: ef750ff7497ed0384d4eab05282b6ec55e374b71 [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
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090018#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/types.h>
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/socket.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/netdevice.h>
24#include <linux/proc_fs.h>
25#ifdef CONFIG_SYSCTL
26#include <linux/sysctl.h>
27#endif
28#include <linux/times.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020029#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <net/neighbour.h>
31#include <net/dst.h>
32#include <net/sock.h>
Tom Tucker8d717402006-07-30 20:43:36 -070033#include <net/netevent.h>
Thomas Grafa14a49d2006-08-07 17:53:08 -070034#include <net/netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/rtnetlink.h>
36#include <linux/random.h>
Paulo Marques543537b2005-06-23 00:09:02 -070037#include <linux/string.h>
vignesh babuc3609d52007-08-24 22:27:55 -070038#include <linux/log2.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40#define NEIGH_DEBUG 1
41
42#define NEIGH_PRINTK(x...) printk(x)
43#define NEIGH_NOPRINTK(x...) do { ; } while(0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#define NEIGH_PRINTK1 NEIGH_NOPRINTK
45#define NEIGH_PRINTK2 NEIGH_NOPRINTK
46
47#if NEIGH_DEBUG >= 1
48#undef NEIGH_PRINTK1
49#define NEIGH_PRINTK1 NEIGH_PRINTK
50#endif
51#if NEIGH_DEBUG >= 2
52#undef NEIGH_PRINTK2
53#define NEIGH_PRINTK2 NEIGH_PRINTK
54#endif
55
56#define PNEIGH_HASHMASK 0xF
57
58static void neigh_timer_handler(unsigned long arg);
Thomas Grafd961db32007-08-08 23:12:56 -070059static void __neigh_notify(struct neighbour *n, int type, int flags);
60static void neigh_update_notify(struct neighbour *neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -070061static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63static struct neigh_table *neigh_tables;
Amos Waterland45fc3b12005-09-24 16:53:16 -070064#ifdef CONFIG_PROC_FS
Arjan van de Ven9a321442007-02-12 00:55:35 -080065static const struct file_operations neigh_stat_seq_fops;
Amos Waterland45fc3b12005-09-24 16:53:16 -070066#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68/*
69 Neighbour hash table buckets are protected with rwlock tbl->lock.
70
71 - All the scans/updates to hash buckets MUST be made under this lock.
72 - NOTHING clever should be made under this lock: no callbacks
73 to protocol backends, no attempts to send something to network.
74 It will result in deadlocks, if backend/driver wants to use neighbour
75 cache.
76 - If the entry requires some non-trivial actions, increase
77 its reference count and release table lock.
78
79 Neighbour entries are protected:
80 - with reference count.
81 - with rwlock neigh->lock
82
83 Reference count prevents destruction.
84
85 neigh->lock mainly serializes ll address data and its validity state.
86 However, the same lock is used to protect another entry fields:
87 - timer
88 - resolution queue
89
90 Again, nothing clever shall be made under neigh->lock,
91 the most complicated procedure, which we allow is dev->hard_header.
92 It is supposed, that dev->hard_header is simplistic and does
93 not make callbacks to neighbour tables.
94
95 The last lock is neigh_tbl_lock. It is pure SMP lock, protecting
96 list of neighbour tables. This list is used only in process context,
97 */
98
99static DEFINE_RWLOCK(neigh_tbl_lock);
100
David S. Miller8f40b162011-07-17 13:34:11 -0700101static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102{
103 kfree_skb(skb);
104 return -ENETDOWN;
105}
106
Thomas Graf4f494552007-08-08 23:12:36 -0700107static void neigh_cleanup_and_release(struct neighbour *neigh)
108{
109 if (neigh->parms->neigh_cleanup)
110 neigh->parms->neigh_cleanup(neigh);
111
Thomas Grafd961db32007-08-08 23:12:56 -0700112 __neigh_notify(neigh, RTM_DELNEIGH, 0);
Thomas Graf4f494552007-08-08 23:12:36 -0700113 neigh_release(neigh);
114}
115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116/*
117 * It is random distribution in the interval (1/2)*base...(3/2)*base.
118 * It corresponds to default IPv6 settings and is not overridable,
119 * because it is really reasonable choice.
120 */
121
122unsigned long neigh_rand_reach_time(unsigned long base)
123{
Eric Dumazeta02cec22010-09-22 20:43:57 +0000124 return base ? (net_random() % base) + (base >> 1) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900126EXPORT_SYMBOL(neigh_rand_reach_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128
129static int neigh_forced_gc(struct neigh_table *tbl)
130{
131 int shrunk = 0;
132 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000133 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
135 NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
136
137 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000138 nht = rcu_dereference_protected(tbl->nht,
139 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700140 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700141 struct neighbour *n;
142 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000144 np = &nht->hash_buckets[i];
Eric Dumazet767e97e2010-10-06 17:49:21 -0700145 while ((n = rcu_dereference_protected(*np,
146 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 /* Neighbour record may be discarded if:
148 * - nobody refers to it.
149 * - it is not permanent
150 */
151 write_lock(&n->lock);
152 if (atomic_read(&n->refcnt) == 1 &&
153 !(n->nud_state & NUD_PERMANENT)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700154 rcu_assign_pointer(*np,
155 rcu_dereference_protected(n->next,
156 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 n->dead = 1;
158 shrunk = 1;
159 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700160 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 continue;
162 }
163 write_unlock(&n->lock);
164 np = &n->next;
165 }
166 }
167
168 tbl->last_flush = jiffies;
169
170 write_unlock_bh(&tbl->lock);
171
172 return shrunk;
173}
174
Pavel Emelyanova43d8992007-12-20 15:49:05 -0800175static void neigh_add_timer(struct neighbour *n, unsigned long when)
176{
177 neigh_hold(n);
178 if (unlikely(mod_timer(&n->timer, when))) {
179 printk("NEIGH: BUG, double timer add, state is %x\n",
180 n->nud_state);
181 dump_stack();
182 }
183}
184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185static int neigh_del_timer(struct neighbour *n)
186{
187 if ((n->nud_state & NUD_IN_TIMER) &&
188 del_timer(&n->timer)) {
189 neigh_release(n);
190 return 1;
191 }
192 return 0;
193}
194
195static void pneigh_queue_purge(struct sk_buff_head *list)
196{
197 struct sk_buff *skb;
198
199 while ((skb = skb_dequeue(list)) != NULL) {
200 dev_put(skb->dev);
201 kfree_skb(skb);
202 }
203}
204
Herbert Xu49636bb2005-10-23 17:18:00 +1000205static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
207 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000208 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000210 nht = rcu_dereference_protected(tbl->nht,
211 lockdep_is_held(&tbl->lock));
212
David S. Millercd089332011-07-11 01:28:12 -0700213 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700214 struct neighbour *n;
215 struct neighbour __rcu **np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Eric Dumazet767e97e2010-10-06 17:49:21 -0700217 while ((n = rcu_dereference_protected(*np,
218 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 if (dev && n->dev != dev) {
220 np = &n->next;
221 continue;
222 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700223 rcu_assign_pointer(*np,
224 rcu_dereference_protected(n->next,
225 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 write_lock(&n->lock);
227 neigh_del_timer(n);
228 n->dead = 1;
229
230 if (atomic_read(&n->refcnt) != 1) {
231 /* The most unpleasant situation.
232 We must destroy neighbour entry,
233 but someone still uses it.
234
235 The destroy will be delayed until
236 the last user releases us, but
237 we must kill timers etc. and move
238 it to safe state.
239 */
240 skb_queue_purge(&n->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000241 n->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 n->output = neigh_blackhole;
243 if (n->nud_state & NUD_VALID)
244 n->nud_state = NUD_NOARP;
245 else
246 n->nud_state = NUD_NONE;
247 NEIGH_PRINTK2("neigh %p is stray.\n", n);
248 }
249 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700250 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 }
252 }
Herbert Xu49636bb2005-10-23 17:18:00 +1000253}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Herbert Xu49636bb2005-10-23 17:18:00 +1000255void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
256{
257 write_lock_bh(&tbl->lock);
258 neigh_flush_dev(tbl, dev);
259 write_unlock_bh(&tbl->lock);
260}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900261EXPORT_SYMBOL(neigh_changeaddr);
Herbert Xu49636bb2005-10-23 17:18:00 +1000262
263int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
264{
265 write_lock_bh(&tbl->lock);
266 neigh_flush_dev(tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 pneigh_ifdown(tbl, dev);
268 write_unlock_bh(&tbl->lock);
269
270 del_timer_sync(&tbl->proxy_timer);
271 pneigh_queue_purge(&tbl->proxy_queue);
272 return 0;
273}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900274EXPORT_SYMBOL(neigh_ifdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
David Miller596b9b62011-07-25 00:01:25 +0000276static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
278 struct neighbour *n = NULL;
279 unsigned long now = jiffies;
280 int entries;
281
282 entries = atomic_inc_return(&tbl->entries) - 1;
283 if (entries >= tbl->gc_thresh3 ||
284 (entries >= tbl->gc_thresh2 &&
285 time_after(now, tbl->last_flush + 5 * HZ))) {
286 if (!neigh_forced_gc(tbl) &&
287 entries >= tbl->gc_thresh3)
288 goto out_entries;
289 }
290
David Miller596b9b62011-07-25 00:01:25 +0000291 if (tbl->entry_size)
292 n = kzalloc(tbl->entry_size, GFP_ATOMIC);
293 else {
294 int sz = sizeof(*n) + tbl->key_len;
295
296 sz = ALIGN(sz, NEIGH_PRIV_ALIGN);
297 sz += dev->neigh_priv_len;
298 n = kzalloc(sz, GFP_ATOMIC);
299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 if (!n)
301 goto out_entries;
302
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 skb_queue_head_init(&n->arp_queue);
304 rwlock_init(&n->lock);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +0000305 seqlock_init(&n->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 n->updated = n->used = now;
307 n->nud_state = NUD_NONE;
308 n->output = neigh_blackhole;
David S. Millerf6b72b622011-07-14 07:53:20 -0700309 seqlock_init(&n->hh.hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 n->parms = neigh_parms_clone(&tbl->parms);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800311 setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 NEIGH_CACHE_STAT_INC(tbl, allocs);
314 n->tbl = tbl;
315 atomic_set(&n->refcnt, 1);
316 n->dead = 1;
317out:
318 return n;
319
320out_entries:
321 atomic_dec(&tbl->entries);
322 goto out;
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000331 ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
332 if (!ret)
333 return NULL;
334 if (size <= PAGE_SIZE)
335 buckets = kzalloc(size, GFP_ATOMIC);
336 else
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000337 buckets = (struct neighbour __rcu **)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000338 __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
339 get_order(size));
340 if (!buckets) {
341 kfree(ret);
342 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 }
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000344 ret->hash_buckets = buckets;
David S. Millercd089332011-07-11 01:28:12 -0700345 ret->hash_shift = shift;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000346 get_random_bytes(&ret->hash_rnd, sizeof(ret->hash_rnd));
David S. Millerf610b742011-07-11 01:37:28 -0700347 ret->hash_rnd |= 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 return ret;
349}
350
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000351static void neigh_hash_free_rcu(struct rcu_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000353 struct neigh_hash_table *nht = container_of(head,
354 struct neigh_hash_table,
355 rcu);
David S. Millercd089332011-07-11 01:28:12 -0700356 size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000357 struct neighbour __rcu **buckets = nht->hash_buckets;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
359 if (size <= PAGE_SIZE)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000360 kfree(buckets);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 else
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000362 free_pages((unsigned long)buckets, get_order(size));
363 kfree(nht);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364}
365
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000366static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
David S. Millercd089332011-07-11 01:28:12 -0700367 unsigned long new_shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000369 unsigned int i, hash;
370 struct neigh_hash_table *new_nht, *old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
372 NEIGH_CACHE_STAT_INC(tbl, hash_grows);
373
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000374 old_nht = rcu_dereference_protected(tbl->nht,
375 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700376 new_nht = neigh_hash_alloc(new_shift);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000377 if (!new_nht)
378 return old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
David S. Millercd089332011-07-11 01:28:12 -0700380 for (i = 0; i < (1 << old_nht->hash_shift); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 struct neighbour *n, *next;
382
Eric Dumazet767e97e2010-10-06 17:49:21 -0700383 for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
384 lockdep_is_held(&tbl->lock));
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000385 n != NULL;
386 n = next) {
387 hash = tbl->hash(n->primary_key, n->dev,
388 new_nht->hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
David S. Millercd089332011-07-11 01:28:12 -0700390 hash >>= (32 - new_nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700391 next = rcu_dereference_protected(n->next,
392 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
Eric Dumazet767e97e2010-10-06 17:49:21 -0700394 rcu_assign_pointer(n->next,
395 rcu_dereference_protected(
396 new_nht->hash_buckets[hash],
397 lockdep_is_held(&tbl->lock)));
398 rcu_assign_pointer(new_nht->hash_buckets[hash], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 }
400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000402 rcu_assign_pointer(tbl->nht, new_nht);
403 call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
404 return new_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405}
406
407struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
408 struct net_device *dev)
409{
410 struct neighbour *n;
411 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800412 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000413 struct neigh_hash_table *nht;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900414
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 NEIGH_CACHE_STAT_INC(tbl, lookups);
416
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000417 rcu_read_lock_bh();
418 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700419 hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700420
421 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
422 n != NULL;
423 n = rcu_dereference_bh(n->next)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700425 if (!atomic_inc_not_zero(&n->refcnt))
426 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 NEIGH_CACHE_STAT_INC(tbl, hits);
428 break;
429 }
430 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700431
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000432 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 return n;
434}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900435EXPORT_SYMBOL(neigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
Eric W. Biederman426b5302008-01-24 00:13:18 -0800437struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
438 const void *pkey)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
440 struct neighbour *n;
441 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800442 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000443 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444
445 NEIGH_CACHE_STAT_INC(tbl, lookups);
446
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000447 rcu_read_lock_bh();
448 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700449 hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700450
451 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
452 n != NULL;
453 n = rcu_dereference_bh(n->next)) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800454 if (!memcmp(n->primary_key, pkey, key_len) &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900455 net_eq(dev_net(n->dev), net)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700456 if (!atomic_inc_not_zero(&n->refcnt))
457 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 NEIGH_CACHE_STAT_INC(tbl, hits);
459 break;
460 }
461 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700462
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000463 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 return n;
465}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900466EXPORT_SYMBOL(neigh_lookup_nodev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
468struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
469 struct net_device *dev)
470{
471 u32 hash_val;
472 int key_len = tbl->key_len;
473 int error;
David Miller596b9b62011-07-25 00:01:25 +0000474 struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000475 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
477 if (!n) {
478 rc = ERR_PTR(-ENOBUFS);
479 goto out;
480 }
481
482 memcpy(n->primary_key, pkey, key_len);
483 n->dev = dev;
484 dev_hold(dev);
485
486 /* Protocol specific setup. */
487 if (tbl->constructor && (error = tbl->constructor(n)) < 0) {
488 rc = ERR_PTR(error);
489 goto out_neigh_release;
490 }
491
492 /* Device specific setup. */
493 if (n->parms->neigh_setup &&
494 (error = n->parms->neigh_setup(n)) < 0) {
495 rc = ERR_PTR(error);
496 goto out_neigh_release;
497 }
498
499 n->confirmed = jiffies - (n->parms->base_reachable_time << 1);
500
501 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000502 nht = rcu_dereference_protected(tbl->nht,
503 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
David S. Millercd089332011-07-11 01:28:12 -0700505 if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
506 nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
David S. Millercd089332011-07-11 01:28:12 -0700508 hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 if (n->parms->dead) {
511 rc = ERR_PTR(-EINVAL);
512 goto out_tbl_unlock;
513 }
514
Eric Dumazet767e97e2010-10-06 17:49:21 -0700515 for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
516 lockdep_is_held(&tbl->lock));
517 n1 != NULL;
518 n1 = rcu_dereference_protected(n1->next,
519 lockdep_is_held(&tbl->lock))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
521 neigh_hold(n1);
522 rc = n1;
523 goto out_tbl_unlock;
524 }
525 }
526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 n->dead = 0;
528 neigh_hold(n);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700529 rcu_assign_pointer(n->next,
530 rcu_dereference_protected(nht->hash_buckets[hash_val],
531 lockdep_is_held(&tbl->lock)));
532 rcu_assign_pointer(nht->hash_buckets[hash_val], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 write_unlock_bh(&tbl->lock);
534 NEIGH_PRINTK2("neigh %p is created.\n", n);
535 rc = n;
536out:
537 return rc;
538out_tbl_unlock:
539 write_unlock_bh(&tbl->lock);
540out_neigh_release:
541 neigh_release(n);
542 goto out;
543}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900544EXPORT_SYMBOL(neigh_create);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900546static u32 pneigh_hash(const void *pkey, int key_len)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700547{
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700548 u32 hash_val = *(u32 *)(pkey + key_len - 4);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700549 hash_val ^= (hash_val >> 16);
550 hash_val ^= hash_val >> 8;
551 hash_val ^= hash_val >> 4;
552 hash_val &= PNEIGH_HASHMASK;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900553 return hash_val;
554}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700555
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900556static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
557 struct net *net,
558 const void *pkey,
559 int key_len,
560 struct net_device *dev)
561{
562 while (n) {
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700563 if (!memcmp(n->key, pkey, key_len) &&
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900564 net_eq(pneigh_net(n), net) &&
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700565 (n->dev == dev || !n->dev))
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900566 return n;
567 n = n->next;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700568 }
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900569 return NULL;
570}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700571
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900572struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
573 struct net *net, const void *pkey, struct net_device *dev)
574{
575 int key_len = tbl->key_len;
576 u32 hash_val = pneigh_hash(pkey, key_len);
577
578 return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
579 net, pkey, key_len, dev);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700580}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900581EXPORT_SYMBOL_GPL(__pneigh_lookup);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700582
Eric W. Biederman426b5302008-01-24 00:13:18 -0800583struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
584 struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 struct net_device *dev, int creat)
586{
587 struct pneigh_entry *n;
588 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900589 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
591 read_lock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900592 n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
593 net, pkey, key_len, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 read_unlock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900595
596 if (n || !creat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 goto out;
598
Pavel Emelyanov4ae28942007-10-15 12:54:15 -0700599 ASSERT_RTNL();
600
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
602 if (!n)
603 goto out;
604
Eric Dumazete42ea982008-11-12 00:54:54 -0800605 write_pnet(&n->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 memcpy(n->key, pkey, key_len);
607 n->dev = dev;
608 if (dev)
609 dev_hold(dev);
610
611 if (tbl->pconstructor && tbl->pconstructor(n)) {
612 if (dev)
613 dev_put(dev);
Denis V. Lunevda12f732008-02-20 00:26:16 -0800614 release_net(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 kfree(n);
616 n = NULL;
617 goto out;
618 }
619
620 write_lock_bh(&tbl->lock);
621 n->next = tbl->phash_buckets[hash_val];
622 tbl->phash_buckets[hash_val] = n;
623 write_unlock_bh(&tbl->lock);
624out:
625 return n;
626}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900627EXPORT_SYMBOL(pneigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629
Eric W. Biederman426b5302008-01-24 00:13:18 -0800630int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 struct net_device *dev)
632{
633 struct pneigh_entry *n, **np;
634 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900635 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637 write_lock_bh(&tbl->lock);
638 for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
639 np = &n->next) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800640 if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900641 net_eq(pneigh_net(n), net)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 *np = n->next;
643 write_unlock_bh(&tbl->lock);
644 if (tbl->pdestructor)
645 tbl->pdestructor(n);
646 if (n->dev)
647 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900648 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 kfree(n);
650 return 0;
651 }
652 }
653 write_unlock_bh(&tbl->lock);
654 return -ENOENT;
655}
656
657static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
658{
659 struct pneigh_entry *n, **np;
660 u32 h;
661
662 for (h = 0; h <= PNEIGH_HASHMASK; h++) {
663 np = &tbl->phash_buckets[h];
664 while ((n = *np) != NULL) {
665 if (!dev || n->dev == dev) {
666 *np = n->next;
667 if (tbl->pdestructor)
668 tbl->pdestructor(n);
669 if (n->dev)
670 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900671 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 kfree(n);
673 continue;
674 }
675 np = &n->next;
676 }
677 }
678 return -ENOENT;
679}
680
Denis V. Lunev06f05112008-01-24 00:30:58 -0800681static void neigh_parms_destroy(struct neigh_parms *parms);
682
683static inline void neigh_parms_put(struct neigh_parms *parms)
684{
685 if (atomic_dec_and_test(&parms->refcnt))
686 neigh_parms_destroy(parms);
687}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
689/*
690 * neighbour must already be out of the table;
691 *
692 */
693void neigh_destroy(struct neighbour *neigh)
694{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
696
697 if (!neigh->dead) {
698 printk(KERN_WARNING
699 "Destroying alive neighbour %p\n", neigh);
700 dump_stack();
701 return;
702 }
703
704 if (neigh_del_timer(neigh))
705 printk(KERN_WARNING "Impossible event.\n");
706
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000708 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 dev_put(neigh->dev);
711 neigh_parms_put(neigh->parms);
712
713 NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh);
714
715 atomic_dec(&neigh->tbl->entries);
David Miller5b8b0062011-07-25 00:01:22 +0000716 kfree_rcu(neigh, rcu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900718EXPORT_SYMBOL(neigh_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720/* Neighbour state is suspicious;
721 disable fast path.
722
723 Called with write_locked neigh.
724 */
725static void neigh_suspect(struct neighbour *neigh)
726{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
728
729 neigh->output = neigh->ops->output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730}
731
732/* Neighbour state is OK;
733 enable fast path.
734
735 Called with write_locked neigh.
736 */
737static void neigh_connect(struct neighbour *neigh)
738{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 NEIGH_PRINTK2("neigh %p is connected.\n", neigh);
740
741 neigh->output = neigh->ops->connected_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742}
743
Eric Dumazete4c4e442009-07-30 03:15:07 +0000744static void neigh_periodic_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745{
Eric Dumazete4c4e442009-07-30 03:15:07 +0000746 struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700747 struct neighbour *n;
748 struct neighbour __rcu **np;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000749 unsigned int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000750 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
752 NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
753
Eric Dumazete4c4e442009-07-30 03:15:07 +0000754 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000755 nht = rcu_dereference_protected(tbl->nht,
756 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
758 /*
759 * periodically recompute ReachableTime from random function
760 */
761
Eric Dumazete4c4e442009-07-30 03:15:07 +0000762 if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 struct neigh_parms *p;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000764 tbl->last_rand = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 for (p = &tbl->parms; p; p = p->next)
766 p->reachable_time =
767 neigh_rand_reach_time(p->base_reachable_time);
768 }
769
David S. Millercd089332011-07-11 01:28:12 -0700770 for (i = 0 ; i < (1 << nht->hash_shift); i++) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000771 np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
Eric Dumazet767e97e2010-10-06 17:49:21 -0700773 while ((n = rcu_dereference_protected(*np,
774 lockdep_is_held(&tbl->lock))) != NULL) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000775 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Eric Dumazete4c4e442009-07-30 03:15:07 +0000777 write_lock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Eric Dumazete4c4e442009-07-30 03:15:07 +0000779 state = n->nud_state;
780 if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
781 write_unlock(&n->lock);
782 goto next_elt;
783 }
784
785 if (time_before(n->used, n->confirmed))
786 n->used = n->confirmed;
787
788 if (atomic_read(&n->refcnt) == 1 &&
789 (state == NUD_FAILED ||
790 time_after(jiffies, n->used + n->parms->gc_staletime))) {
791 *np = n->next;
792 n->dead = 1;
793 write_unlock(&n->lock);
794 neigh_cleanup_and_release(n);
795 continue;
796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 write_unlock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
799next_elt:
Eric Dumazete4c4e442009-07-30 03:15:07 +0000800 np = &n->next;
801 }
802 /*
803 * It's fine to release lock here, even if hash table
804 * grows while we are preempted.
805 */
806 write_unlock_bh(&tbl->lock);
807 cond_resched();
808 write_lock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900810 /* Cycle through all hash buckets every base_reachable_time/2 ticks.
811 * ARP entry timeouts range from 1/2 base_reachable_time to 3/2
812 * base_reachable_time.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 */
Eric Dumazete4c4e442009-07-30 03:15:07 +0000814 schedule_delayed_work(&tbl->gc_work,
815 tbl->parms.base_reachable_time >> 1);
816 write_unlock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817}
818
819static __inline__ int neigh_max_probes(struct neighbour *n)
820{
821 struct neigh_parms *p = n->parms;
Eric Dumazeta02cec22010-09-22 20:43:57 +0000822 return (n->nud_state & NUD_PROBE) ?
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 p->ucast_probes :
Eric Dumazeta02cec22010-09-22 20:43:57 +0000824 p->ucast_probes + p->app_probes + p->mcast_probes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825}
826
Timo Teras5ef12d92009-06-11 04:16:28 -0700827static void neigh_invalidate(struct neighbour *neigh)
Eric Dumazet0a141502010-03-09 19:40:54 +0000828 __releases(neigh->lock)
829 __acquires(neigh->lock)
Timo Teras5ef12d92009-06-11 04:16:28 -0700830{
831 struct sk_buff *skb;
832
833 NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
834 NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
835 neigh->updated = jiffies;
836
837 /* It is very thin place. report_unreachable is very complicated
838 routine. Particularly, it can hit the same neighbour entry!
839
840 So that, we try to be accurate and avoid dead loop. --ANK
841 */
842 while (neigh->nud_state == NUD_FAILED &&
843 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
844 write_unlock(&neigh->lock);
845 neigh->ops->error_report(neigh, skb);
846 write_lock(&neigh->lock);
847 }
848 skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000849 neigh->arp_queue_len_bytes = 0;
Timo Teras5ef12d92009-06-11 04:16:28 -0700850}
851
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000852static void neigh_probe(struct neighbour *neigh)
853 __releases(neigh->lock)
854{
855 struct sk_buff *skb = skb_peek(&neigh->arp_queue);
856 /* keep skb alive even if arp_queue overflows */
857 if (skb)
858 skb = skb_copy(skb, GFP_ATOMIC);
859 write_unlock(&neigh->lock);
860 neigh->ops->solicit(neigh, skb);
861 atomic_inc(&neigh->probes);
862 kfree_skb(skb);
863}
864
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865/* Called when a timer expires for a neighbour entry. */
866
867static void neigh_timer_handler(unsigned long arg)
868{
869 unsigned long now, next;
870 struct neighbour *neigh = (struct neighbour *)arg;
871 unsigned state;
872 int notify = 0;
873
874 write_lock(&neigh->lock);
875
876 state = neigh->nud_state;
877 now = jiffies;
878 next = now + HZ;
879
David S. Miller045f7b32011-11-01 17:45:55 -0400880 if (!(state & NUD_IN_TIMER))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
883 if (state & NUD_REACHABLE) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900884 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 neigh->confirmed + neigh->parms->reachable_time)) {
886 NEIGH_PRINTK2("neigh %p is still alive.\n", neigh);
887 next = neigh->confirmed + neigh->parms->reachable_time;
888 } else if (time_before_eq(now,
889 neigh->used + neigh->parms->delay_probe_time)) {
890 NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
891 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800892 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 neigh_suspect(neigh);
894 next = now + neigh->parms->delay_probe_time;
895 } else {
896 NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
897 neigh->nud_state = NUD_STALE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800898 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 neigh_suspect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700900 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 }
902 } else if (state & NUD_DELAY) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900903 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 neigh->confirmed + neigh->parms->delay_probe_time)) {
905 NEIGH_PRINTK2("neigh %p is now reachable.\n", neigh);
906 neigh->nud_state = NUD_REACHABLE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800907 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 neigh_connect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700909 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 next = neigh->confirmed + neigh->parms->reachable_time;
911 } else {
912 NEIGH_PRINTK2("neigh %p is probed.\n", neigh);
913 neigh->nud_state = NUD_PROBE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800914 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 atomic_set(&neigh->probes, 0);
916 next = now + neigh->parms->retrans_time;
917 }
918 } else {
919 /* NUD_PROBE|NUD_INCOMPLETE */
920 next = now + neigh->parms->retrans_time;
921 }
922
923 if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
924 atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 neigh->nud_state = NUD_FAILED;
926 notify = 1;
Timo Teras5ef12d92009-06-11 04:16:28 -0700927 neigh_invalidate(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 }
929
930 if (neigh->nud_state & NUD_IN_TIMER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 if (time_before(next, jiffies + HZ/2))
932 next = jiffies + HZ/2;
Herbert Xu6fb99742005-10-23 16:37:48 +1000933 if (!mod_timer(&neigh->timer, next))
934 neigh_hold(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 }
936 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000937 neigh_probe(neigh);
David S. Miller9ff56602008-02-17 18:39:54 -0800938 } else {
David S. Miller69cc64d2008-02-11 21:45:44 -0800939out:
David S. Miller9ff56602008-02-17 18:39:54 -0800940 write_unlock(&neigh->lock);
941 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
Thomas Grafd961db32007-08-08 23:12:56 -0700943 if (notify)
944 neigh_update_notify(neigh);
945
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 neigh_release(neigh);
947}
948
949int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
950{
951 int rc;
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000952 bool immediate_probe = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 write_lock_bh(&neigh->lock);
955
956 rc = 0;
957 if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
958 goto out_unlock_bh;
959
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
961 if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000962 unsigned long next, now = jiffies;
963
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 atomic_set(&neigh->probes, neigh->parms->ucast_probes);
965 neigh->nud_state = NUD_INCOMPLETE;
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000966 neigh->updated = now;
967 next = now + max(neigh->parms->retrans_time, HZ/2);
968 neigh_add_timer(neigh, next);
969 immediate_probe = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 } else {
971 neigh->nud_state = NUD_FAILED;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800972 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 write_unlock_bh(&neigh->lock);
974
Wei Yongjunf3fbbe02009-02-25 00:37:32 +0000975 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 return 1;
977 }
978 } else if (neigh->nud_state & NUD_STALE) {
979 NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800981 neigh->updated = jiffies;
David S. Miller667347f2005-09-27 12:07:44 -0700982 neigh_add_timer(neigh,
983 jiffies + neigh->parms->delay_probe_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 }
985
986 if (neigh->nud_state == NUD_INCOMPLETE) {
987 if (skb) {
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000988 while (neigh->arp_queue_len_bytes + skb->truesize >
989 neigh->parms->queue_len_bytes) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 struct sk_buff *buff;
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000991
David S. Millerf72051b2008-09-23 01:11:18 -0700992 buff = __skb_dequeue(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000993 if (!buff)
994 break;
995 neigh->arp_queue_len_bytes -= buff->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 kfree_skb(buff);
Neil Horman9a6d2762008-07-16 20:50:49 -0700997 NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 }
Eric Dumazeta4731132010-05-27 16:09:39 -0700999 skb_dst_force(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 __skb_queue_tail(&neigh->arp_queue, skb);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001001 neigh->arp_queue_len_bytes += skb->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 }
1003 rc = 1;
1004 }
1005out_unlock_bh:
Eric Dumazetcd28ca02011-08-09 08:15:58 +00001006 if (immediate_probe)
1007 neigh_probe(neigh);
1008 else
1009 write_unlock(&neigh->lock);
1010 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 return rc;
1012}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001013EXPORT_SYMBOL(__neigh_event_send);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
David S. Millerf6b72b622011-07-14 07:53:20 -07001015static void neigh_update_hhs(struct neighbour *neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016{
1017 struct hh_cache *hh;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001018 void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
Doug Kehn91a72a72010-07-14 18:02:16 -07001019 = NULL;
1020
1021 if (neigh->dev->header_ops)
1022 update = neigh->dev->header_ops->cache_update;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024 if (update) {
David S. Millerf6b72b622011-07-14 07:53:20 -07001025 hh = &neigh->hh;
1026 if (hh->hh_len) {
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001027 write_seqlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 update(hh, neigh->dev, neigh->ha);
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001029 write_sequnlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 }
1031 }
1032}
1033
1034
1035
1036/* Generic update routine.
1037 -- lladdr is new lladdr or NULL, if it is not supplied.
1038 -- new is new state.
1039 -- flags
1040 NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
1041 if it is different.
1042 NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001043 lladdr instead of overriding it
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 if it is different.
1045 It also allows to retain current state
1046 if lladdr is unchanged.
1047 NEIGH_UPDATE_F_ADMIN means that the change is administrative.
1048
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001049 NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 NTF_ROUTER flag.
1051 NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
1052 a router.
1053
1054 Caller MUST hold reference count on the entry.
1055 */
1056
1057int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
1058 u32 flags)
1059{
1060 u8 old;
1061 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 int notify = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 struct net_device *dev;
1064 int update_isrouter = 0;
1065
1066 write_lock_bh(&neigh->lock);
1067
1068 dev = neigh->dev;
1069 old = neigh->nud_state;
1070 err = -EPERM;
1071
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001072 if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 (old & (NUD_NOARP | NUD_PERMANENT)))
1074 goto out;
1075
1076 if (!(new & NUD_VALID)) {
1077 neigh_del_timer(neigh);
1078 if (old & NUD_CONNECTED)
1079 neigh_suspect(neigh);
1080 neigh->nud_state = new;
1081 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 notify = old & NUD_VALID;
Timo Teras5ef12d92009-06-11 04:16:28 -07001083 if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
1084 (new & NUD_FAILED)) {
1085 neigh_invalidate(neigh);
1086 notify = 1;
1087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 goto out;
1089 }
1090
1091 /* Compare new lladdr with cached one */
1092 if (!dev->addr_len) {
1093 /* First case: device needs no address. */
1094 lladdr = neigh->ha;
1095 } else if (lladdr) {
1096 /* The second case: if something is already cached
1097 and a new address is proposed:
1098 - compare new & old
1099 - if they are different, check override flag
1100 */
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001101 if ((old & NUD_VALID) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 !memcmp(lladdr, neigh->ha, dev->addr_len))
1103 lladdr = neigh->ha;
1104 } else {
1105 /* No address is supplied; if we know something,
1106 use it, otherwise discard the request.
1107 */
1108 err = -EINVAL;
1109 if (!(old & NUD_VALID))
1110 goto out;
1111 lladdr = neigh->ha;
1112 }
1113
1114 if (new & NUD_CONNECTED)
1115 neigh->confirmed = jiffies;
1116 neigh->updated = jiffies;
1117
1118 /* If entry was valid and address is not changed,
1119 do not change entry state, if new one is STALE.
1120 */
1121 err = 0;
1122 update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
1123 if (old & NUD_VALID) {
1124 if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
1125 update_isrouter = 0;
1126 if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
1127 (old & NUD_CONNECTED)) {
1128 lladdr = neigh->ha;
1129 new = NUD_STALE;
1130 } else
1131 goto out;
1132 } else {
1133 if (lladdr == neigh->ha && new == NUD_STALE &&
1134 ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||
1135 (old & NUD_CONNECTED))
1136 )
1137 new = old;
1138 }
1139 }
1140
1141 if (new != old) {
1142 neigh_del_timer(neigh);
Pavel Emelyanova43d8992007-12-20 15:49:05 -08001143 if (new & NUD_IN_TIMER)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001144 neigh_add_timer(neigh, (jiffies +
1145 ((new & NUD_REACHABLE) ?
David S. Miller667347f2005-09-27 12:07:44 -07001146 neigh->parms->reachable_time :
1147 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 neigh->nud_state = new;
1149 }
1150
1151 if (lladdr != neigh->ha) {
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001152 write_seqlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 memcpy(&neigh->ha, lladdr, dev->addr_len);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001154 write_sequnlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 neigh_update_hhs(neigh);
1156 if (!(new & NUD_CONNECTED))
1157 neigh->confirmed = jiffies -
1158 (neigh->parms->base_reachable_time << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 }
1161 if (new == old)
1162 goto out;
1163 if (new & NUD_CONNECTED)
1164 neigh_connect(neigh);
1165 else
1166 neigh_suspect(neigh);
1167 if (!(old & NUD_VALID)) {
1168 struct sk_buff *skb;
1169
1170 /* Again: avoid dead loop if something went wrong */
1171
1172 while (neigh->nud_state & NUD_VALID &&
1173 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
David S. Miller69cce1d2011-07-17 23:09:49 -07001174 struct dst_entry *dst = skb_dst(skb);
1175 struct neighbour *n2, *n1 = neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 write_unlock_bh(&neigh->lock);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001177
1178 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 /* On shaper/eql skb->dst->neighbour != neigh :( */
David S. Miller69cce1d2011-07-17 23:09:49 -07001180 if (dst && (n2 = dst_get_neighbour(dst)) != NULL)
1181 n1 = n2;
David S. Miller8f40b162011-07-17 13:34:11 -07001182 n1->output(n1, skb);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001183 rcu_read_unlock();
1184
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 write_lock_bh(&neigh->lock);
1186 }
1187 skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001188 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 }
1190out:
1191 if (update_isrouter) {
1192 neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?
1193 (neigh->flags | NTF_ROUTER) :
1194 (neigh->flags & ~NTF_ROUTER);
1195 }
1196 write_unlock_bh(&neigh->lock);
Tom Tucker8d717402006-07-30 20:43:36 -07001197
1198 if (notify)
Thomas Grafd961db32007-08-08 23:12:56 -07001199 neigh_update_notify(neigh);
1200
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 return err;
1202}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001203EXPORT_SYMBOL(neigh_update);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
1205struct neighbour *neigh_event_ns(struct neigh_table *tbl,
1206 u8 *lladdr, void *saddr,
1207 struct net_device *dev)
1208{
1209 struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
1210 lladdr || !dev->addr_len);
1211 if (neigh)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001212 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 NEIGH_UPDATE_F_OVERRIDE);
1214 return neigh;
1215}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001216EXPORT_SYMBOL(neigh_event_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
Eric Dumazet34d101d2010-10-11 09:16:57 -07001218/* called with read_lock_bh(&n->lock); */
David S. Millerf6b72b622011-07-14 07:53:20 -07001219static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 struct net_device *dev = dst->dev;
David S. Millerf6b72b622011-07-14 07:53:20 -07001222 __be16 prot = dst->ops->protocol;
1223 struct hh_cache *hh = &n->hh;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001224
1225 write_lock_bh(&n->lock);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001226
David S. Millerf6b72b622011-07-14 07:53:20 -07001227 /* Only one thread can come in here and initialize the
1228 * hh_cache entry.
1229 */
David S. Millerb23b5452011-07-16 17:45:02 -07001230 if (!hh->hh_len)
1231 dev->header_ops->cache(n, hh, prot);
David S. Millerf6b72b622011-07-14 07:53:20 -07001232
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001233 write_unlock_bh(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234}
1235
1236/* This function can be used in contexts, where only old dev_queue_xmit
Eric Dumazet767e97e2010-10-06 17:49:21 -07001237 * worked, f.e. if you want to override normal output path (eql, shaper),
1238 * but resolution is not made yet.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 */
1240
David S. Miller8f40b162011-07-17 13:34:11 -07001241int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242{
1243 struct net_device *dev = skb->dev;
1244
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001245 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
Stephen Hemminger0c4e8582007-10-09 01:36:32 -07001247 if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
1248 skb->len) < 0 &&
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001249 dev->header_ops->rebuild(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 return 0;
1251
1252 return dev_queue_xmit(skb);
1253}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001254EXPORT_SYMBOL(neigh_compat_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255
1256/* Slow and careful. */
1257
David S. Miller8f40b162011-07-17 13:34:11 -07001258int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259{
Eric Dumazetadf30902009-06-02 05:19:30 +00001260 struct dst_entry *dst = skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 int rc = 0;
1262
David S. Miller8f40b162011-07-17 13:34:11 -07001263 if (!dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 goto discard;
1265
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001266 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267
1268 if (!neigh_event_send(neigh, skb)) {
1269 int err;
1270 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001271 unsigned int seq;
Eric Dumazet34d101d2010-10-11 09:16:57 -07001272
David S. Millerf6b72b622011-07-14 07:53:20 -07001273 if (dev->header_ops->cache && !neigh->hh.hh_len)
1274 neigh_hh_init(neigh, dst);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001275
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001276 do {
1277 seq = read_seqbegin(&neigh->ha_lock);
1278 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1279 neigh->ha, NULL, skb->len);
1280 } while (read_seqretry(&neigh->ha_lock, seq));
Eric Dumazet34d101d2010-10-11 09:16:57 -07001281
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001283 rc = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 else
1285 goto out_kfree_skb;
1286 }
1287out:
1288 return rc;
1289discard:
1290 NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
David S. Miller8f40b162011-07-17 13:34:11 -07001291 dst, neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292out_kfree_skb:
1293 rc = -EINVAL;
1294 kfree_skb(skb);
1295 goto out;
1296}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001297EXPORT_SYMBOL(neigh_resolve_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
1299/* As fast as possible without hh cache */
1300
David S. Miller8f40b162011-07-17 13:34:11 -07001301int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001304 unsigned int seq;
David S. Miller8f40b162011-07-17 13:34:11 -07001305 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001307 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001309 do {
1310 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));
1314
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001316 err = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 else {
1318 err = -EINVAL;
1319 kfree_skb(skb);
1320 }
1321 return err;
1322}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001323EXPORT_SYMBOL(neigh_connected_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
David S. Miller8f40b162011-07-17 13:34:11 -07001325int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
1326{
1327 return dev_queue_xmit(skb);
1328}
1329EXPORT_SYMBOL(neigh_direct_output);
1330
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331static void neigh_proxy_process(unsigned long arg)
1332{
1333 struct neigh_table *tbl = (struct neigh_table *)arg;
1334 long sched_next = 0;
1335 unsigned long now = jiffies;
David S. Millerf72051b2008-09-23 01:11:18 -07001336 struct sk_buff *skb, *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
1338 spin_lock(&tbl->proxy_queue.lock);
1339
David S. Millerf72051b2008-09-23 01:11:18 -07001340 skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1341 long tdif = NEIGH_CB(skb)->sched_next - now;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 if (tdif <= 0) {
David S. Millerf72051b2008-09-23 01:11:18 -07001344 struct net_device *dev = skb->dev;
Eric Dumazet20e60742011-08-22 19:32:42 +00001345
David S. Millerf72051b2008-09-23 01:11:18 -07001346 __skb_unlink(skb, &tbl->proxy_queue);
Eric Dumazet20e60742011-08-22 19:32:42 +00001347 if (tbl->proxy_redo && netif_running(dev)) {
1348 rcu_read_lock();
David S. Millerf72051b2008-09-23 01:11:18 -07001349 tbl->proxy_redo(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001350 rcu_read_unlock();
1351 } else {
David S. Millerf72051b2008-09-23 01:11:18 -07001352 kfree_skb(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
1355 dev_put(dev);
1356 } else if (!sched_next || tdif < sched_next)
1357 sched_next = tdif;
1358 }
1359 del_timer(&tbl->proxy_timer);
1360 if (sched_next)
1361 mod_timer(&tbl->proxy_timer, jiffies + sched_next);
1362 spin_unlock(&tbl->proxy_queue.lock);
1363}
1364
1365void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
1366 struct sk_buff *skb)
1367{
1368 unsigned long now = jiffies;
1369 unsigned long sched_next = now + (net_random() % p->proxy_delay);
1370
1371 if (tbl->proxy_queue.qlen > p->proxy_qlen) {
1372 kfree_skb(skb);
1373 return;
1374 }
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001375
1376 NEIGH_CB(skb)->sched_next = sched_next;
1377 NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
1379 spin_lock(&tbl->proxy_queue.lock);
1380 if (del_timer(&tbl->proxy_timer)) {
1381 if (time_before(tbl->proxy_timer.expires, sched_next))
1382 sched_next = tbl->proxy_timer.expires;
1383 }
Eric Dumazetadf30902009-06-02 05:19:30 +00001384 skb_dst_drop(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 dev_hold(skb->dev);
1386 __skb_queue_tail(&tbl->proxy_queue, skb);
1387 mod_timer(&tbl->proxy_timer, sched_next);
1388 spin_unlock(&tbl->proxy_queue.lock);
1389}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001390EXPORT_SYMBOL(pneigh_enqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001392static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
Eric W. Biederman426b5302008-01-24 00:13:18 -08001393 struct net *net, int ifindex)
1394{
1395 struct neigh_parms *p;
1396
1397 for (p = &tbl->parms; p; p = p->next) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09001398 if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
Eric W. Biederman426b5302008-01-24 00:13:18 -08001399 (!p->dev && !ifindex))
1400 return p;
1401 }
1402
1403 return NULL;
1404}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
1406struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1407 struct neigh_table *tbl)
1408{
Eric W. Biederman426b5302008-01-24 00:13:18 -08001409 struct neigh_parms *p, *ref;
Stephen Hemminger00829822008-11-20 20:14:53 -08001410 struct net *net = dev_net(dev);
1411 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001413 ref = lookup_neigh_parms(tbl, net, 0);
Eric W. Biederman426b5302008-01-24 00:13:18 -08001414 if (!ref)
1415 return NULL;
1416
1417 p = kmemdup(ref, sizeof(*p), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 if (p) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 p->tbl = tbl;
1420 atomic_set(&p->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 p->reachable_time =
1422 neigh_rand_reach_time(p->base_reachable_time);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001423
Stephen Hemminger00829822008-11-20 20:14:53 -08001424 if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001425 kfree(p);
1426 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 }
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001428
1429 dev_hold(dev);
1430 p->dev = dev;
Eric Dumazete42ea982008-11-12 00:54:54 -08001431 write_pnet(&p->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 p->sysctl_table = NULL;
1433 write_lock_bh(&tbl->lock);
1434 p->next = tbl->parms.next;
1435 tbl->parms.next = p;
1436 write_unlock_bh(&tbl->lock);
1437 }
1438 return p;
1439}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001440EXPORT_SYMBOL(neigh_parms_alloc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441
1442static void neigh_rcu_free_parms(struct rcu_head *head)
1443{
1444 struct neigh_parms *parms =
1445 container_of(head, struct neigh_parms, rcu_head);
1446
1447 neigh_parms_put(parms);
1448}
1449
1450void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
1451{
1452 struct neigh_parms **p;
1453
1454 if (!parms || parms == &tbl->parms)
1455 return;
1456 write_lock_bh(&tbl->lock);
1457 for (p = &tbl->parms.next; *p; p = &(*p)->next) {
1458 if (*p == parms) {
1459 *p = parms->next;
1460 parms->dead = 1;
1461 write_unlock_bh(&tbl->lock);
David S. Millercecbb632008-01-20 16:39:03 -08001462 if (parms->dev)
1463 dev_put(parms->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
1465 return;
1466 }
1467 }
1468 write_unlock_bh(&tbl->lock);
1469 NEIGH_PRINTK1("neigh_parms_release: not found\n");
1470}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001471EXPORT_SYMBOL(neigh_parms_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
Denis V. Lunev06f05112008-01-24 00:30:58 -08001473static void neigh_parms_destroy(struct neigh_parms *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474{
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +09001475 release_net(neigh_parms_net(parms));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 kfree(parms);
1477}
1478
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001479static struct lock_class_key neigh_table_proxy_queue_class;
1480
Simon Kelleybd89efc2006-05-12 14:56:08 -07001481void neigh_table_init_no_netlink(struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482{
1483 unsigned long now = jiffies;
1484 unsigned long phsize;
1485
Eric Dumazete42ea982008-11-12 00:54:54 -08001486 write_pnet(&tbl->parms.net, &init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 atomic_set(&tbl->parms.refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 tbl->parms.reachable_time =
1489 neigh_rand_reach_time(tbl->parms.base_reachable_time);
1490
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 tbl->stats = alloc_percpu(struct neigh_statistics);
1492 if (!tbl->stats)
1493 panic("cannot create neighbour cache statistics");
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001494
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495#ifdef CONFIG_PROC_FS
Alexey Dobriyan9b739ba2008-11-11 16:47:44 -08001496 if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat,
1497 &neigh_stat_seq_fops, tbl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 panic("cannot create neighbour proc dir entry");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499#endif
1500
David S. Millercd089332011-07-11 01:28:12 -07001501 RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502
1503 phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
Andrew Morton77d04bd2006-04-07 14:52:59 -07001504 tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001506 if (!tbl->nht || !tbl->phash_buckets)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 panic("cannot allocate neighbour cache hashes");
1508
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 rwlock_init(&tbl->lock);
Eric Dumazete4c4e442009-07-30 03:15:07 +00001510 INIT_DELAYED_WORK_DEFERRABLE(&tbl->gc_work, neigh_periodic_work);
1511 schedule_delayed_work(&tbl->gc_work, tbl->parms.reachable_time);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001512 setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl);
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001513 skb_queue_head_init_class(&tbl->proxy_queue,
1514 &neigh_table_proxy_queue_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515
1516 tbl->last_flush = now;
1517 tbl->last_rand = now + tbl->parms.reachable_time * 20;
Simon Kelleybd89efc2006-05-12 14:56:08 -07001518}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001519EXPORT_SYMBOL(neigh_table_init_no_netlink);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001520
1521void neigh_table_init(struct neigh_table *tbl)
1522{
1523 struct neigh_table *tmp;
1524
1525 neigh_table_init_no_netlink(tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 write_lock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001527 for (tmp = neigh_tables; tmp; tmp = tmp->next) {
1528 if (tmp->family == tbl->family)
1529 break;
1530 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 tbl->next = neigh_tables;
1532 neigh_tables = tbl;
1533 write_unlock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001534
1535 if (unlikely(tmp)) {
1536 printk(KERN_ERR "NEIGH: Registering multiple tables for "
1537 "family %d\n", tbl->family);
1538 dump_stack();
1539 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001541EXPORT_SYMBOL(neigh_table_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
1543int neigh_table_clear(struct neigh_table *tbl)
1544{
1545 struct neigh_table **tp;
1546
1547 /* It is not clean... Fix it to unload IPv6 module safely */
Tejun Heoa5c30b32010-10-19 06:04:42 +00001548 cancel_delayed_work_sync(&tbl->gc_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 del_timer_sync(&tbl->proxy_timer);
1550 pneigh_queue_purge(&tbl->proxy_queue);
1551 neigh_ifdown(tbl, NULL);
1552 if (atomic_read(&tbl->entries))
1553 printk(KERN_CRIT "neighbour leakage\n");
1554 write_lock(&neigh_tbl_lock);
1555 for (tp = &neigh_tables; *tp; tp = &(*tp)->next) {
1556 if (*tp == tbl) {
1557 *tp = tbl->next;
1558 break;
1559 }
1560 }
1561 write_unlock(&neigh_tbl_lock);
1562
Eric Dumazet6193d2b2011-01-19 22:02:47 +00001563 call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
1564 neigh_hash_free_rcu);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001565 tbl->nht = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566
1567 kfree(tbl->phash_buckets);
1568 tbl->phash_buckets = NULL;
1569
Alexey Dobriyan3f192b52007-11-05 21:28:13 -08001570 remove_proc_entry(tbl->id, init_net.proc_net_stat);
1571
Kirill Korotaev3fcde742006-09-01 01:34:10 -07001572 free_percpu(tbl->stats);
1573 tbl->stats = NULL;
1574
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 return 0;
1576}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001577EXPORT_SYMBOL(neigh_table_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
Thomas Grafc8822a42007-03-22 11:50:06 -07001579static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001581 struct net *net = sock_net(skb->sk);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001582 struct ndmsg *ndm;
1583 struct nlattr *dst_attr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 struct neigh_table *tbl;
1585 struct net_device *dev = NULL;
Thomas Grafa14a49d2006-08-07 17:53:08 -07001586 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
Eric Dumazet110b2492010-10-04 04:27:36 +00001588 ASSERT_RTNL();
Thomas Grafa14a49d2006-08-07 17:53:08 -07001589 if (nlmsg_len(nlh) < sizeof(*ndm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 goto out;
1591
Thomas Grafa14a49d2006-08-07 17:53:08 -07001592 dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
1593 if (dst_attr == NULL)
1594 goto out;
1595
1596 ndm = nlmsg_data(nlh);
1597 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001598 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001599 if (dev == NULL) {
1600 err = -ENODEV;
1601 goto out;
1602 }
1603 }
1604
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 read_lock(&neigh_tbl_lock);
1606 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Grafa14a49d2006-08-07 17:53:08 -07001607 struct neighbour *neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608
1609 if (tbl->family != ndm->ndm_family)
1610 continue;
1611 read_unlock(&neigh_tbl_lock);
1612
Thomas Grafa14a49d2006-08-07 17:53:08 -07001613 if (nla_len(dst_attr) < tbl->key_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001614 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615
1616 if (ndm->ndm_flags & NTF_PROXY) {
Eric W. Biederman426b5302008-01-24 00:13:18 -08001617 err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
Eric Dumazet110b2492010-10-04 04:27:36 +00001618 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 }
1620
Thomas Grafa14a49d2006-08-07 17:53:08 -07001621 if (dev == NULL)
Eric Dumazet110b2492010-10-04 04:27:36 +00001622 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623
Thomas Grafa14a49d2006-08-07 17:53:08 -07001624 neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1625 if (neigh == NULL) {
1626 err = -ENOENT;
Eric Dumazet110b2492010-10-04 04:27:36 +00001627 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 }
Thomas Grafa14a49d2006-08-07 17:53:08 -07001629
1630 err = neigh_update(neigh, NULL, NUD_FAILED,
1631 NEIGH_UPDATE_F_OVERRIDE |
1632 NEIGH_UPDATE_F_ADMIN);
1633 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001634 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 }
1636 read_unlock(&neigh_tbl_lock);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001637 err = -EAFNOSUPPORT;
1638
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639out:
1640 return err;
1641}
1642
Thomas Grafc8822a42007-03-22 11:50:06 -07001643static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001645 struct net *net = sock_net(skb->sk);
Thomas Graf5208deb2006-08-07 17:55:40 -07001646 struct ndmsg *ndm;
1647 struct nlattr *tb[NDA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 struct neigh_table *tbl;
1649 struct net_device *dev = NULL;
Thomas Graf5208deb2006-08-07 17:55:40 -07001650 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651
Eric Dumazet110b2492010-10-04 04:27:36 +00001652 ASSERT_RTNL();
Thomas Graf5208deb2006-08-07 17:55:40 -07001653 err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
1654 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 goto out;
1656
Thomas Graf5208deb2006-08-07 17:55:40 -07001657 err = -EINVAL;
1658 if (tb[NDA_DST] == NULL)
1659 goto out;
1660
1661 ndm = nlmsg_data(nlh);
1662 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001663 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Graf5208deb2006-08-07 17:55:40 -07001664 if (dev == NULL) {
1665 err = -ENODEV;
1666 goto out;
1667 }
1668
1669 if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001670 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001671 }
1672
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 read_lock(&neigh_tbl_lock);
1674 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Graf5208deb2006-08-07 17:55:40 -07001675 int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
1676 struct neighbour *neigh;
1677 void *dst, *lladdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
1679 if (tbl->family != ndm->ndm_family)
1680 continue;
1681 read_unlock(&neigh_tbl_lock);
1682
Thomas Graf5208deb2006-08-07 17:55:40 -07001683 if (nla_len(tb[NDA_DST]) < tbl->key_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001684 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001685 dst = nla_data(tb[NDA_DST]);
1686 lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
1688 if (ndm->ndm_flags & NTF_PROXY) {
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001689 struct pneigh_entry *pn;
1690
1691 err = -ENOBUFS;
Eric W. Biederman426b5302008-01-24 00:13:18 -08001692 pn = pneigh_lookup(tbl, net, dst, dev, 1);
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001693 if (pn) {
1694 pn->flags = ndm->ndm_flags;
1695 err = 0;
1696 }
Eric Dumazet110b2492010-10-04 04:27:36 +00001697 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 }
1699
Thomas Graf5208deb2006-08-07 17:55:40 -07001700 if (dev == NULL)
Eric Dumazet110b2492010-10-04 04:27:36 +00001701 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001702
1703 neigh = neigh_lookup(tbl, dst, dev);
1704 if (neigh == NULL) {
1705 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
1706 err = -ENOENT;
Eric Dumazet110b2492010-10-04 04:27:36 +00001707 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001708 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001709
Thomas Graf5208deb2006-08-07 17:55:40 -07001710 neigh = __neigh_lookup_errno(tbl, dst, dev);
1711 if (IS_ERR(neigh)) {
1712 err = PTR_ERR(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001713 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001714 }
1715 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 if (nlh->nlmsg_flags & NLM_F_EXCL) {
1717 err = -EEXIST;
Thomas Graf5208deb2006-08-07 17:55:40 -07001718 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001719 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 }
Thomas Graf5208deb2006-08-07 17:55:40 -07001721
1722 if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
1723 flags &= ~NEIGH_UPDATE_F_OVERRIDE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 }
1725
Eric Biederman0c5c2d32009-03-04 00:03:08 -08001726 if (ndm->ndm_flags & NTF_USE) {
1727 neigh_event_send(neigh, NULL);
1728 err = 0;
1729 } else
1730 err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
Thomas Graf5208deb2006-08-07 17:55:40 -07001731 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001732 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 }
1734
1735 read_unlock(&neigh_tbl_lock);
Thomas Graf5208deb2006-08-07 17:55:40 -07001736 err = -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737out:
1738 return err;
1739}
1740
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001741static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1742{
Thomas Grafca860fb2006-08-07 18:00:18 -07001743 struct nlattr *nest;
1744
1745 nest = nla_nest_start(skb, NDTA_PARMS);
1746 if (nest == NULL)
1747 return -ENOBUFS;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001748
1749 if (parms->dev)
Thomas Grafca860fb2006-08-07 18:00:18 -07001750 NLA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001751
Thomas Grafca860fb2006-08-07 18:00:18 -07001752 NLA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt));
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001753 NLA_PUT_U32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes);
1754 /* approximative value for deprecated QUEUE_LEN (in packets) */
1755 NLA_PUT_U32(skb, NDTPA_QUEUE_LEN,
1756 DIV_ROUND_UP(parms->queue_len_bytes,
1757 SKB_TRUESIZE(ETH_FRAME_LEN)));
Thomas Grafca860fb2006-08-07 18:00:18 -07001758 NLA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen);
1759 NLA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes);
1760 NLA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes);
1761 NLA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes);
1762 NLA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time);
1763 NLA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001764 parms->base_reachable_time);
Thomas Grafca860fb2006-08-07 18:00:18 -07001765 NLA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime);
1766 NLA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time);
1767 NLA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time);
1768 NLA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay);
1769 NLA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay);
1770 NLA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001771
Thomas Grafca860fb2006-08-07 18:00:18 -07001772 return nla_nest_end(skb, nest);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001773
Thomas Grafca860fb2006-08-07 18:00:18 -07001774nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07001775 nla_nest_cancel(skb, nest);
1776 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001777}
1778
Thomas Grafca860fb2006-08-07 18:00:18 -07001779static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
1780 u32 pid, u32 seq, int type, int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001781{
1782 struct nlmsghdr *nlh;
1783 struct ndtmsg *ndtmsg;
1784
Thomas Grafca860fb2006-08-07 18:00:18 -07001785 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1786 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001787 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001788
Thomas Grafca860fb2006-08-07 18:00:18 -07001789 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001790
1791 read_lock_bh(&tbl->lock);
1792 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001793 ndtmsg->ndtm_pad1 = 0;
1794 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001795
Thomas Grafca860fb2006-08-07 18:00:18 -07001796 NLA_PUT_STRING(skb, NDTA_NAME, tbl->id);
1797 NLA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval);
1798 NLA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1);
1799 NLA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2);
1800 NLA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001801
1802 {
1803 unsigned long now = jiffies;
1804 unsigned int flush_delta = now - tbl->last_flush;
1805 unsigned int rand_delta = now - tbl->last_rand;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001806 struct neigh_hash_table *nht;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001807 struct ndt_config ndc = {
1808 .ndtc_key_len = tbl->key_len,
1809 .ndtc_entry_size = tbl->entry_size,
1810 .ndtc_entries = atomic_read(&tbl->entries),
1811 .ndtc_last_flush = jiffies_to_msecs(flush_delta),
1812 .ndtc_last_rand = jiffies_to_msecs(rand_delta),
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001813 .ndtc_proxy_qlen = tbl->proxy_queue.qlen,
1814 };
1815
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001816 rcu_read_lock_bh();
1817 nht = rcu_dereference_bh(tbl->nht);
1818 ndc.ndtc_hash_rnd = nht->hash_rnd;
David S. Millercd089332011-07-11 01:28:12 -07001819 ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001820 rcu_read_unlock_bh();
1821
Thomas Grafca860fb2006-08-07 18:00:18 -07001822 NLA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001823 }
1824
1825 {
1826 int cpu;
1827 struct ndt_stats ndst;
1828
1829 memset(&ndst, 0, sizeof(ndst));
1830
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001831 for_each_possible_cpu(cpu) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001832 struct neigh_statistics *st;
1833
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001834 st = per_cpu_ptr(tbl->stats, cpu);
1835 ndst.ndts_allocs += st->allocs;
1836 ndst.ndts_destroys += st->destroys;
1837 ndst.ndts_hash_grows += st->hash_grows;
1838 ndst.ndts_res_failed += st->res_failed;
1839 ndst.ndts_lookups += st->lookups;
1840 ndst.ndts_hits += st->hits;
1841 ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast;
1842 ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast;
1843 ndst.ndts_periodic_gc_runs += st->periodic_gc_runs;
1844 ndst.ndts_forced_gc_runs += st->forced_gc_runs;
1845 }
1846
Thomas Grafca860fb2006-08-07 18:00:18 -07001847 NLA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001848 }
1849
1850 BUG_ON(tbl->parms.dev);
1851 if (neightbl_fill_parms(skb, &tbl->parms) < 0)
Thomas Grafca860fb2006-08-07 18:00:18 -07001852 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001853
1854 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001855 return nlmsg_end(skb, nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001856
Thomas Grafca860fb2006-08-07 18:00:18 -07001857nla_put_failure:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001858 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001859 nlmsg_cancel(skb, nlh);
1860 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001861}
1862
Thomas Grafca860fb2006-08-07 18:00:18 -07001863static int neightbl_fill_param_info(struct sk_buff *skb,
1864 struct neigh_table *tbl,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001865 struct neigh_parms *parms,
Thomas Grafca860fb2006-08-07 18:00:18 -07001866 u32 pid, u32 seq, int type,
1867 unsigned int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001868{
1869 struct ndtmsg *ndtmsg;
1870 struct nlmsghdr *nlh;
1871
Thomas Grafca860fb2006-08-07 18:00:18 -07001872 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1873 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001874 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001875
Thomas Grafca860fb2006-08-07 18:00:18 -07001876 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001877
1878 read_lock_bh(&tbl->lock);
1879 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001880 ndtmsg->ndtm_pad1 = 0;
1881 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001882
Thomas Grafca860fb2006-08-07 18:00:18 -07001883 if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
1884 neightbl_fill_parms(skb, parms) < 0)
1885 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001886
1887 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001888 return nlmsg_end(skb, nlh);
1889errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001890 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001891 nlmsg_cancel(skb, nlh);
1892 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001893}
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001894
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001895static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001896 [NDTA_NAME] = { .type = NLA_STRING },
1897 [NDTA_THRESH1] = { .type = NLA_U32 },
1898 [NDTA_THRESH2] = { .type = NLA_U32 },
1899 [NDTA_THRESH3] = { .type = NLA_U32 },
1900 [NDTA_GC_INTERVAL] = { .type = NLA_U64 },
1901 [NDTA_PARMS] = { .type = NLA_NESTED },
1902};
1903
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001904static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001905 [NDTPA_IFINDEX] = { .type = NLA_U32 },
1906 [NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
1907 [NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
1908 [NDTPA_APP_PROBES] = { .type = NLA_U32 },
1909 [NDTPA_UCAST_PROBES] = { .type = NLA_U32 },
1910 [NDTPA_MCAST_PROBES] = { .type = NLA_U32 },
1911 [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 },
1912 [NDTPA_GC_STALETIME] = { .type = NLA_U64 },
1913 [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 },
1914 [NDTPA_RETRANS_TIME] = { .type = NLA_U64 },
1915 [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
1916 [NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
1917 [NDTPA_LOCKTIME] = { .type = NLA_U64 },
1918};
1919
Thomas Grafc8822a42007-03-22 11:50:06 -07001920static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001921{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001922 struct net *net = sock_net(skb->sk);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001923 struct neigh_table *tbl;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001924 struct ndtmsg *ndtmsg;
1925 struct nlattr *tb[NDTA_MAX+1];
1926 int err;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001927
Thomas Graf6b3f8672006-08-07 17:58:53 -07001928 err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
1929 nl_neightbl_policy);
1930 if (err < 0)
1931 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001932
Thomas Graf6b3f8672006-08-07 17:58:53 -07001933 if (tb[NDTA_NAME] == NULL) {
1934 err = -EINVAL;
1935 goto errout;
1936 }
1937
1938 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001939 read_lock(&neigh_tbl_lock);
1940 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
1941 if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
1942 continue;
1943
Thomas Graf6b3f8672006-08-07 17:58:53 -07001944 if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001945 break;
1946 }
1947
1948 if (tbl == NULL) {
1949 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001950 goto errout_locked;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001951 }
1952
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001953 /*
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001954 * We acquire tbl->lock to be nice to the periodic timers and
1955 * make sure they always see a consistent set of values.
1956 */
1957 write_lock_bh(&tbl->lock);
1958
Thomas Graf6b3f8672006-08-07 17:58:53 -07001959 if (tb[NDTA_PARMS]) {
1960 struct nlattr *tbp[NDTPA_MAX+1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001961 struct neigh_parms *p;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001962 int i, ifindex = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001963
Thomas Graf6b3f8672006-08-07 17:58:53 -07001964 err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
1965 nl_ntbl_parm_policy);
1966 if (err < 0)
1967 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001968
Thomas Graf6b3f8672006-08-07 17:58:53 -07001969 if (tbp[NDTPA_IFINDEX])
1970 ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001971
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001972 p = lookup_neigh_parms(tbl, net, ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001973 if (p == NULL) {
1974 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001975 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001976 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001977
Thomas Graf6b3f8672006-08-07 17:58:53 -07001978 for (i = 1; i <= NDTPA_MAX; i++) {
1979 if (tbp[i] == NULL)
1980 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001981
Thomas Graf6b3f8672006-08-07 17:58:53 -07001982 switch (i) {
1983 case NDTPA_QUEUE_LEN:
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001984 p->queue_len_bytes = nla_get_u32(tbp[i]) *
1985 SKB_TRUESIZE(ETH_FRAME_LEN);
1986 break;
1987 case NDTPA_QUEUE_LENBYTES:
1988 p->queue_len_bytes = nla_get_u32(tbp[i]);
Thomas Graf6b3f8672006-08-07 17:58:53 -07001989 break;
1990 case NDTPA_PROXY_QLEN:
1991 p->proxy_qlen = nla_get_u32(tbp[i]);
1992 break;
1993 case NDTPA_APP_PROBES:
1994 p->app_probes = nla_get_u32(tbp[i]);
1995 break;
1996 case NDTPA_UCAST_PROBES:
1997 p->ucast_probes = nla_get_u32(tbp[i]);
1998 break;
1999 case NDTPA_MCAST_PROBES:
2000 p->mcast_probes = nla_get_u32(tbp[i]);
2001 break;
2002 case NDTPA_BASE_REACHABLE_TIME:
2003 p->base_reachable_time = nla_get_msecs(tbp[i]);
2004 break;
2005 case NDTPA_GC_STALETIME:
2006 p->gc_staletime = nla_get_msecs(tbp[i]);
2007 break;
2008 case NDTPA_DELAY_PROBE_TIME:
2009 p->delay_probe_time = nla_get_msecs(tbp[i]);
2010 break;
2011 case NDTPA_RETRANS_TIME:
2012 p->retrans_time = nla_get_msecs(tbp[i]);
2013 break;
2014 case NDTPA_ANYCAST_DELAY:
2015 p->anycast_delay = nla_get_msecs(tbp[i]);
2016 break;
2017 case NDTPA_PROXY_DELAY:
2018 p->proxy_delay = nla_get_msecs(tbp[i]);
2019 break;
2020 case NDTPA_LOCKTIME:
2021 p->locktime = nla_get_msecs(tbp[i]);
2022 break;
2023 }
2024 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002025 }
2026
Thomas Graf6b3f8672006-08-07 17:58:53 -07002027 if (tb[NDTA_THRESH1])
2028 tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
2029
2030 if (tb[NDTA_THRESH2])
2031 tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
2032
2033 if (tb[NDTA_THRESH3])
2034 tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
2035
2036 if (tb[NDTA_GC_INTERVAL])
2037 tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2038
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002039 err = 0;
2040
Thomas Graf6b3f8672006-08-07 17:58:53 -07002041errout_tbl_lock:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002042 write_unlock_bh(&tbl->lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002043errout_locked:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002044 read_unlock(&neigh_tbl_lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002045errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002046 return err;
2047}
2048
Thomas Grafc8822a42007-03-22 11:50:06 -07002049static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002050{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002051 struct net *net = sock_net(skb->sk);
Thomas Grafca860fb2006-08-07 18:00:18 -07002052 int family, tidx, nidx = 0;
2053 int tbl_skip = cb->args[0];
2054 int neigh_skip = cb->args[1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002055 struct neigh_table *tbl;
2056
Thomas Grafca860fb2006-08-07 18:00:18 -07002057 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002058
2059 read_lock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07002060 for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002061 struct neigh_parms *p;
2062
Thomas Grafca860fb2006-08-07 18:00:18 -07002063 if (tidx < tbl_skip || (family && tbl->family != family))
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002064 continue;
2065
Thomas Grafca860fb2006-08-07 18:00:18 -07002066 if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).pid,
2067 cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
2068 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002069 break;
2070
Eric W. Biederman426b5302008-01-24 00:13:18 -08002071 for (nidx = 0, p = tbl->parms.next; p; p = p->next) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002072 if (!net_eq(neigh_parms_net(p), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002073 continue;
2074
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002075 if (nidx < neigh_skip)
2076 goto next;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002077
Thomas Grafca860fb2006-08-07 18:00:18 -07002078 if (neightbl_fill_param_info(skb, tbl, p,
2079 NETLINK_CB(cb->skb).pid,
2080 cb->nlh->nlmsg_seq,
2081 RTM_NEWNEIGHTBL,
2082 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002083 goto out;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002084 next:
2085 nidx++;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002086 }
2087
Thomas Grafca860fb2006-08-07 18:00:18 -07002088 neigh_skip = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002089 }
2090out:
2091 read_unlock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07002092 cb->args[0] = tidx;
2093 cb->args[1] = nidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002094
2095 return skb->len;
2096}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
Thomas Graf8b8aec52006-08-07 17:56:37 -07002098static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
2099 u32 pid, u32 seq, int type, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100{
2101 unsigned long now = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 struct nda_cacheinfo ci;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002103 struct nlmsghdr *nlh;
2104 struct ndmsg *ndm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105
Thomas Graf8b8aec52006-08-07 17:56:37 -07002106 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2107 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002108 return -EMSGSIZE;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002109
2110 ndm = nlmsg_data(nlh);
2111 ndm->ndm_family = neigh->ops->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002112 ndm->ndm_pad1 = 0;
2113 ndm->ndm_pad2 = 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002114 ndm->ndm_flags = neigh->flags;
2115 ndm->ndm_type = neigh->type;
2116 ndm->ndm_ifindex = neigh->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117
Thomas Graf8b8aec52006-08-07 17:56:37 -07002118 NLA_PUT(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key);
2119
2120 read_lock_bh(&neigh->lock);
2121 ndm->ndm_state = neigh->nud_state;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00002122 if (neigh->nud_state & NUD_VALID) {
2123 char haddr[MAX_ADDR_LEN];
2124
2125 neigh_ha_snapshot(haddr, neigh, neigh->dev);
2126 if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
2127 read_unlock_bh(&neigh->lock);
2128 goto nla_put_failure;
2129 }
Thomas Graf8b8aec52006-08-07 17:56:37 -07002130 }
2131
Stephen Hemmingerb9f5f522008-06-03 16:03:15 -07002132 ci.ndm_used = jiffies_to_clock_t(now - neigh->used);
2133 ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2134 ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002135 ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1;
2136 read_unlock_bh(&neigh->lock);
2137
2138 NLA_PUT_U32(skb, NDA_PROBES, atomic_read(&neigh->probes));
2139 NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
2140
2141 return nlmsg_end(skb, nlh);
2142
2143nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002144 nlmsg_cancel(skb, nlh);
2145 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146}
2147
Thomas Grafd961db32007-08-08 23:12:56 -07002148static void neigh_update_notify(struct neighbour *neigh)
2149{
2150 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
2151 __neigh_notify(neigh, RTM_NEWNEIGH, 0);
2152}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153
2154static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2155 struct netlink_callback *cb)
2156{
Eric Dumazet767e97e2010-10-06 17:49:21 -07002157 struct net *net = sock_net(skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 struct neighbour *n;
2159 int rc, h, s_h = cb->args[1];
2160 int idx, s_idx = idx = cb->args[2];
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002161 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002163 rcu_read_lock_bh();
2164 nht = rcu_dereference_bh(tbl->nht);
2165
David S. Millercd089332011-07-11 01:28:12 -07002166 for (h = 0; h < (1 << nht->hash_shift); h++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 if (h < s_h)
2168 continue;
2169 if (h > s_h)
2170 s_idx = 0;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002171 for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2172 n != NULL;
2173 n = rcu_dereference_bh(n->next)) {
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002174 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002175 continue;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002176 if (idx < s_idx)
2177 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid,
2179 cb->nlh->nlmsg_seq,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07002180 RTM_NEWNEIGH,
2181 NLM_F_MULTI) <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 rc = -1;
2183 goto out;
2184 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002185next:
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002186 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 }
2189 rc = skb->len;
2190out:
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002191 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 cb->args[1] = h;
2193 cb->args[2] = idx;
2194 return rc;
2195}
2196
Thomas Grafc8822a42007-03-22 11:50:06 -07002197static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198{
2199 struct neigh_table *tbl;
2200 int t, family, s_t;
2201
2202 read_lock(&neigh_tbl_lock);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002203 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 s_t = cb->args[0];
2205
2206 for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) {
2207 if (t < s_t || (family && tbl->family != family))
2208 continue;
2209 if (t > s_t)
2210 memset(&cb->args[1], 0, sizeof(cb->args) -
2211 sizeof(cb->args[0]));
2212 if (neigh_dump_table(tbl, skb, cb) < 0)
2213 break;
2214 }
2215 read_unlock(&neigh_tbl_lock);
2216
2217 cb->args[0] = t;
2218 return skb->len;
2219}
2220
2221void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
2222{
2223 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002224 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002226 rcu_read_lock_bh();
2227 nht = rcu_dereference_bh(tbl->nht);
2228
Eric Dumazet767e97e2010-10-06 17:49:21 -07002229 read_lock(&tbl->lock); /* avoid resizes */
David S. Millercd089332011-07-11 01:28:12 -07002230 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 struct neighbour *n;
2232
Eric Dumazet767e97e2010-10-06 17:49:21 -07002233 for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
2234 n != NULL;
2235 n = rcu_dereference_bh(n->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 cb(n, cookie);
2237 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002238 read_unlock(&tbl->lock);
2239 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240}
2241EXPORT_SYMBOL(neigh_for_each);
2242
2243/* The tbl->lock must be held as a writer and BH disabled. */
2244void __neigh_for_each_release(struct neigh_table *tbl,
2245 int (*cb)(struct neighbour *))
2246{
2247 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002248 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002250 nht = rcu_dereference_protected(tbl->nht,
2251 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -07002252 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002253 struct neighbour *n;
2254 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002256 np = &nht->hash_buckets[chain];
Eric Dumazet767e97e2010-10-06 17:49:21 -07002257 while ((n = rcu_dereference_protected(*np,
2258 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 int release;
2260
2261 write_lock(&n->lock);
2262 release = cb(n);
2263 if (release) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002264 rcu_assign_pointer(*np,
2265 rcu_dereference_protected(n->next,
2266 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 n->dead = 1;
2268 } else
2269 np = &n->next;
2270 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -07002271 if (release)
2272 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 }
2274 }
2275}
2276EXPORT_SYMBOL(__neigh_for_each_release);
2277
2278#ifdef CONFIG_PROC_FS
2279
2280static struct neighbour *neigh_get_first(struct seq_file *seq)
2281{
2282 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002283 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002284 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 struct neighbour *n = NULL;
2286 int bucket = state->bucket;
2287
2288 state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
David S. Millercd089332011-07-11 01:28:12 -07002289 for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002290 n = rcu_dereference_bh(nht->hash_buckets[bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
2292 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002293 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002294 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 if (state->neigh_sub_iter) {
2296 loff_t fakep = 0;
2297 void *v;
2298
2299 v = state->neigh_sub_iter(state, n, &fakep);
2300 if (!v)
2301 goto next;
2302 }
2303 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2304 break;
2305 if (n->nud_state & ~NUD_NOARP)
2306 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002307next:
2308 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 }
2310
2311 if (n)
2312 break;
2313 }
2314 state->bucket = bucket;
2315
2316 return n;
2317}
2318
2319static struct neighbour *neigh_get_next(struct seq_file *seq,
2320 struct neighbour *n,
2321 loff_t *pos)
2322{
2323 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002324 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002325 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326
2327 if (state->neigh_sub_iter) {
2328 void *v = state->neigh_sub_iter(state, n, pos);
2329 if (v)
2330 return n;
2331 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002332 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333
2334 while (1) {
2335 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002336 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002337 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 if (state->neigh_sub_iter) {
2339 void *v = state->neigh_sub_iter(state, n, pos);
2340 if (v)
2341 return n;
2342 goto next;
2343 }
2344 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2345 break;
2346
2347 if (n->nud_state & ~NUD_NOARP)
2348 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002349next:
2350 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 }
2352
2353 if (n)
2354 break;
2355
David S. Millercd089332011-07-11 01:28:12 -07002356 if (++state->bucket >= (1 << nht->hash_shift))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 break;
2358
Eric Dumazet767e97e2010-10-06 17:49:21 -07002359 n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 }
2361
2362 if (n && pos)
2363 --(*pos);
2364 return n;
2365}
2366
2367static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
2368{
2369 struct neighbour *n = neigh_get_first(seq);
2370
2371 if (n) {
Chris Larson745e2032008-08-03 01:10:55 -07002372 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 while (*pos) {
2374 n = neigh_get_next(seq, n, pos);
2375 if (!n)
2376 break;
2377 }
2378 }
2379 return *pos ? NULL : n;
2380}
2381
2382static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
2383{
2384 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002385 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 struct neigh_table *tbl = state->tbl;
2387 struct pneigh_entry *pn = NULL;
2388 int bucket = state->bucket;
2389
2390 state->flags |= NEIGH_SEQ_IS_PNEIGH;
2391 for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
2392 pn = tbl->phash_buckets[bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002393 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002394 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 if (pn)
2396 break;
2397 }
2398 state->bucket = bucket;
2399
2400 return pn;
2401}
2402
2403static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
2404 struct pneigh_entry *pn,
2405 loff_t *pos)
2406{
2407 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002408 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 struct neigh_table *tbl = state->tbl;
2410
Jorge Boncompte [DTI2]df07a942011-11-25 13:24:49 -05002411 do {
2412 pn = pn->next;
2413 } while (pn && !net_eq(pneigh_net(pn), net));
2414
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 while (!pn) {
2416 if (++state->bucket > PNEIGH_HASHMASK)
2417 break;
2418 pn = tbl->phash_buckets[state->bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002419 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002420 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 if (pn)
2422 break;
2423 }
2424
2425 if (pn && pos)
2426 --(*pos);
2427
2428 return pn;
2429}
2430
2431static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
2432{
2433 struct pneigh_entry *pn = pneigh_get_first(seq);
2434
2435 if (pn) {
Chris Larson745e2032008-08-03 01:10:55 -07002436 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 while (*pos) {
2438 pn = pneigh_get_next(seq, pn, pos);
2439 if (!pn)
2440 break;
2441 }
2442 }
2443 return *pos ? NULL : pn;
2444}
2445
2446static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
2447{
2448 struct neigh_seq_state *state = seq->private;
2449 void *rc;
Chris Larson745e2032008-08-03 01:10:55 -07002450 loff_t idxpos = *pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
Chris Larson745e2032008-08-03 01:10:55 -07002452 rc = neigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
Chris Larson745e2032008-08-03 01:10:55 -07002454 rc = pneigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
2456 return rc;
2457}
2458
2459void *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 +00002460 __acquires(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461{
2462 struct neigh_seq_state *state = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463
2464 state->tbl = tbl;
2465 state->bucket = 0;
2466 state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
2467
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002468 rcu_read_lock_bh();
2469 state->nht = rcu_dereference_bh(tbl->nht);
Eric Dumazet767e97e2010-10-06 17:49:21 -07002470
Chris Larson745e2032008-08-03 01:10:55 -07002471 return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472}
2473EXPORT_SYMBOL(neigh_seq_start);
2474
2475void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2476{
2477 struct neigh_seq_state *state;
2478 void *rc;
2479
2480 if (v == SEQ_START_TOKEN) {
Chris Larsonbff69732008-08-03 01:02:41 -07002481 rc = neigh_get_first(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 goto out;
2483 }
2484
2485 state = seq->private;
2486 if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
2487 rc = neigh_get_next(seq, v, NULL);
2488 if (rc)
2489 goto out;
2490 if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
2491 rc = pneigh_get_first(seq);
2492 } else {
2493 BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
2494 rc = pneigh_get_next(seq, v, NULL);
2495 }
2496out:
2497 ++(*pos);
2498 return rc;
2499}
2500EXPORT_SYMBOL(neigh_seq_next);
2501
2502void neigh_seq_stop(struct seq_file *seq, void *v)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002503 __releases(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504{
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002505 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506}
2507EXPORT_SYMBOL(neigh_seq_stop);
2508
2509/* statistics via seq_file */
2510
2511static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
2512{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002513 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 int cpu;
2515
2516 if (*pos == 0)
2517 return SEQ_START_TOKEN;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002518
Rusty Russell0f23174a2008-12-29 12:23:42 +00002519 for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 if (!cpu_possible(cpu))
2521 continue;
2522 *pos = cpu+1;
2523 return per_cpu_ptr(tbl->stats, cpu);
2524 }
2525 return NULL;
2526}
2527
2528static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2529{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002530 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 int cpu;
2532
Rusty Russell0f23174a2008-12-29 12:23:42 +00002533 for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 if (!cpu_possible(cpu))
2535 continue;
2536 *pos = cpu+1;
2537 return per_cpu_ptr(tbl->stats, cpu);
2538 }
2539 return NULL;
2540}
2541
2542static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
2543{
2544
2545}
2546
2547static int neigh_stat_seq_show(struct seq_file *seq, void *v)
2548{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002549 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 struct neigh_statistics *st = v;
2551
2552 if (v == SEQ_START_TOKEN) {
Neil Horman9a6d2762008-07-16 20:50:49 -07002553 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 -07002554 return 0;
2555 }
2556
2557 seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
Neil Horman9a6d2762008-07-16 20:50:49 -07002558 "%08lx %08lx %08lx %08lx %08lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 atomic_read(&tbl->entries),
2560
2561 st->allocs,
2562 st->destroys,
2563 st->hash_grows,
2564
2565 st->lookups,
2566 st->hits,
2567
2568 st->res_failed,
2569
2570 st->rcv_probes_mcast,
2571 st->rcv_probes_ucast,
2572
2573 st->periodic_gc_runs,
Neil Horman9a6d2762008-07-16 20:50:49 -07002574 st->forced_gc_runs,
2575 st->unres_discards
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 );
2577
2578 return 0;
2579}
2580
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002581static const struct seq_operations neigh_stat_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 .start = neigh_stat_seq_start,
2583 .next = neigh_stat_seq_next,
2584 .stop = neigh_stat_seq_stop,
2585 .show = neigh_stat_seq_show,
2586};
2587
2588static int neigh_stat_seq_open(struct inode *inode, struct file *file)
2589{
2590 int ret = seq_open(file, &neigh_stat_seq_ops);
2591
2592 if (!ret) {
2593 struct seq_file *sf = file->private_data;
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002594 sf->private = PDE(inode)->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 }
2596 return ret;
2597};
2598
Arjan van de Ven9a321442007-02-12 00:55:35 -08002599static const struct file_operations neigh_stat_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 .owner = THIS_MODULE,
2601 .open = neigh_stat_seq_open,
2602 .read = seq_read,
2603 .llseek = seq_lseek,
2604 .release = seq_release,
2605};
2606
2607#endif /* CONFIG_PROC_FS */
2608
Thomas Graf339bf982006-11-10 14:10:15 -08002609static inline size_t neigh_nlmsg_size(void)
2610{
2611 return NLMSG_ALIGN(sizeof(struct ndmsg))
2612 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2613 + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2614 + nla_total_size(sizeof(struct nda_cacheinfo))
2615 + nla_total_size(4); /* NDA_PROBES */
2616}
2617
Thomas Grafb8673312006-08-15 00:33:14 -07002618static void __neigh_notify(struct neighbour *n, int type, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002620 struct net *net = dev_net(n->dev);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002621 struct sk_buff *skb;
Thomas Grafb8673312006-08-15 00:33:14 -07002622 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623
Thomas Graf339bf982006-11-10 14:10:15 -08002624 skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002625 if (skb == NULL)
Thomas Grafb8673312006-08-15 00:33:14 -07002626 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627
Thomas Grafb8673312006-08-15 00:33:14 -07002628 err = neigh_fill_info(skb, n, 0, 0, type, flags);
Patrick McHardy26932562007-01-31 23:16:40 -08002629 if (err < 0) {
2630 /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
2631 WARN_ON(err == -EMSGSIZE);
2632 kfree_skb(skb);
2633 goto errout;
2634 }
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002635 rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
2636 return;
Thomas Grafb8673312006-08-15 00:33:14 -07002637errout:
2638 if (err < 0)
Eric W. Biederman426b5302008-01-24 00:13:18 -08002639 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
Thomas Grafb8673312006-08-15 00:33:14 -07002640}
2641
Thomas Grafd961db32007-08-08 23:12:56 -07002642#ifdef CONFIG_ARPD
Thomas Grafb8673312006-08-15 00:33:14 -07002643void neigh_app_ns(struct neighbour *n)
2644{
2645 __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09002647EXPORT_SYMBOL(neigh_app_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648#endif /* CONFIG_ARPD */
2649
2650#ifdef CONFIG_SYSCTL
2651
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002652static int proc_unres_qlen(ctl_table *ctl, int write, void __user *buffer,
2653 size_t *lenp, loff_t *ppos)
2654{
2655 int size, ret;
2656 ctl_table tmp = *ctl;
2657
2658 tmp.data = &size;
2659 size = DIV_ROUND_UP(*(int *)ctl->data, SKB_TRUESIZE(ETH_FRAME_LEN));
2660 ret = proc_dointvec(&tmp, write, buffer, lenp, ppos);
2661 if (write && !ret)
2662 *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
2663 return ret;
2664}
2665
2666enum {
2667 NEIGH_VAR_MCAST_PROBE,
2668 NEIGH_VAR_UCAST_PROBE,
2669 NEIGH_VAR_APP_PROBE,
2670 NEIGH_VAR_RETRANS_TIME,
2671 NEIGH_VAR_BASE_REACHABLE_TIME,
2672 NEIGH_VAR_DELAY_PROBE_TIME,
2673 NEIGH_VAR_GC_STALETIME,
2674 NEIGH_VAR_QUEUE_LEN,
2675 NEIGH_VAR_QUEUE_LEN_BYTES,
2676 NEIGH_VAR_PROXY_QLEN,
2677 NEIGH_VAR_ANYCAST_DELAY,
2678 NEIGH_VAR_PROXY_DELAY,
2679 NEIGH_VAR_LOCKTIME,
2680 NEIGH_VAR_RETRANS_TIME_MS,
2681 NEIGH_VAR_BASE_REACHABLE_TIME_MS,
2682 NEIGH_VAR_GC_INTERVAL,
2683 NEIGH_VAR_GC_THRESH1,
2684 NEIGH_VAR_GC_THRESH2,
2685 NEIGH_VAR_GC_THRESH3,
2686 NEIGH_VAR_MAX
2687};
Eric W. Biederman54716e32010-02-14 03:27:03 +00002688
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689static struct neigh_sysctl_table {
2690 struct ctl_table_header *sysctl_header;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002691 struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002692 char *dev_name;
Brian Haleyab32ea52006-09-22 14:15:41 -07002693} neigh_sysctl_template __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 .neigh_vars = {
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002695 [NEIGH_VAR_MCAST_PROBE] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 .procname = "mcast_solicit",
2697 .maxlen = sizeof(int),
2698 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002699 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002701 [NEIGH_VAR_UCAST_PROBE] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 .procname = "ucast_solicit",
2703 .maxlen = sizeof(int),
2704 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002705 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002707 [NEIGH_VAR_APP_PROBE] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 .procname = "app_solicit",
2709 .maxlen = sizeof(int),
2710 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002711 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002713 [NEIGH_VAR_RETRANS_TIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 .procname = "retrans_time",
2715 .maxlen = sizeof(int),
2716 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002717 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002719 [NEIGH_VAR_BASE_REACHABLE_TIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 .procname = "base_reachable_time",
2721 .maxlen = sizeof(int),
2722 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002723 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002725 [NEIGH_VAR_DELAY_PROBE_TIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 .procname = "delay_first_probe_time",
2727 .maxlen = sizeof(int),
2728 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002729 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002731 [NEIGH_VAR_GC_STALETIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 .procname = "gc_stale_time",
2733 .maxlen = sizeof(int),
2734 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002735 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002737 [NEIGH_VAR_QUEUE_LEN] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 .procname = "unres_qlen",
2739 .maxlen = sizeof(int),
2740 .mode = 0644,
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002741 .proc_handler = proc_unres_qlen,
2742 },
2743 [NEIGH_VAR_QUEUE_LEN_BYTES] = {
2744 .procname = "unres_qlen_bytes",
2745 .maxlen = sizeof(int),
2746 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002747 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002749 [NEIGH_VAR_PROXY_QLEN] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 .procname = "proxy_qlen",
2751 .maxlen = sizeof(int),
2752 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002753 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002755 [NEIGH_VAR_ANYCAST_DELAY] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 .procname = "anycast_delay",
2757 .maxlen = sizeof(int),
2758 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002759 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002761 [NEIGH_VAR_PROXY_DELAY] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 .procname = "proxy_delay",
2763 .maxlen = sizeof(int),
2764 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002765 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002767 [NEIGH_VAR_LOCKTIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 .procname = "locktime",
2769 .maxlen = sizeof(int),
2770 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002771 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002773 [NEIGH_VAR_RETRANS_TIME_MS] = {
Eric W. Biedermand12af672007-10-18 03:05:25 -07002774 .procname = "retrans_time_ms",
2775 .maxlen = sizeof(int),
2776 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002777 .proc_handler = proc_dointvec_ms_jiffies,
Eric W. Biedermand12af672007-10-18 03:05:25 -07002778 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002779 [NEIGH_VAR_BASE_REACHABLE_TIME_MS] = {
Eric W. Biedermand12af672007-10-18 03:05:25 -07002780 .procname = "base_reachable_time_ms",
2781 .maxlen = sizeof(int),
2782 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002783 .proc_handler = proc_dointvec_ms_jiffies,
Eric W. Biedermand12af672007-10-18 03:05:25 -07002784 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002785 [NEIGH_VAR_GC_INTERVAL] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 .procname = "gc_interval",
2787 .maxlen = sizeof(int),
2788 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002789 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002791 [NEIGH_VAR_GC_THRESH1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 .procname = "gc_thresh1",
2793 .maxlen = sizeof(int),
2794 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002795 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002797 [NEIGH_VAR_GC_THRESH2] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 .procname = "gc_thresh2",
2799 .maxlen = sizeof(int),
2800 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002801 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002803 [NEIGH_VAR_GC_THRESH3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 .procname = "gc_thresh3",
2805 .maxlen = sizeof(int),
2806 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002807 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002809 {},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 },
2811};
2812
2813int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
Eric W. Biederman54716e32010-02-14 03:27:03 +00002814 char *p_name, proc_handler *handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815{
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002816 struct neigh_sysctl_table *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 const char *dev_name_source = NULL;
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002818
2819#define NEIGH_CTL_PATH_ROOT 0
2820#define NEIGH_CTL_PATH_PROTO 1
2821#define NEIGH_CTL_PATH_NEIGH 2
2822#define NEIGH_CTL_PATH_DEV 3
2823
2824 struct ctl_path neigh_path[] = {
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002825 { .procname = "net", },
2826 { .procname = "proto", },
2827 { .procname = "neigh", },
2828 { .procname = "default", },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002829 { },
2830 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002832 t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 if (!t)
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002834 goto err;
2835
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002836 t->neigh_vars[NEIGH_VAR_MCAST_PROBE].data = &p->mcast_probes;
2837 t->neigh_vars[NEIGH_VAR_UCAST_PROBE].data = &p->ucast_probes;
2838 t->neigh_vars[NEIGH_VAR_APP_PROBE].data = &p->app_probes;
2839 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].data = &p->retrans_time;
2840 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].data = &p->base_reachable_time;
2841 t->neigh_vars[NEIGH_VAR_DELAY_PROBE_TIME].data = &p->delay_probe_time;
2842 t->neigh_vars[NEIGH_VAR_GC_STALETIME].data = &p->gc_staletime;
2843 t->neigh_vars[NEIGH_VAR_QUEUE_LEN].data = &p->queue_len_bytes;
2844 t->neigh_vars[NEIGH_VAR_QUEUE_LEN_BYTES].data = &p->queue_len_bytes;
2845 t->neigh_vars[NEIGH_VAR_PROXY_QLEN].data = &p->proxy_qlen;
2846 t->neigh_vars[NEIGH_VAR_ANYCAST_DELAY].data = &p->anycast_delay;
2847 t->neigh_vars[NEIGH_VAR_PROXY_DELAY].data = &p->proxy_delay;
2848 t->neigh_vars[NEIGH_VAR_LOCKTIME].data = &p->locktime;
2849 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].data = &p->retrans_time;
2850 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].data = &p->base_reachable_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851
2852 if (dev) {
2853 dev_name_source = dev->name;
Eric W. Biedermand12af672007-10-18 03:05:25 -07002854 /* Terminate the table early */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002855 memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
2856 sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 } else {
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002858 dev_name_source = neigh_path[NEIGH_CTL_PATH_DEV].procname;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002859 t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = (int *)(p + 1);
2860 t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = (int *)(p + 1) + 1;
2861 t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = (int *)(p + 1) + 2;
2862 t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = (int *)(p + 1) + 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 }
2864
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002866 if (handler) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 /* RetransTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002868 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
2869 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 /* ReachableTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002871 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
2872 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 /* RetransTime (in milliseconds)*/
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002874 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
2875 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 /* ReachableTime (in milliseconds) */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002877 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
2878 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 }
2880
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002881 t->dev_name = kstrdup(dev_name_source, GFP_KERNEL);
2882 if (!t->dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002885 neigh_path[NEIGH_CTL_PATH_DEV].procname = t->dev_name;
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002886 neigh_path[NEIGH_CTL_PATH_PROTO].procname = p_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887
Denis V. Lunev4ab438f2008-02-28 20:48:01 -08002888 t->sysctl_header =
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +09002889 register_net_sysctl_table(neigh_parms_net(p), neigh_path, t->neigh_vars);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002890 if (!t->sysctl_header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 goto free_procname;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002892
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 p->sysctl_table = t;
2894 return 0;
2895
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002896free_procname:
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002897 kfree(t->dev_name);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002898free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 kfree(t);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002900err:
2901 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09002903EXPORT_SYMBOL(neigh_sysctl_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904
2905void neigh_sysctl_unregister(struct neigh_parms *p)
2906{
2907 if (p->sysctl_table) {
2908 struct neigh_sysctl_table *t = p->sysctl_table;
2909 p->sysctl_table = NULL;
2910 unregister_sysctl_table(t->sysctl_header);
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002911 kfree(t->dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 kfree(t);
2913 }
2914}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09002915EXPORT_SYMBOL(neigh_sysctl_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916
2917#endif /* CONFIG_SYSCTL */
2918
Thomas Grafc8822a42007-03-22 11:50:06 -07002919static int __init neigh_init(void)
2920{
Greg Rosec7ac8672011-06-10 01:27:09 +00002921 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, NULL);
2922 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, NULL);
2923 rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, NULL);
Thomas Grafc8822a42007-03-22 11:50:06 -07002924
Greg Rosec7ac8672011-06-10 01:27:09 +00002925 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
2926 NULL);
2927 rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, NULL);
Thomas Grafc8822a42007-03-22 11:50:06 -07002928
2929 return 0;
2930}
2931
2932subsys_initcall(neigh_init);
2933