blob: 62d47841c67da09f6c641158e049baa0b3c24e84 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/types.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/socket.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/netdevice.h>
23#include <linux/proc_fs.h>
24#ifdef CONFIG_SYSCTL
25#include <linux/sysctl.h>
26#endif
27#include <linux/times.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020028#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <net/neighbour.h>
30#include <net/dst.h>
31#include <net/sock.h>
Tom Tucker8d717402006-07-30 20:43:36 -070032#include <net/netevent.h>
Thomas Grafa14a49d2006-08-07 17:53:08 -070033#include <net/netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/rtnetlink.h>
35#include <linux/random.h>
Paulo Marques543537b2005-06-23 00:09:02 -070036#include <linux/string.h>
vignesh babuc3609d52007-08-24 22:27:55 -070037#include <linux/log2.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39#define NEIGH_DEBUG 1
40
41#define NEIGH_PRINTK(x...) printk(x)
42#define NEIGH_NOPRINTK(x...) do { ; } while(0)
43#define NEIGH_PRINTK0 NEIGH_PRINTK
44#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);
62void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
63
64static struct neigh_table *neigh_tables;
Amos Waterland45fc3b12005-09-24 16:53:16 -070065#ifdef CONFIG_PROC_FS
Arjan van de Ven9a321442007-02-12 00:55:35 -080066static const struct file_operations neigh_stat_seq_fops;
Amos Waterland45fc3b12005-09-24 16:53:16 -070067#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*
70 Neighbour hash table buckets are protected with rwlock tbl->lock.
71
72 - All the scans/updates to hash buckets MUST be made under this lock.
73 - NOTHING clever should be made under this lock: no callbacks
74 to protocol backends, no attempts to send something to network.
75 It will result in deadlocks, if backend/driver wants to use neighbour
76 cache.
77 - If the entry requires some non-trivial actions, increase
78 its reference count and release table lock.
79
80 Neighbour entries are protected:
81 - with reference count.
82 - with rwlock neigh->lock
83
84 Reference count prevents destruction.
85
86 neigh->lock mainly serializes ll address data and its validity state.
87 However, the same lock is used to protect another entry fields:
88 - timer
89 - resolution queue
90
91 Again, nothing clever shall be made under neigh->lock,
92 the most complicated procedure, which we allow is dev->hard_header.
93 It is supposed, that dev->hard_header is simplistic and does
94 not make callbacks to neighbour tables.
95
96 The last lock is neigh_tbl_lock. It is pure SMP lock, protecting
97 list of neighbour tables. This list is used only in process context,
98 */
99
100static DEFINE_RWLOCK(neigh_tbl_lock);
101
102static int neigh_blackhole(struct sk_buff *skb)
103{
104 kfree_skb(skb);
105 return -ENETDOWN;
106}
107
Thomas Graf4f494552007-08-08 23:12:36 -0700108static void neigh_cleanup_and_release(struct neighbour *neigh)
109{
110 if (neigh->parms->neigh_cleanup)
111 neigh->parms->neigh_cleanup(neigh);
112
Thomas Grafd961db32007-08-08 23:12:56 -0700113 __neigh_notify(neigh, RTM_DELNEIGH, 0);
Thomas Graf4f494552007-08-08 23:12:36 -0700114 neigh_release(neigh);
115}
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117/*
118 * It is random distribution in the interval (1/2)*base...(3/2)*base.
119 * It corresponds to default IPv6 settings and is not overridable,
120 * because it is really reasonable choice.
121 */
122
123unsigned long neigh_rand_reach_time(unsigned long base)
124{
125 return (base ? (net_random() % base) + (base >> 1) : 0);
126}
127
128
129static int neigh_forced_gc(struct neigh_table *tbl)
130{
131 int shrunk = 0;
132 int i;
133
134 NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
135
136 write_lock_bh(&tbl->lock);
137 for (i = 0; i <= tbl->hash_mask; i++) {
138 struct neighbour *n, **np;
139
140 np = &tbl->hash_buckets[i];
141 while ((n = *np) != NULL) {
142 /* Neighbour record may be discarded if:
143 * - nobody refers to it.
144 * - it is not permanent
145 */
146 write_lock(&n->lock);
147 if (atomic_read(&n->refcnt) == 1 &&
148 !(n->nud_state & NUD_PERMANENT)) {
149 *np = n->next;
150 n->dead = 1;
151 shrunk = 1;
152 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700153 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 continue;
155 }
156 write_unlock(&n->lock);
157 np = &n->next;
158 }
159 }
160
161 tbl->last_flush = jiffies;
162
163 write_unlock_bh(&tbl->lock);
164
165 return shrunk;
166}
167
Pavel Emelyanova43d8992007-12-20 15:49:05 -0800168static void neigh_add_timer(struct neighbour *n, unsigned long when)
169{
170 neigh_hold(n);
171 if (unlikely(mod_timer(&n->timer, when))) {
172 printk("NEIGH: BUG, double timer add, state is %x\n",
173 n->nud_state);
174 dump_stack();
175 }
176}
177
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178static int neigh_del_timer(struct neighbour *n)
179{
180 if ((n->nud_state & NUD_IN_TIMER) &&
181 del_timer(&n->timer)) {
182 neigh_release(n);
183 return 1;
184 }
185 return 0;
186}
187
188static void pneigh_queue_purge(struct sk_buff_head *list)
189{
190 struct sk_buff *skb;
191
192 while ((skb = skb_dequeue(list)) != NULL) {
193 dev_put(skb->dev);
194 kfree_skb(skb);
195 }
196}
197
Herbert Xu49636bb2005-10-23 17:18:00 +1000198static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199{
200 int i;
201
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 for (i = 0; i <= tbl->hash_mask; i++) {
203 struct neighbour *n, **np = &tbl->hash_buckets[i];
204
205 while ((n = *np) != NULL) {
206 if (dev && n->dev != dev) {
207 np = &n->next;
208 continue;
209 }
210 *np = n->next;
211 write_lock(&n->lock);
212 neigh_del_timer(n);
213 n->dead = 1;
214
215 if (atomic_read(&n->refcnt) != 1) {
216 /* The most unpleasant situation.
217 We must destroy neighbour entry,
218 but someone still uses it.
219
220 The destroy will be delayed until
221 the last user releases us, but
222 we must kill timers etc. and move
223 it to safe state.
224 */
225 skb_queue_purge(&n->arp_queue);
226 n->output = neigh_blackhole;
227 if (n->nud_state & NUD_VALID)
228 n->nud_state = NUD_NOARP;
229 else
230 n->nud_state = NUD_NONE;
231 NEIGH_PRINTK2("neigh %p is stray.\n", n);
232 }
233 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700234 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 }
236 }
Herbert Xu49636bb2005-10-23 17:18:00 +1000237}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Herbert Xu49636bb2005-10-23 17:18:00 +1000239void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
240{
241 write_lock_bh(&tbl->lock);
242 neigh_flush_dev(tbl, dev);
243 write_unlock_bh(&tbl->lock);
244}
245
246int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
247{
248 write_lock_bh(&tbl->lock);
249 neigh_flush_dev(tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 pneigh_ifdown(tbl, dev);
251 write_unlock_bh(&tbl->lock);
252
253 del_timer_sync(&tbl->proxy_timer);
254 pneigh_queue_purge(&tbl->proxy_queue);
255 return 0;
256}
257
258static struct neighbour *neigh_alloc(struct neigh_table *tbl)
259{
260 struct neighbour *n = NULL;
261 unsigned long now = jiffies;
262 int entries;
263
264 entries = atomic_inc_return(&tbl->entries) - 1;
265 if (entries >= tbl->gc_thresh3 ||
266 (entries >= tbl->gc_thresh2 &&
267 time_after(now, tbl->last_flush + 5 * HZ))) {
268 if (!neigh_forced_gc(tbl) &&
269 entries >= tbl->gc_thresh3)
270 goto out_entries;
271 }
272
Robert P. J. Dayc3762222007-02-10 01:45:03 -0800273 n = kmem_cache_zalloc(tbl->kmem_cachep, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 if (!n)
275 goto out_entries;
276
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 skb_queue_head_init(&n->arp_queue);
278 rwlock_init(&n->lock);
279 n->updated = n->used = now;
280 n->nud_state = NUD_NONE;
281 n->output = neigh_blackhole;
282 n->parms = neigh_parms_clone(&tbl->parms);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800283 setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
285 NEIGH_CACHE_STAT_INC(tbl, allocs);
286 n->tbl = tbl;
287 atomic_set(&n->refcnt, 1);
288 n->dead = 1;
289out:
290 return n;
291
292out_entries:
293 atomic_dec(&tbl->entries);
294 goto out;
295}
296
297static struct neighbour **neigh_hash_alloc(unsigned int entries)
298{
299 unsigned long size = entries * sizeof(struct neighbour *);
300 struct neighbour **ret;
301
302 if (size <= PAGE_SIZE) {
Andrew Morton77d04bd2006-04-07 14:52:59 -0700303 ret = kzalloc(size, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 } else {
305 ret = (struct neighbour **)
Andrew Morton77d04bd2006-04-07 14:52:59 -0700306 __get_free_pages(GFP_ATOMIC|__GFP_ZERO, get_order(size));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 return ret;
309}
310
311static void neigh_hash_free(struct neighbour **hash, unsigned int entries)
312{
313 unsigned long size = entries * sizeof(struct neighbour *);
314
315 if (size <= PAGE_SIZE)
316 kfree(hash);
317 else
318 free_pages((unsigned long)hash, get_order(size));
319}
320
321static void neigh_hash_grow(struct neigh_table *tbl, unsigned long new_entries)
322{
323 struct neighbour **new_hash, **old_hash;
324 unsigned int i, new_hash_mask, old_entries;
325
326 NEIGH_CACHE_STAT_INC(tbl, hash_grows);
327
vignesh babuc3609d52007-08-24 22:27:55 -0700328 BUG_ON(!is_power_of_2(new_entries));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 new_hash = neigh_hash_alloc(new_entries);
330 if (!new_hash)
331 return;
332
333 old_entries = tbl->hash_mask + 1;
334 new_hash_mask = new_entries - 1;
335 old_hash = tbl->hash_buckets;
336
337 get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd));
338 for (i = 0; i < old_entries; i++) {
339 struct neighbour *n, *next;
340
341 for (n = old_hash[i]; n; n = next) {
342 unsigned int hash_val = tbl->hash(n->primary_key, n->dev);
343
344 hash_val &= new_hash_mask;
345 next = n->next;
346
347 n->next = new_hash[hash_val];
348 new_hash[hash_val] = n;
349 }
350 }
351 tbl->hash_buckets = new_hash;
352 tbl->hash_mask = new_hash_mask;
353
354 neigh_hash_free(old_hash, old_entries);
355}
356
357struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
358 struct net_device *dev)
359{
360 struct neighbour *n;
361 int key_len = tbl->key_len;
Julian Anastasovc5e29462006-10-03 15:49:46 -0700362 u32 hash_val = tbl->hash(pkey, dev);
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900363
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 NEIGH_CACHE_STAT_INC(tbl, lookups);
365
366 read_lock_bh(&tbl->lock);
Julian Anastasovc5e29462006-10-03 15:49:46 -0700367 for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
369 neigh_hold(n);
370 NEIGH_CACHE_STAT_INC(tbl, hits);
371 break;
372 }
373 }
374 read_unlock_bh(&tbl->lock);
375 return n;
376}
377
Eric W. Biederman426b5302008-01-24 00:13:18 -0800378struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
379 const void *pkey)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
381 struct neighbour *n;
382 int key_len = tbl->key_len;
Julian Anastasovc5e29462006-10-03 15:49:46 -0700383 u32 hash_val = tbl->hash(pkey, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
385 NEIGH_CACHE_STAT_INC(tbl, lookups);
386
387 read_lock_bh(&tbl->lock);
Julian Anastasovc5e29462006-10-03 15:49:46 -0700388 for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800389 if (!memcmp(n->primary_key, pkey, key_len) &&
390 (net == n->dev->nd_net)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 neigh_hold(n);
392 NEIGH_CACHE_STAT_INC(tbl, hits);
393 break;
394 }
395 }
396 read_unlock_bh(&tbl->lock);
397 return n;
398}
399
400struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
401 struct net_device *dev)
402{
403 u32 hash_val;
404 int key_len = tbl->key_len;
405 int error;
406 struct neighbour *n1, *rc, *n = neigh_alloc(tbl);
407
408 if (!n) {
409 rc = ERR_PTR(-ENOBUFS);
410 goto out;
411 }
412
413 memcpy(n->primary_key, pkey, key_len);
414 n->dev = dev;
415 dev_hold(dev);
416
417 /* Protocol specific setup. */
418 if (tbl->constructor && (error = tbl->constructor(n)) < 0) {
419 rc = ERR_PTR(error);
420 goto out_neigh_release;
421 }
422
423 /* Device specific setup. */
424 if (n->parms->neigh_setup &&
425 (error = n->parms->neigh_setup(n)) < 0) {
426 rc = ERR_PTR(error);
427 goto out_neigh_release;
428 }
429
430 n->confirmed = jiffies - (n->parms->base_reachable_time << 1);
431
432 write_lock_bh(&tbl->lock);
433
434 if (atomic_read(&tbl->entries) > (tbl->hash_mask + 1))
435 neigh_hash_grow(tbl, (tbl->hash_mask + 1) << 1);
436
437 hash_val = tbl->hash(pkey, dev) & tbl->hash_mask;
438
439 if (n->parms->dead) {
440 rc = ERR_PTR(-EINVAL);
441 goto out_tbl_unlock;
442 }
443
444 for (n1 = tbl->hash_buckets[hash_val]; n1; n1 = n1->next) {
445 if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
446 neigh_hold(n1);
447 rc = n1;
448 goto out_tbl_unlock;
449 }
450 }
451
452 n->next = tbl->hash_buckets[hash_val];
453 tbl->hash_buckets[hash_val] = n;
454 n->dead = 0;
455 neigh_hold(n);
456 write_unlock_bh(&tbl->lock);
457 NEIGH_PRINTK2("neigh %p is created.\n", n);
458 rc = n;
459out:
460 return rc;
461out_tbl_unlock:
462 write_unlock_bh(&tbl->lock);
463out_neigh_release:
464 neigh_release(n);
465 goto out;
466}
467
Eric W. Biederman426b5302008-01-24 00:13:18 -0800468struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
469 struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 struct net_device *dev, int creat)
471{
472 struct pneigh_entry *n;
473 int key_len = tbl->key_len;
474 u32 hash_val = *(u32 *)(pkey + key_len - 4);
475
476 hash_val ^= (hash_val >> 16);
477 hash_val ^= hash_val >> 8;
478 hash_val ^= hash_val >> 4;
479 hash_val &= PNEIGH_HASHMASK;
480
481 read_lock_bh(&tbl->lock);
482
483 for (n = tbl->phash_buckets[hash_val]; n; n = n->next) {
484 if (!memcmp(n->key, pkey, key_len) &&
Eric W. Biederman426b5302008-01-24 00:13:18 -0800485 (n->net == net) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 (n->dev == dev || !n->dev)) {
487 read_unlock_bh(&tbl->lock);
488 goto out;
489 }
490 }
491 read_unlock_bh(&tbl->lock);
492 n = NULL;
493 if (!creat)
494 goto out;
495
Pavel Emelyanov4ae28942007-10-15 12:54:15 -0700496 ASSERT_RTNL();
497
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
499 if (!n)
500 goto out;
501
Eric W. Biederman426b5302008-01-24 00:13:18 -0800502 n->net = hold_net(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 memcpy(n->key, pkey, key_len);
504 n->dev = dev;
505 if (dev)
506 dev_hold(dev);
507
508 if (tbl->pconstructor && tbl->pconstructor(n)) {
509 if (dev)
510 dev_put(dev);
511 kfree(n);
512 n = NULL;
513 goto out;
514 }
515
516 write_lock_bh(&tbl->lock);
517 n->next = tbl->phash_buckets[hash_val];
518 tbl->phash_buckets[hash_val] = n;
519 write_unlock_bh(&tbl->lock);
520out:
521 return n;
522}
523
524
Eric W. Biederman426b5302008-01-24 00:13:18 -0800525int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 struct net_device *dev)
527{
528 struct pneigh_entry *n, **np;
529 int key_len = tbl->key_len;
530 u32 hash_val = *(u32 *)(pkey + key_len - 4);
531
532 hash_val ^= (hash_val >> 16);
533 hash_val ^= hash_val >> 8;
534 hash_val ^= hash_val >> 4;
535 hash_val &= PNEIGH_HASHMASK;
536
537 write_lock_bh(&tbl->lock);
538 for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
539 np = &n->next) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800540 if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
541 (n->net == net)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 *np = n->next;
543 write_unlock_bh(&tbl->lock);
544 if (tbl->pdestructor)
545 tbl->pdestructor(n);
546 if (n->dev)
547 dev_put(n->dev);
Eric W. Biederman426b5302008-01-24 00:13:18 -0800548 release_net(n->net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 kfree(n);
550 return 0;
551 }
552 }
553 write_unlock_bh(&tbl->lock);
554 return -ENOENT;
555}
556
557static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
558{
559 struct pneigh_entry *n, **np;
560 u32 h;
561
562 for (h = 0; h <= PNEIGH_HASHMASK; h++) {
563 np = &tbl->phash_buckets[h];
564 while ((n = *np) != NULL) {
565 if (!dev || n->dev == dev) {
566 *np = n->next;
567 if (tbl->pdestructor)
568 tbl->pdestructor(n);
569 if (n->dev)
570 dev_put(n->dev);
Eric W. Biederman426b5302008-01-24 00:13:18 -0800571 release_net(n->net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 kfree(n);
573 continue;
574 }
575 np = &n->next;
576 }
577 }
578 return -ENOENT;
579}
580
581
582/*
583 * neighbour must already be out of the table;
584 *
585 */
586void neigh_destroy(struct neighbour *neigh)
587{
588 struct hh_cache *hh;
589
590 NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
591
592 if (!neigh->dead) {
593 printk(KERN_WARNING
594 "Destroying alive neighbour %p\n", neigh);
595 dump_stack();
596 return;
597 }
598
599 if (neigh_del_timer(neigh))
600 printk(KERN_WARNING "Impossible event.\n");
601
602 while ((hh = neigh->hh) != NULL) {
603 neigh->hh = hh->hh_next;
604 hh->hh_next = NULL;
Stephen Hemminger3644f0c2006-12-07 15:08:17 -0800605
606 write_seqlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 hh->hh_output = neigh_blackhole;
Stephen Hemminger3644f0c2006-12-07 15:08:17 -0800608 write_sequnlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 if (atomic_dec_and_test(&hh->hh_refcnt))
610 kfree(hh);
611 }
612
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 skb_queue_purge(&neigh->arp_queue);
614
615 dev_put(neigh->dev);
616 neigh_parms_put(neigh->parms);
617
618 NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh);
619
620 atomic_dec(&neigh->tbl->entries);
621 kmem_cache_free(neigh->tbl->kmem_cachep, neigh);
622}
623
624/* Neighbour state is suspicious;
625 disable fast path.
626
627 Called with write_locked neigh.
628 */
629static void neigh_suspect(struct neighbour *neigh)
630{
631 struct hh_cache *hh;
632
633 NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
634
635 neigh->output = neigh->ops->output;
636
637 for (hh = neigh->hh; hh; hh = hh->hh_next)
638 hh->hh_output = neigh->ops->output;
639}
640
641/* Neighbour state is OK;
642 enable fast path.
643
644 Called with write_locked neigh.
645 */
646static void neigh_connect(struct neighbour *neigh)
647{
648 struct hh_cache *hh;
649
650 NEIGH_PRINTK2("neigh %p is connected.\n", neigh);
651
652 neigh->output = neigh->ops->connected_output;
653
654 for (hh = neigh->hh; hh; hh = hh->hh_next)
655 hh->hh_output = neigh->ops->hh_output;
656}
657
658static void neigh_periodic_timer(unsigned long arg)
659{
660 struct neigh_table *tbl = (struct neigh_table *)arg;
661 struct neighbour *n, **np;
662 unsigned long expire, now = jiffies;
663
664 NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
665
666 write_lock(&tbl->lock);
667
668 /*
669 * periodically recompute ReachableTime from random function
670 */
671
672 if (time_after(now, tbl->last_rand + 300 * HZ)) {
673 struct neigh_parms *p;
674 tbl->last_rand = now;
675 for (p = &tbl->parms; p; p = p->next)
676 p->reachable_time =
677 neigh_rand_reach_time(p->base_reachable_time);
678 }
679
680 np = &tbl->hash_buckets[tbl->hash_chain_gc];
681 tbl->hash_chain_gc = ((tbl->hash_chain_gc + 1) & tbl->hash_mask);
682
683 while ((n = *np) != NULL) {
684 unsigned int state;
685
686 write_lock(&n->lock);
687
688 state = n->nud_state;
689 if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
690 write_unlock(&n->lock);
691 goto next_elt;
692 }
693
694 if (time_before(n->used, n->confirmed))
695 n->used = n->confirmed;
696
697 if (atomic_read(&n->refcnt) == 1 &&
698 (state == NUD_FAILED ||
699 time_after(now, n->used + n->parms->gc_staletime))) {
700 *np = n->next;
701 n->dead = 1;
702 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700703 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 continue;
705 }
706 write_unlock(&n->lock);
707
708next_elt:
709 np = &n->next;
710 }
711
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900712 /* Cycle through all hash buckets every base_reachable_time/2 ticks.
713 * ARP entry timeouts range from 1/2 base_reachable_time to 3/2
714 * base_reachable_time.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 */
716 expire = tbl->parms.base_reachable_time >> 1;
717 expire /= (tbl->hash_mask + 1);
718 if (!expire)
719 expire = 1;
720
Arjan van de Venf5a6e012007-02-05 17:59:51 -0800721 if (expire>HZ)
722 mod_timer(&tbl->gc_timer, round_jiffies(now + expire));
723 else
724 mod_timer(&tbl->gc_timer, now + expire);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 write_unlock(&tbl->lock);
727}
728
729static __inline__ int neigh_max_probes(struct neighbour *n)
730{
731 struct neigh_parms *p = n->parms;
732 return (n->nud_state & NUD_PROBE ?
733 p->ucast_probes :
734 p->ucast_probes + p->app_probes + p->mcast_probes);
735}
736
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737/* Called when a timer expires for a neighbour entry. */
738
739static void neigh_timer_handler(unsigned long arg)
740{
741 unsigned long now, next;
742 struct neighbour *neigh = (struct neighbour *)arg;
743 unsigned state;
744 int notify = 0;
745
746 write_lock(&neigh->lock);
747
748 state = neigh->nud_state;
749 now = jiffies;
750 next = now + HZ;
751
752 if (!(state & NUD_IN_TIMER)) {
753#ifndef CONFIG_SMP
754 printk(KERN_WARNING "neigh: timer & !nud_in_timer\n");
755#endif
756 goto out;
757 }
758
759 if (state & NUD_REACHABLE) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900760 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 neigh->confirmed + neigh->parms->reachable_time)) {
762 NEIGH_PRINTK2("neigh %p is still alive.\n", neigh);
763 next = neigh->confirmed + neigh->parms->reachable_time;
764 } else if (time_before_eq(now,
765 neigh->used + neigh->parms->delay_probe_time)) {
766 NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
767 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800768 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 neigh_suspect(neigh);
770 next = now + neigh->parms->delay_probe_time;
771 } else {
772 NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
773 neigh->nud_state = NUD_STALE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800774 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 neigh_suspect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700776 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 }
778 } else if (state & NUD_DELAY) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900779 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 neigh->confirmed + neigh->parms->delay_probe_time)) {
781 NEIGH_PRINTK2("neigh %p is now reachable.\n", neigh);
782 neigh->nud_state = NUD_REACHABLE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800783 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 neigh_connect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700785 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 next = neigh->confirmed + neigh->parms->reachable_time;
787 } else {
788 NEIGH_PRINTK2("neigh %p is probed.\n", neigh);
789 neigh->nud_state = NUD_PROBE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800790 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 atomic_set(&neigh->probes, 0);
792 next = now + neigh->parms->retrans_time;
793 }
794 } else {
795 /* NUD_PROBE|NUD_INCOMPLETE */
796 next = now + neigh->parms->retrans_time;
797 }
798
799 if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
800 atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
801 struct sk_buff *skb;
802
803 neigh->nud_state = NUD_FAILED;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800804 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 notify = 1;
806 NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
807 NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
808
809 /* It is very thin place. report_unreachable is very complicated
810 routine. Particularly, it can hit the same neighbour entry!
811
812 So that, we try to be accurate and avoid dead loop. --ANK
813 */
814 while (neigh->nud_state == NUD_FAILED &&
815 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
816 write_unlock(&neigh->lock);
817 neigh->ops->error_report(neigh, skb);
818 write_lock(&neigh->lock);
819 }
820 skb_queue_purge(&neigh->arp_queue);
821 }
822
823 if (neigh->nud_state & NUD_IN_TIMER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 if (time_before(next, jiffies + HZ/2))
825 next = jiffies + HZ/2;
Herbert Xu6fb99742005-10-23 16:37:48 +1000826 if (!mod_timer(&neigh->timer, next))
827 neigh_hold(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 }
829 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
830 struct sk_buff *skb = skb_peek(&neigh->arp_queue);
831 /* keep skb alive even if arp_queue overflows */
832 if (skb)
833 skb_get(skb);
834 write_unlock(&neigh->lock);
835 neigh->ops->solicit(neigh, skb);
836 atomic_inc(&neigh->probes);
837 if (skb)
838 kfree_skb(skb);
839 } else {
840out:
841 write_unlock(&neigh->lock);
842 }
843
Thomas Grafd961db32007-08-08 23:12:56 -0700844 if (notify)
845 neigh_update_notify(neigh);
846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 neigh_release(neigh);
848}
849
850int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
851{
852 int rc;
853 unsigned long now;
854
855 write_lock_bh(&neigh->lock);
856
857 rc = 0;
858 if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
859 goto out_unlock_bh;
860
861 now = jiffies;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900862
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
864 if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
865 atomic_set(&neigh->probes, neigh->parms->ucast_probes);
866 neigh->nud_state = NUD_INCOMPLETE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800867 neigh->updated = jiffies;
David S. Miller667347f2005-09-27 12:07:44 -0700868 neigh_add_timer(neigh, now + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 } else {
870 neigh->nud_state = NUD_FAILED;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800871 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 write_unlock_bh(&neigh->lock);
873
874 if (skb)
875 kfree_skb(skb);
876 return 1;
877 }
878 } else if (neigh->nud_state & NUD_STALE) {
879 NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800881 neigh->updated = jiffies;
David S. Miller667347f2005-09-27 12:07:44 -0700882 neigh_add_timer(neigh,
883 jiffies + neigh->parms->delay_probe_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 }
885
886 if (neigh->nud_state == NUD_INCOMPLETE) {
887 if (skb) {
888 if (skb_queue_len(&neigh->arp_queue) >=
889 neigh->parms->queue_len) {
890 struct sk_buff *buff;
891 buff = neigh->arp_queue.next;
892 __skb_unlink(buff, &neigh->arp_queue);
893 kfree_skb(buff);
894 }
895 __skb_queue_tail(&neigh->arp_queue, skb);
896 }
897 rc = 1;
898 }
899out_unlock_bh:
900 write_unlock_bh(&neigh->lock);
901 return rc;
902}
903
Stephen Hemmingere92b43a2006-08-17 18:17:37 -0700904static void neigh_update_hhs(struct neighbour *neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905{
906 struct hh_cache *hh;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700907 void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
908 = neigh->dev->header_ops->cache_update;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
910 if (update) {
911 for (hh = neigh->hh; hh; hh = hh->hh_next) {
Stephen Hemminger3644f0c2006-12-07 15:08:17 -0800912 write_seqlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 update(hh, neigh->dev, neigh->ha);
Stephen Hemminger3644f0c2006-12-07 15:08:17 -0800914 write_sequnlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 }
916 }
917}
918
919
920
921/* Generic update routine.
922 -- lladdr is new lladdr or NULL, if it is not supplied.
923 -- new is new state.
924 -- flags
925 NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
926 if it is different.
927 NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900928 lladdr instead of overriding it
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 if it is different.
930 It also allows to retain current state
931 if lladdr is unchanged.
932 NEIGH_UPDATE_F_ADMIN means that the change is administrative.
933
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900934 NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 NTF_ROUTER flag.
936 NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
937 a router.
938
939 Caller MUST hold reference count on the entry.
940 */
941
942int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
943 u32 flags)
944{
945 u8 old;
946 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 int notify = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 struct net_device *dev;
949 int update_isrouter = 0;
950
951 write_lock_bh(&neigh->lock);
952
953 dev = neigh->dev;
954 old = neigh->nud_state;
955 err = -EPERM;
956
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900957 if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 (old & (NUD_NOARP | NUD_PERMANENT)))
959 goto out;
960
961 if (!(new & NUD_VALID)) {
962 neigh_del_timer(neigh);
963 if (old & NUD_CONNECTED)
964 neigh_suspect(neigh);
965 neigh->nud_state = new;
966 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 notify = old & NUD_VALID;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 goto out;
969 }
970
971 /* Compare new lladdr with cached one */
972 if (!dev->addr_len) {
973 /* First case: device needs no address. */
974 lladdr = neigh->ha;
975 } else if (lladdr) {
976 /* The second case: if something is already cached
977 and a new address is proposed:
978 - compare new & old
979 - if they are different, check override flag
980 */
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900981 if ((old & NUD_VALID) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 !memcmp(lladdr, neigh->ha, dev->addr_len))
983 lladdr = neigh->ha;
984 } else {
985 /* No address is supplied; if we know something,
986 use it, otherwise discard the request.
987 */
988 err = -EINVAL;
989 if (!(old & NUD_VALID))
990 goto out;
991 lladdr = neigh->ha;
992 }
993
994 if (new & NUD_CONNECTED)
995 neigh->confirmed = jiffies;
996 neigh->updated = jiffies;
997
998 /* If entry was valid and address is not changed,
999 do not change entry state, if new one is STALE.
1000 */
1001 err = 0;
1002 update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
1003 if (old & NUD_VALID) {
1004 if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
1005 update_isrouter = 0;
1006 if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
1007 (old & NUD_CONNECTED)) {
1008 lladdr = neigh->ha;
1009 new = NUD_STALE;
1010 } else
1011 goto out;
1012 } else {
1013 if (lladdr == neigh->ha && new == NUD_STALE &&
1014 ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||
1015 (old & NUD_CONNECTED))
1016 )
1017 new = old;
1018 }
1019 }
1020
1021 if (new != old) {
1022 neigh_del_timer(neigh);
Pavel Emelyanova43d8992007-12-20 15:49:05 -08001023 if (new & NUD_IN_TIMER)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001024 neigh_add_timer(neigh, (jiffies +
1025 ((new & NUD_REACHABLE) ?
David S. Miller667347f2005-09-27 12:07:44 -07001026 neigh->parms->reachable_time :
1027 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 neigh->nud_state = new;
1029 }
1030
1031 if (lladdr != neigh->ha) {
1032 memcpy(&neigh->ha, lladdr, dev->addr_len);
1033 neigh_update_hhs(neigh);
1034 if (!(new & NUD_CONNECTED))
1035 neigh->confirmed = jiffies -
1036 (neigh->parms->base_reachable_time << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 }
1039 if (new == old)
1040 goto out;
1041 if (new & NUD_CONNECTED)
1042 neigh_connect(neigh);
1043 else
1044 neigh_suspect(neigh);
1045 if (!(old & NUD_VALID)) {
1046 struct sk_buff *skb;
1047
1048 /* Again: avoid dead loop if something went wrong */
1049
1050 while (neigh->nud_state & NUD_VALID &&
1051 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
1052 struct neighbour *n1 = neigh;
1053 write_unlock_bh(&neigh->lock);
1054 /* On shaper/eql skb->dst->neighbour != neigh :( */
1055 if (skb->dst && skb->dst->neighbour)
1056 n1 = skb->dst->neighbour;
1057 n1->output(skb);
1058 write_lock_bh(&neigh->lock);
1059 }
1060 skb_queue_purge(&neigh->arp_queue);
1061 }
1062out:
1063 if (update_isrouter) {
1064 neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?
1065 (neigh->flags | NTF_ROUTER) :
1066 (neigh->flags & ~NTF_ROUTER);
1067 }
1068 write_unlock_bh(&neigh->lock);
Tom Tucker8d717402006-07-30 20:43:36 -07001069
1070 if (notify)
Thomas Grafd961db32007-08-08 23:12:56 -07001071 neigh_update_notify(neigh);
1072
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 return err;
1074}
1075
1076struct neighbour *neigh_event_ns(struct neigh_table *tbl,
1077 u8 *lladdr, void *saddr,
1078 struct net_device *dev)
1079{
1080 struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
1081 lladdr || !dev->addr_len);
1082 if (neigh)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001083 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 NEIGH_UPDATE_F_OVERRIDE);
1085 return neigh;
1086}
1087
1088static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
Al Virod77072e2006-09-28 14:20:34 -07001089 __be16 protocol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090{
1091 struct hh_cache *hh;
1092 struct net_device *dev = dst->dev;
1093
1094 for (hh = n->hh; hh; hh = hh->hh_next)
1095 if (hh->hh_type == protocol)
1096 break;
1097
Andrew Morton77d04bd2006-04-07 14:52:59 -07001098 if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) {
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001099 seqlock_init(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 hh->hh_type = protocol;
1101 atomic_set(&hh->hh_refcnt, 0);
1102 hh->hh_next = NULL;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001103
1104 if (dev->header_ops->cache(n, hh)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 kfree(hh);
1106 hh = NULL;
1107 } else {
1108 atomic_inc(&hh->hh_refcnt);
1109 hh->hh_next = n->hh;
1110 n->hh = hh;
1111 if (n->nud_state & NUD_CONNECTED)
1112 hh->hh_output = n->ops->hh_output;
1113 else
1114 hh->hh_output = n->ops->output;
1115 }
1116 }
1117 if (hh) {
1118 atomic_inc(&hh->hh_refcnt);
1119 dst->hh = hh;
1120 }
1121}
1122
1123/* This function can be used in contexts, where only old dev_queue_xmit
1124 worked, f.e. if you want to override normal output path (eql, shaper),
1125 but resolution is not made yet.
1126 */
1127
1128int neigh_compat_output(struct sk_buff *skb)
1129{
1130 struct net_device *dev = skb->dev;
1131
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001132 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
Stephen Hemminger0c4e8582007-10-09 01:36:32 -07001134 if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
1135 skb->len) < 0 &&
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001136 dev->header_ops->rebuild(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 return 0;
1138
1139 return dev_queue_xmit(skb);
1140}
1141
1142/* Slow and careful. */
1143
1144int neigh_resolve_output(struct sk_buff *skb)
1145{
1146 struct dst_entry *dst = skb->dst;
1147 struct neighbour *neigh;
1148 int rc = 0;
1149
1150 if (!dst || !(neigh = dst->neighbour))
1151 goto discard;
1152
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001153 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154
1155 if (!neigh_event_send(neigh, skb)) {
1156 int err;
1157 struct net_device *dev = neigh->dev;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001158 if (dev->header_ops->cache && !dst->hh) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 write_lock_bh(&neigh->lock);
1160 if (!dst->hh)
1161 neigh_hh_init(neigh, dst, dst->ops->protocol);
Stephen Hemminger0c4e8582007-10-09 01:36:32 -07001162 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1163 neigh->ha, NULL, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 write_unlock_bh(&neigh->lock);
1165 } else {
1166 read_lock_bh(&neigh->lock);
Stephen Hemminger0c4e8582007-10-09 01:36:32 -07001167 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1168 neigh->ha, NULL, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 read_unlock_bh(&neigh->lock);
1170 }
1171 if (err >= 0)
1172 rc = neigh->ops->queue_xmit(skb);
1173 else
1174 goto out_kfree_skb;
1175 }
1176out:
1177 return rc;
1178discard:
1179 NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
1180 dst, dst ? dst->neighbour : NULL);
1181out_kfree_skb:
1182 rc = -EINVAL;
1183 kfree_skb(skb);
1184 goto out;
1185}
1186
1187/* As fast as possible without hh cache */
1188
1189int neigh_connected_output(struct sk_buff *skb)
1190{
1191 int err;
1192 struct dst_entry *dst = skb->dst;
1193 struct neighbour *neigh = dst->neighbour;
1194 struct net_device *dev = neigh->dev;
1195
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001196 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197
1198 read_lock_bh(&neigh->lock);
Stephen Hemminger0c4e8582007-10-09 01:36:32 -07001199 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1200 neigh->ha, NULL, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 read_unlock_bh(&neigh->lock);
1202 if (err >= 0)
1203 err = neigh->ops->queue_xmit(skb);
1204 else {
1205 err = -EINVAL;
1206 kfree_skb(skb);
1207 }
1208 return err;
1209}
1210
1211static void neigh_proxy_process(unsigned long arg)
1212{
1213 struct neigh_table *tbl = (struct neigh_table *)arg;
1214 long sched_next = 0;
1215 unsigned long now = jiffies;
1216 struct sk_buff *skb;
1217
1218 spin_lock(&tbl->proxy_queue.lock);
1219
1220 skb = tbl->proxy_queue.next;
1221
1222 while (skb != (struct sk_buff *)&tbl->proxy_queue) {
1223 struct sk_buff *back = skb;
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001224 long tdif = NEIGH_CB(back)->sched_next - now;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
1226 skb = skb->next;
1227 if (tdif <= 0) {
1228 struct net_device *dev = back->dev;
1229 __skb_unlink(back, &tbl->proxy_queue);
1230 if (tbl->proxy_redo && netif_running(dev))
1231 tbl->proxy_redo(back);
1232 else
1233 kfree_skb(back);
1234
1235 dev_put(dev);
1236 } else if (!sched_next || tdif < sched_next)
1237 sched_next = tdif;
1238 }
1239 del_timer(&tbl->proxy_timer);
1240 if (sched_next)
1241 mod_timer(&tbl->proxy_timer, jiffies + sched_next);
1242 spin_unlock(&tbl->proxy_queue.lock);
1243}
1244
1245void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
1246 struct sk_buff *skb)
1247{
1248 unsigned long now = jiffies;
1249 unsigned long sched_next = now + (net_random() % p->proxy_delay);
1250
1251 if (tbl->proxy_queue.qlen > p->proxy_qlen) {
1252 kfree_skb(skb);
1253 return;
1254 }
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001255
1256 NEIGH_CB(skb)->sched_next = sched_next;
1257 NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
1259 spin_lock(&tbl->proxy_queue.lock);
1260 if (del_timer(&tbl->proxy_timer)) {
1261 if (time_before(tbl->proxy_timer.expires, sched_next))
1262 sched_next = tbl->proxy_timer.expires;
1263 }
1264 dst_release(skb->dst);
1265 skb->dst = NULL;
1266 dev_hold(skb->dev);
1267 __skb_queue_tail(&tbl->proxy_queue, skb);
1268 mod_timer(&tbl->proxy_timer, sched_next);
1269 spin_unlock(&tbl->proxy_queue.lock);
1270}
1271
Eric W. Biederman426b5302008-01-24 00:13:18 -08001272static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
1273 struct net *net, int ifindex)
1274{
1275 struct neigh_parms *p;
1276
1277 for (p = &tbl->parms; p; p = p->next) {
1278 if (p->net != net)
1279 continue;
1280 if ((p->dev && p->dev->ifindex == ifindex) ||
1281 (!p->dev && !ifindex))
1282 return p;
1283 }
1284
1285 return NULL;
1286}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287
1288struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1289 struct neigh_table *tbl)
1290{
Eric W. Biederman426b5302008-01-24 00:13:18 -08001291 struct neigh_parms *p, *ref;
1292 struct net *net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001294 net = dev->nd_net;
Eric W. Biederman426b5302008-01-24 00:13:18 -08001295 ref = lookup_neigh_params(tbl, net, 0);
1296 if (!ref)
1297 return NULL;
1298
1299 p = kmemdup(ref, sizeof(*p), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 if (p) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 p->tbl = tbl;
1302 atomic_set(&p->refcnt, 1);
1303 INIT_RCU_HEAD(&p->rcu_head);
1304 p->reachable_time =
1305 neigh_rand_reach_time(p->base_reachable_time);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001306
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001307 if (dev->neigh_setup && dev->neigh_setup(dev, p)) {
1308 kfree(p);
1309 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 }
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001311
1312 dev_hold(dev);
1313 p->dev = dev;
Eric W. Biederman426b5302008-01-24 00:13:18 -08001314 p->net = hold_net(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 p->sysctl_table = NULL;
1316 write_lock_bh(&tbl->lock);
1317 p->next = tbl->parms.next;
1318 tbl->parms.next = p;
1319 write_unlock_bh(&tbl->lock);
1320 }
1321 return p;
1322}
1323
1324static void neigh_rcu_free_parms(struct rcu_head *head)
1325{
1326 struct neigh_parms *parms =
1327 container_of(head, struct neigh_parms, rcu_head);
1328
1329 neigh_parms_put(parms);
1330}
1331
1332void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
1333{
1334 struct neigh_parms **p;
1335
1336 if (!parms || parms == &tbl->parms)
1337 return;
1338 write_lock_bh(&tbl->lock);
1339 for (p = &tbl->parms.next; *p; p = &(*p)->next) {
1340 if (*p == parms) {
1341 *p = parms->next;
1342 parms->dead = 1;
1343 write_unlock_bh(&tbl->lock);
David S. Millercecbb632008-01-20 16:39:03 -08001344 if (parms->dev)
1345 dev_put(parms->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
1347 return;
1348 }
1349 }
1350 write_unlock_bh(&tbl->lock);
1351 NEIGH_PRINTK1("neigh_parms_release: not found\n");
1352}
1353
1354void neigh_parms_destroy(struct neigh_parms *parms)
1355{
Eric W. Biederman426b5302008-01-24 00:13:18 -08001356 release_net(parms->net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 kfree(parms);
1358}
1359
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001360static struct lock_class_key neigh_table_proxy_queue_class;
1361
Simon Kelleybd89efc2006-05-12 14:56:08 -07001362void neigh_table_init_no_netlink(struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363{
1364 unsigned long now = jiffies;
1365 unsigned long phsize;
1366
Eric W. Biederman426b5302008-01-24 00:13:18 -08001367 tbl->parms.net = &init_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 atomic_set(&tbl->parms.refcnt, 1);
1369 INIT_RCU_HEAD(&tbl->parms.rcu_head);
1370 tbl->parms.reachable_time =
1371 neigh_rand_reach_time(tbl->parms.base_reachable_time);
1372
1373 if (!tbl->kmem_cachep)
Alexey Dobriyane5d679f332006-08-26 19:25:52 -07001374 tbl->kmem_cachep =
1375 kmem_cache_create(tbl->id, tbl->entry_size, 0,
1376 SLAB_HWCACHE_ALIGN|SLAB_PANIC,
Paul Mundt20c2df82007-07-20 10:11:58 +09001377 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 tbl->stats = alloc_percpu(struct neigh_statistics);
1379 if (!tbl->stats)
1380 panic("cannot create neighbour cache statistics");
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001381
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382#ifdef CONFIG_PROC_FS
Eric W. Biederman457c4cb2007-09-12 12:01:34 +02001383 tbl->pde = create_proc_entry(tbl->id, 0, init_net.proc_net_stat);
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001384 if (!tbl->pde)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 panic("cannot create neighbour proc dir entry");
1386 tbl->pde->proc_fops = &neigh_stat_seq_fops;
1387 tbl->pde->data = tbl;
1388#endif
1389
1390 tbl->hash_mask = 1;
1391 tbl->hash_buckets = neigh_hash_alloc(tbl->hash_mask + 1);
1392
1393 phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
Andrew Morton77d04bd2006-04-07 14:52:59 -07001394 tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
1396 if (!tbl->hash_buckets || !tbl->phash_buckets)
1397 panic("cannot allocate neighbour cache hashes");
1398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd));
1400
1401 rwlock_init(&tbl->lock);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001402 setup_timer(&tbl->gc_timer, neigh_periodic_timer, (unsigned long)tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 tbl->gc_timer.expires = now + 1;
1404 add_timer(&tbl->gc_timer);
1405
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001406 setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl);
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001407 skb_queue_head_init_class(&tbl->proxy_queue,
1408 &neigh_table_proxy_queue_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409
1410 tbl->last_flush = now;
1411 tbl->last_rand = now + tbl->parms.reachable_time * 20;
Simon Kelleybd89efc2006-05-12 14:56:08 -07001412}
1413
1414void neigh_table_init(struct neigh_table *tbl)
1415{
1416 struct neigh_table *tmp;
1417
1418 neigh_table_init_no_netlink(tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 write_lock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001420 for (tmp = neigh_tables; tmp; tmp = tmp->next) {
1421 if (tmp->family == tbl->family)
1422 break;
1423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 tbl->next = neigh_tables;
1425 neigh_tables = tbl;
1426 write_unlock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001427
1428 if (unlikely(tmp)) {
1429 printk(KERN_ERR "NEIGH: Registering multiple tables for "
1430 "family %d\n", tbl->family);
1431 dump_stack();
1432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433}
1434
1435int neigh_table_clear(struct neigh_table *tbl)
1436{
1437 struct neigh_table **tp;
1438
1439 /* It is not clean... Fix it to unload IPv6 module safely */
1440 del_timer_sync(&tbl->gc_timer);
1441 del_timer_sync(&tbl->proxy_timer);
1442 pneigh_queue_purge(&tbl->proxy_queue);
1443 neigh_ifdown(tbl, NULL);
1444 if (atomic_read(&tbl->entries))
1445 printk(KERN_CRIT "neighbour leakage\n");
1446 write_lock(&neigh_tbl_lock);
1447 for (tp = &neigh_tables; *tp; tp = &(*tp)->next) {
1448 if (*tp == tbl) {
1449 *tp = tbl->next;
1450 break;
1451 }
1452 }
1453 write_unlock(&neigh_tbl_lock);
1454
1455 neigh_hash_free(tbl->hash_buckets, tbl->hash_mask + 1);
1456 tbl->hash_buckets = NULL;
1457
1458 kfree(tbl->phash_buckets);
1459 tbl->phash_buckets = NULL;
1460
Alexey Dobriyan3f192b52007-11-05 21:28:13 -08001461 remove_proc_entry(tbl->id, init_net.proc_net_stat);
1462
Kirill Korotaev3fcde742006-09-01 01:34:10 -07001463 free_percpu(tbl->stats);
1464 tbl->stats = NULL;
1465
Randy Dunlapbfb85c92007-10-21 16:24:27 -07001466 kmem_cache_destroy(tbl->kmem_cachep);
1467 tbl->kmem_cachep = NULL;
1468
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 return 0;
1470}
1471
Thomas Grafc8822a42007-03-22 11:50:06 -07001472static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473{
Eric W. Biederman881d9662007-09-17 11:56:21 -07001474 struct net *net = skb->sk->sk_net;
Thomas Grafa14a49d2006-08-07 17:53:08 -07001475 struct ndmsg *ndm;
1476 struct nlattr *dst_attr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 struct neigh_table *tbl;
1478 struct net_device *dev = NULL;
Thomas Grafa14a49d2006-08-07 17:53:08 -07001479 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480
Thomas Grafa14a49d2006-08-07 17:53:08 -07001481 if (nlmsg_len(nlh) < sizeof(*ndm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 goto out;
1483
Thomas Grafa14a49d2006-08-07 17:53:08 -07001484 dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
1485 if (dst_attr == NULL)
1486 goto out;
1487
1488 ndm = nlmsg_data(nlh);
1489 if (ndm->ndm_ifindex) {
Eric W. Biederman881d9662007-09-17 11:56:21 -07001490 dev = dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001491 if (dev == NULL) {
1492 err = -ENODEV;
1493 goto out;
1494 }
1495 }
1496
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 read_lock(&neigh_tbl_lock);
1498 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Grafa14a49d2006-08-07 17:53:08 -07001499 struct neighbour *neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
1501 if (tbl->family != ndm->ndm_family)
1502 continue;
1503 read_unlock(&neigh_tbl_lock);
1504
Thomas Grafa14a49d2006-08-07 17:53:08 -07001505 if (nla_len(dst_attr) < tbl->key_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 goto out_dev_put;
1507
1508 if (ndm->ndm_flags & NTF_PROXY) {
Eric W. Biederman426b5302008-01-24 00:13:18 -08001509 err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 goto out_dev_put;
1511 }
1512
Thomas Grafa14a49d2006-08-07 17:53:08 -07001513 if (dev == NULL)
1514 goto out_dev_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515
Thomas Grafa14a49d2006-08-07 17:53:08 -07001516 neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1517 if (neigh == NULL) {
1518 err = -ENOENT;
1519 goto out_dev_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 }
Thomas Grafa14a49d2006-08-07 17:53:08 -07001521
1522 err = neigh_update(neigh, NULL, NUD_FAILED,
1523 NEIGH_UPDATE_F_OVERRIDE |
1524 NEIGH_UPDATE_F_ADMIN);
1525 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 goto out_dev_put;
1527 }
1528 read_unlock(&neigh_tbl_lock);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001529 err = -EAFNOSUPPORT;
1530
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531out_dev_put:
1532 if (dev)
1533 dev_put(dev);
1534out:
1535 return err;
1536}
1537
Thomas Grafc8822a42007-03-22 11:50:06 -07001538static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539{
Eric W. Biederman881d9662007-09-17 11:56:21 -07001540 struct net *net = skb->sk->sk_net;
Thomas Graf5208deb2006-08-07 17:55:40 -07001541 struct ndmsg *ndm;
1542 struct nlattr *tb[NDA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 struct neigh_table *tbl;
1544 struct net_device *dev = NULL;
Thomas Graf5208deb2006-08-07 17:55:40 -07001545 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546
Thomas Graf5208deb2006-08-07 17:55:40 -07001547 err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
1548 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 goto out;
1550
Thomas Graf5208deb2006-08-07 17:55:40 -07001551 err = -EINVAL;
1552 if (tb[NDA_DST] == NULL)
1553 goto out;
1554
1555 ndm = nlmsg_data(nlh);
1556 if (ndm->ndm_ifindex) {
Eric W. Biederman881d9662007-09-17 11:56:21 -07001557 dev = dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Graf5208deb2006-08-07 17:55:40 -07001558 if (dev == NULL) {
1559 err = -ENODEV;
1560 goto out;
1561 }
1562
1563 if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
1564 goto out_dev_put;
1565 }
1566
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 read_lock(&neigh_tbl_lock);
1568 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Graf5208deb2006-08-07 17:55:40 -07001569 int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
1570 struct neighbour *neigh;
1571 void *dst, *lladdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
1573 if (tbl->family != ndm->ndm_family)
1574 continue;
1575 read_unlock(&neigh_tbl_lock);
1576
Thomas Graf5208deb2006-08-07 17:55:40 -07001577 if (nla_len(tb[NDA_DST]) < tbl->key_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 goto out_dev_put;
Thomas Graf5208deb2006-08-07 17:55:40 -07001579 dst = nla_data(tb[NDA_DST]);
1580 lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
1582 if (ndm->ndm_flags & NTF_PROXY) {
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001583 struct pneigh_entry *pn;
1584
1585 err = -ENOBUFS;
Eric W. Biederman426b5302008-01-24 00:13:18 -08001586 pn = pneigh_lookup(tbl, net, dst, dev, 1);
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001587 if (pn) {
1588 pn->flags = ndm->ndm_flags;
1589 err = 0;
1590 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 goto out_dev_put;
1592 }
1593
Thomas Graf5208deb2006-08-07 17:55:40 -07001594 if (dev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 goto out_dev_put;
Thomas Graf5208deb2006-08-07 17:55:40 -07001596
1597 neigh = neigh_lookup(tbl, dst, dev);
1598 if (neigh == NULL) {
1599 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
1600 err = -ENOENT;
1601 goto out_dev_put;
1602 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001603
Thomas Graf5208deb2006-08-07 17:55:40 -07001604 neigh = __neigh_lookup_errno(tbl, dst, dev);
1605 if (IS_ERR(neigh)) {
1606 err = PTR_ERR(neigh);
1607 goto out_dev_put;
1608 }
1609 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 if (nlh->nlmsg_flags & NLM_F_EXCL) {
1611 err = -EEXIST;
Thomas Graf5208deb2006-08-07 17:55:40 -07001612 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 goto out_dev_put;
1614 }
Thomas Graf5208deb2006-08-07 17:55:40 -07001615
1616 if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
1617 flags &= ~NEIGH_UPDATE_F_OVERRIDE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 }
1619
Thomas Graf5208deb2006-08-07 17:55:40 -07001620 err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
1621 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 goto out_dev_put;
1623 }
1624
1625 read_unlock(&neigh_tbl_lock);
Thomas Graf5208deb2006-08-07 17:55:40 -07001626 err = -EAFNOSUPPORT;
1627
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628out_dev_put:
1629 if (dev)
1630 dev_put(dev);
1631out:
1632 return err;
1633}
1634
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001635static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1636{
Thomas Grafca860fb2006-08-07 18:00:18 -07001637 struct nlattr *nest;
1638
1639 nest = nla_nest_start(skb, NDTA_PARMS);
1640 if (nest == NULL)
1641 return -ENOBUFS;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001642
1643 if (parms->dev)
Thomas Grafca860fb2006-08-07 18:00:18 -07001644 NLA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001645
Thomas Grafca860fb2006-08-07 18:00:18 -07001646 NLA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt));
1647 NLA_PUT_U32(skb, NDTPA_QUEUE_LEN, parms->queue_len);
1648 NLA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen);
1649 NLA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes);
1650 NLA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes);
1651 NLA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes);
1652 NLA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time);
1653 NLA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001654 parms->base_reachable_time);
Thomas Grafca860fb2006-08-07 18:00:18 -07001655 NLA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime);
1656 NLA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time);
1657 NLA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time);
1658 NLA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay);
1659 NLA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay);
1660 NLA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001661
Thomas Grafca860fb2006-08-07 18:00:18 -07001662 return nla_nest_end(skb, nest);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001663
Thomas Grafca860fb2006-08-07 18:00:18 -07001664nla_put_failure:
1665 return nla_nest_cancel(skb, nest);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001666}
1667
Thomas Grafca860fb2006-08-07 18:00:18 -07001668static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
1669 u32 pid, u32 seq, int type, int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001670{
1671 struct nlmsghdr *nlh;
1672 struct ndtmsg *ndtmsg;
1673
Thomas Grafca860fb2006-08-07 18:00:18 -07001674 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1675 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001676 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001677
Thomas Grafca860fb2006-08-07 18:00:18 -07001678 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001679
1680 read_lock_bh(&tbl->lock);
1681 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001682 ndtmsg->ndtm_pad1 = 0;
1683 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001684
Thomas Grafca860fb2006-08-07 18:00:18 -07001685 NLA_PUT_STRING(skb, NDTA_NAME, tbl->id);
1686 NLA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval);
1687 NLA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1);
1688 NLA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2);
1689 NLA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001690
1691 {
1692 unsigned long now = jiffies;
1693 unsigned int flush_delta = now - tbl->last_flush;
1694 unsigned int rand_delta = now - tbl->last_rand;
1695
1696 struct ndt_config ndc = {
1697 .ndtc_key_len = tbl->key_len,
1698 .ndtc_entry_size = tbl->entry_size,
1699 .ndtc_entries = atomic_read(&tbl->entries),
1700 .ndtc_last_flush = jiffies_to_msecs(flush_delta),
1701 .ndtc_last_rand = jiffies_to_msecs(rand_delta),
1702 .ndtc_hash_rnd = tbl->hash_rnd,
1703 .ndtc_hash_mask = tbl->hash_mask,
1704 .ndtc_hash_chain_gc = tbl->hash_chain_gc,
1705 .ndtc_proxy_qlen = tbl->proxy_queue.qlen,
1706 };
1707
Thomas Grafca860fb2006-08-07 18:00:18 -07001708 NLA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001709 }
1710
1711 {
1712 int cpu;
1713 struct ndt_stats ndst;
1714
1715 memset(&ndst, 0, sizeof(ndst));
1716
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001717 for_each_possible_cpu(cpu) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001718 struct neigh_statistics *st;
1719
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001720 st = per_cpu_ptr(tbl->stats, cpu);
1721 ndst.ndts_allocs += st->allocs;
1722 ndst.ndts_destroys += st->destroys;
1723 ndst.ndts_hash_grows += st->hash_grows;
1724 ndst.ndts_res_failed += st->res_failed;
1725 ndst.ndts_lookups += st->lookups;
1726 ndst.ndts_hits += st->hits;
1727 ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast;
1728 ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast;
1729 ndst.ndts_periodic_gc_runs += st->periodic_gc_runs;
1730 ndst.ndts_forced_gc_runs += st->forced_gc_runs;
1731 }
1732
Thomas Grafca860fb2006-08-07 18:00:18 -07001733 NLA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001734 }
1735
1736 BUG_ON(tbl->parms.dev);
1737 if (neightbl_fill_parms(skb, &tbl->parms) < 0)
Thomas Grafca860fb2006-08-07 18:00:18 -07001738 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001739
1740 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001741 return nlmsg_end(skb, nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001742
Thomas Grafca860fb2006-08-07 18:00:18 -07001743nla_put_failure:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001744 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001745 nlmsg_cancel(skb, nlh);
1746 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001747}
1748
Thomas Grafca860fb2006-08-07 18:00:18 -07001749static int neightbl_fill_param_info(struct sk_buff *skb,
1750 struct neigh_table *tbl,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001751 struct neigh_parms *parms,
Thomas Grafca860fb2006-08-07 18:00:18 -07001752 u32 pid, u32 seq, int type,
1753 unsigned int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001754{
1755 struct ndtmsg *ndtmsg;
1756 struct nlmsghdr *nlh;
1757
Thomas Grafca860fb2006-08-07 18:00:18 -07001758 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1759 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001760 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001761
Thomas Grafca860fb2006-08-07 18:00:18 -07001762 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001763
1764 read_lock_bh(&tbl->lock);
1765 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001766 ndtmsg->ndtm_pad1 = 0;
1767 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001768
Thomas Grafca860fb2006-08-07 18:00:18 -07001769 if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
1770 neightbl_fill_parms(skb, parms) < 0)
1771 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001772
1773 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001774 return nlmsg_end(skb, nlh);
1775errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001776 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001777 nlmsg_cancel(skb, nlh);
1778 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001779}
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001780
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001781static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001782 [NDTA_NAME] = { .type = NLA_STRING },
1783 [NDTA_THRESH1] = { .type = NLA_U32 },
1784 [NDTA_THRESH2] = { .type = NLA_U32 },
1785 [NDTA_THRESH3] = { .type = NLA_U32 },
1786 [NDTA_GC_INTERVAL] = { .type = NLA_U64 },
1787 [NDTA_PARMS] = { .type = NLA_NESTED },
1788};
1789
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001790static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001791 [NDTPA_IFINDEX] = { .type = NLA_U32 },
1792 [NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
1793 [NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
1794 [NDTPA_APP_PROBES] = { .type = NLA_U32 },
1795 [NDTPA_UCAST_PROBES] = { .type = NLA_U32 },
1796 [NDTPA_MCAST_PROBES] = { .type = NLA_U32 },
1797 [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 },
1798 [NDTPA_GC_STALETIME] = { .type = NLA_U64 },
1799 [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 },
1800 [NDTPA_RETRANS_TIME] = { .type = NLA_U64 },
1801 [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
1802 [NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
1803 [NDTPA_LOCKTIME] = { .type = NLA_U64 },
1804};
1805
Thomas Grafc8822a42007-03-22 11:50:06 -07001806static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001807{
Denis V. Lunevb8542722007-12-01 00:21:31 +11001808 struct net *net = skb->sk->sk_net;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001809 struct neigh_table *tbl;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001810 struct ndtmsg *ndtmsg;
1811 struct nlattr *tb[NDTA_MAX+1];
1812 int err;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001813
Thomas Graf6b3f8672006-08-07 17:58:53 -07001814 err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
1815 nl_neightbl_policy);
1816 if (err < 0)
1817 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001818
Thomas Graf6b3f8672006-08-07 17:58:53 -07001819 if (tb[NDTA_NAME] == NULL) {
1820 err = -EINVAL;
1821 goto errout;
1822 }
1823
1824 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001825 read_lock(&neigh_tbl_lock);
1826 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
1827 if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
1828 continue;
1829
Thomas Graf6b3f8672006-08-07 17:58:53 -07001830 if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001831 break;
1832 }
1833
1834 if (tbl == NULL) {
1835 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001836 goto errout_locked;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001837 }
1838
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001839 /*
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001840 * We acquire tbl->lock to be nice to the periodic timers and
1841 * make sure they always see a consistent set of values.
1842 */
1843 write_lock_bh(&tbl->lock);
1844
Thomas Graf6b3f8672006-08-07 17:58:53 -07001845 if (tb[NDTA_PARMS]) {
1846 struct nlattr *tbp[NDTPA_MAX+1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001847 struct neigh_parms *p;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001848 int i, ifindex = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001849
Thomas Graf6b3f8672006-08-07 17:58:53 -07001850 err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
1851 nl_ntbl_parm_policy);
1852 if (err < 0)
1853 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001854
Thomas Graf6b3f8672006-08-07 17:58:53 -07001855 if (tbp[NDTPA_IFINDEX])
1856 ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001857
Eric W. Biederman426b5302008-01-24 00:13:18 -08001858 p = lookup_neigh_params(tbl, net, ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001859 if (p == NULL) {
1860 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001861 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001862 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001863
Thomas Graf6b3f8672006-08-07 17:58:53 -07001864 for (i = 1; i <= NDTPA_MAX; i++) {
1865 if (tbp[i] == NULL)
1866 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001867
Thomas Graf6b3f8672006-08-07 17:58:53 -07001868 switch (i) {
1869 case NDTPA_QUEUE_LEN:
1870 p->queue_len = nla_get_u32(tbp[i]);
1871 break;
1872 case NDTPA_PROXY_QLEN:
1873 p->proxy_qlen = nla_get_u32(tbp[i]);
1874 break;
1875 case NDTPA_APP_PROBES:
1876 p->app_probes = nla_get_u32(tbp[i]);
1877 break;
1878 case NDTPA_UCAST_PROBES:
1879 p->ucast_probes = nla_get_u32(tbp[i]);
1880 break;
1881 case NDTPA_MCAST_PROBES:
1882 p->mcast_probes = nla_get_u32(tbp[i]);
1883 break;
1884 case NDTPA_BASE_REACHABLE_TIME:
1885 p->base_reachable_time = nla_get_msecs(tbp[i]);
1886 break;
1887 case NDTPA_GC_STALETIME:
1888 p->gc_staletime = nla_get_msecs(tbp[i]);
1889 break;
1890 case NDTPA_DELAY_PROBE_TIME:
1891 p->delay_probe_time = nla_get_msecs(tbp[i]);
1892 break;
1893 case NDTPA_RETRANS_TIME:
1894 p->retrans_time = nla_get_msecs(tbp[i]);
1895 break;
1896 case NDTPA_ANYCAST_DELAY:
1897 p->anycast_delay = nla_get_msecs(tbp[i]);
1898 break;
1899 case NDTPA_PROXY_DELAY:
1900 p->proxy_delay = nla_get_msecs(tbp[i]);
1901 break;
1902 case NDTPA_LOCKTIME:
1903 p->locktime = nla_get_msecs(tbp[i]);
1904 break;
1905 }
1906 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001907 }
1908
Thomas Graf6b3f8672006-08-07 17:58:53 -07001909 if (tb[NDTA_THRESH1])
1910 tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
1911
1912 if (tb[NDTA_THRESH2])
1913 tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
1914
1915 if (tb[NDTA_THRESH3])
1916 tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
1917
1918 if (tb[NDTA_GC_INTERVAL])
1919 tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
1920
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001921 err = 0;
1922
Thomas Graf6b3f8672006-08-07 17:58:53 -07001923errout_tbl_lock:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001924 write_unlock_bh(&tbl->lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07001925errout_locked:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001926 read_unlock(&neigh_tbl_lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07001927errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001928 return err;
1929}
1930
Thomas Grafc8822a42007-03-22 11:50:06 -07001931static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001932{
Denis V. Lunevb8542722007-12-01 00:21:31 +11001933 struct net *net = skb->sk->sk_net;
Thomas Grafca860fb2006-08-07 18:00:18 -07001934 int family, tidx, nidx = 0;
1935 int tbl_skip = cb->args[0];
1936 int neigh_skip = cb->args[1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001937 struct neigh_table *tbl;
1938
Thomas Grafca860fb2006-08-07 18:00:18 -07001939 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001940
1941 read_lock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001942 for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001943 struct neigh_parms *p;
1944
Thomas Grafca860fb2006-08-07 18:00:18 -07001945 if (tidx < tbl_skip || (family && tbl->family != family))
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001946 continue;
1947
Thomas Grafca860fb2006-08-07 18:00:18 -07001948 if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).pid,
1949 cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
1950 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001951 break;
1952
Eric W. Biederman426b5302008-01-24 00:13:18 -08001953 for (nidx = 0, p = tbl->parms.next; p; p = p->next) {
1954 if (net != p->net)
1955 continue;
1956
1957 if (nidx++ < neigh_skip)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001958 continue;
1959
Thomas Grafca860fb2006-08-07 18:00:18 -07001960 if (neightbl_fill_param_info(skb, tbl, p,
1961 NETLINK_CB(cb->skb).pid,
1962 cb->nlh->nlmsg_seq,
1963 RTM_NEWNEIGHTBL,
1964 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001965 goto out;
1966 }
1967
Thomas Grafca860fb2006-08-07 18:00:18 -07001968 neigh_skip = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001969 }
1970out:
1971 read_unlock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001972 cb->args[0] = tidx;
1973 cb->args[1] = nidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001974
1975 return skb->len;
1976}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977
Thomas Graf8b8aec52006-08-07 17:56:37 -07001978static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
1979 u32 pid, u32 seq, int type, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980{
1981 unsigned long now = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 struct nda_cacheinfo ci;
Thomas Graf8b8aec52006-08-07 17:56:37 -07001983 struct nlmsghdr *nlh;
1984 struct ndmsg *ndm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985
Thomas Graf8b8aec52006-08-07 17:56:37 -07001986 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
1987 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001988 return -EMSGSIZE;
Thomas Graf8b8aec52006-08-07 17:56:37 -07001989
1990 ndm = nlmsg_data(nlh);
1991 ndm->ndm_family = neigh->ops->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001992 ndm->ndm_pad1 = 0;
1993 ndm->ndm_pad2 = 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07001994 ndm->ndm_flags = neigh->flags;
1995 ndm->ndm_type = neigh->type;
1996 ndm->ndm_ifindex = neigh->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997
Thomas Graf8b8aec52006-08-07 17:56:37 -07001998 NLA_PUT(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key);
1999
2000 read_lock_bh(&neigh->lock);
2001 ndm->ndm_state = neigh->nud_state;
2002 if ((neigh->nud_state & NUD_VALID) &&
2003 nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, neigh->ha) < 0) {
2004 read_unlock_bh(&neigh->lock);
2005 goto nla_put_failure;
2006 }
2007
2008 ci.ndm_used = now - neigh->used;
2009 ci.ndm_confirmed = now - neigh->confirmed;
2010 ci.ndm_updated = now - neigh->updated;
2011 ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1;
2012 read_unlock_bh(&neigh->lock);
2013
2014 NLA_PUT_U32(skb, NDA_PROBES, atomic_read(&neigh->probes));
2015 NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
2016
2017 return nlmsg_end(skb, nlh);
2018
2019nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002020 nlmsg_cancel(skb, nlh);
2021 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022}
2023
Thomas Grafd961db32007-08-08 23:12:56 -07002024static void neigh_update_notify(struct neighbour *neigh)
2025{
2026 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
2027 __neigh_notify(neigh, RTM_NEWNEIGH, 0);
2028}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029
2030static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2031 struct netlink_callback *cb)
2032{
Eric W. Biederman426b5302008-01-24 00:13:18 -08002033 struct net * net = skb->sk->sk_net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 struct neighbour *n;
2035 int rc, h, s_h = cb->args[1];
2036 int idx, s_idx = idx = cb->args[2];
2037
Julian Anastasovc5e29462006-10-03 15:49:46 -07002038 read_lock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 for (h = 0; h <= tbl->hash_mask; h++) {
2040 if (h < s_h)
2041 continue;
2042 if (h > s_h)
2043 s_idx = 0;
Eric W. Biederman426b5302008-01-24 00:13:18 -08002044 for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next) {
2045 int lidx;
2046 if (n->dev->nd_net != net)
2047 continue;
2048 lidx = idx++;
2049 if (lidx < s_idx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 continue;
2051 if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid,
2052 cb->nlh->nlmsg_seq,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07002053 RTM_NEWNEIGH,
2054 NLM_F_MULTI) <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 read_unlock_bh(&tbl->lock);
2056 rc = -1;
2057 goto out;
2058 }
2059 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 }
Julian Anastasovc5e29462006-10-03 15:49:46 -07002061 read_unlock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 rc = skb->len;
2063out:
2064 cb->args[1] = h;
2065 cb->args[2] = idx;
2066 return rc;
2067}
2068
Thomas Grafc8822a42007-03-22 11:50:06 -07002069static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070{
2071 struct neigh_table *tbl;
2072 int t, family, s_t;
2073
2074 read_lock(&neigh_tbl_lock);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002075 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 s_t = cb->args[0];
2077
2078 for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) {
2079 if (t < s_t || (family && tbl->family != family))
2080 continue;
2081 if (t > s_t)
2082 memset(&cb->args[1], 0, sizeof(cb->args) -
2083 sizeof(cb->args[0]));
2084 if (neigh_dump_table(tbl, skb, cb) < 0)
2085 break;
2086 }
2087 read_unlock(&neigh_tbl_lock);
2088
2089 cb->args[0] = t;
2090 return skb->len;
2091}
2092
2093void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
2094{
2095 int chain;
2096
2097 read_lock_bh(&tbl->lock);
2098 for (chain = 0; chain <= tbl->hash_mask; chain++) {
2099 struct neighbour *n;
2100
2101 for (n = tbl->hash_buckets[chain]; n; n = n->next)
2102 cb(n, cookie);
2103 }
2104 read_unlock_bh(&tbl->lock);
2105}
2106EXPORT_SYMBOL(neigh_for_each);
2107
2108/* The tbl->lock must be held as a writer and BH disabled. */
2109void __neigh_for_each_release(struct neigh_table *tbl,
2110 int (*cb)(struct neighbour *))
2111{
2112 int chain;
2113
2114 for (chain = 0; chain <= tbl->hash_mask; chain++) {
2115 struct neighbour *n, **np;
2116
2117 np = &tbl->hash_buckets[chain];
2118 while ((n = *np) != NULL) {
2119 int release;
2120
2121 write_lock(&n->lock);
2122 release = cb(n);
2123 if (release) {
2124 *np = n->next;
2125 n->dead = 1;
2126 } else
2127 np = &n->next;
2128 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -07002129 if (release)
2130 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 }
2132 }
2133}
2134EXPORT_SYMBOL(__neigh_for_each_release);
2135
2136#ifdef CONFIG_PROC_FS
2137
2138static struct neighbour *neigh_get_first(struct seq_file *seq)
2139{
2140 struct neigh_seq_state *state = seq->private;
Denis V. Lunev42508462008-01-10 03:53:12 -08002141 struct net *net = state->p.net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 struct neigh_table *tbl = state->tbl;
2143 struct neighbour *n = NULL;
2144 int bucket = state->bucket;
2145
2146 state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
2147 for (bucket = 0; bucket <= tbl->hash_mask; bucket++) {
2148 n = tbl->hash_buckets[bucket];
2149
2150 while (n) {
Eric W. Biederman426b5302008-01-24 00:13:18 -08002151 if (n->dev->nd_net != net)
2152 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 if (state->neigh_sub_iter) {
2154 loff_t fakep = 0;
2155 void *v;
2156
2157 v = state->neigh_sub_iter(state, n, &fakep);
2158 if (!v)
2159 goto next;
2160 }
2161 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2162 break;
2163 if (n->nud_state & ~NUD_NOARP)
2164 break;
2165 next:
2166 n = n->next;
2167 }
2168
2169 if (n)
2170 break;
2171 }
2172 state->bucket = bucket;
2173
2174 return n;
2175}
2176
2177static struct neighbour *neigh_get_next(struct seq_file *seq,
2178 struct neighbour *n,
2179 loff_t *pos)
2180{
2181 struct neigh_seq_state *state = seq->private;
Denis V. Lunev42508462008-01-10 03:53:12 -08002182 struct net *net = state->p.net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 struct neigh_table *tbl = state->tbl;
2184
2185 if (state->neigh_sub_iter) {
2186 void *v = state->neigh_sub_iter(state, n, pos);
2187 if (v)
2188 return n;
2189 }
2190 n = n->next;
2191
2192 while (1) {
2193 while (n) {
Eric W. Biederman426b5302008-01-24 00:13:18 -08002194 if (n->dev->nd_net != net)
2195 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 if (state->neigh_sub_iter) {
2197 void *v = state->neigh_sub_iter(state, n, pos);
2198 if (v)
2199 return n;
2200 goto next;
2201 }
2202 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2203 break;
2204
2205 if (n->nud_state & ~NUD_NOARP)
2206 break;
2207 next:
2208 n = n->next;
2209 }
2210
2211 if (n)
2212 break;
2213
2214 if (++state->bucket > tbl->hash_mask)
2215 break;
2216
2217 n = tbl->hash_buckets[state->bucket];
2218 }
2219
2220 if (n && pos)
2221 --(*pos);
2222 return n;
2223}
2224
2225static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
2226{
2227 struct neighbour *n = neigh_get_first(seq);
2228
2229 if (n) {
2230 while (*pos) {
2231 n = neigh_get_next(seq, n, pos);
2232 if (!n)
2233 break;
2234 }
2235 }
2236 return *pos ? NULL : n;
2237}
2238
2239static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
2240{
2241 struct neigh_seq_state *state = seq->private;
Denis V. Lunev42508462008-01-10 03:53:12 -08002242 struct net * net = state->p.net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 struct neigh_table *tbl = state->tbl;
2244 struct pneigh_entry *pn = NULL;
2245 int bucket = state->bucket;
2246
2247 state->flags |= NEIGH_SEQ_IS_PNEIGH;
2248 for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
2249 pn = tbl->phash_buckets[bucket];
Eric W. Biederman426b5302008-01-24 00:13:18 -08002250 while (pn && (pn->net != net))
2251 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 if (pn)
2253 break;
2254 }
2255 state->bucket = bucket;
2256
2257 return pn;
2258}
2259
2260static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
2261 struct pneigh_entry *pn,
2262 loff_t *pos)
2263{
2264 struct neigh_seq_state *state = seq->private;
Denis V. Lunev42508462008-01-10 03:53:12 -08002265 struct net * net = state->p.net;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 struct neigh_table *tbl = state->tbl;
2267
2268 pn = pn->next;
2269 while (!pn) {
2270 if (++state->bucket > PNEIGH_HASHMASK)
2271 break;
2272 pn = tbl->phash_buckets[state->bucket];
Eric W. Biederman426b5302008-01-24 00:13:18 -08002273 while (pn && (pn->net != net))
2274 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 if (pn)
2276 break;
2277 }
2278
2279 if (pn && pos)
2280 --(*pos);
2281
2282 return pn;
2283}
2284
2285static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
2286{
2287 struct pneigh_entry *pn = pneigh_get_first(seq);
2288
2289 if (pn) {
2290 while (*pos) {
2291 pn = pneigh_get_next(seq, pn, pos);
2292 if (!pn)
2293 break;
2294 }
2295 }
2296 return *pos ? NULL : pn;
2297}
2298
2299static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
2300{
2301 struct neigh_seq_state *state = seq->private;
2302 void *rc;
2303
2304 rc = neigh_get_idx(seq, pos);
2305 if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
2306 rc = pneigh_get_idx(seq, pos);
2307
2308 return rc;
2309}
2310
2311void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
Eric Dumazet9a429c42008-01-01 21:58:02 -08002312 __acquires(tbl->lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313{
2314 struct neigh_seq_state *state = seq->private;
2315 loff_t pos_minus_one;
2316
2317 state->tbl = tbl;
2318 state->bucket = 0;
2319 state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
2320
2321 read_lock_bh(&tbl->lock);
2322
2323 pos_minus_one = *pos - 1;
2324 return *pos ? neigh_get_idx_any(seq, &pos_minus_one) : SEQ_START_TOKEN;
2325}
2326EXPORT_SYMBOL(neigh_seq_start);
2327
2328void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2329{
2330 struct neigh_seq_state *state;
2331 void *rc;
2332
2333 if (v == SEQ_START_TOKEN) {
2334 rc = neigh_get_idx(seq, pos);
2335 goto out;
2336 }
2337
2338 state = seq->private;
2339 if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
2340 rc = neigh_get_next(seq, v, NULL);
2341 if (rc)
2342 goto out;
2343 if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
2344 rc = pneigh_get_first(seq);
2345 } else {
2346 BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
2347 rc = pneigh_get_next(seq, v, NULL);
2348 }
2349out:
2350 ++(*pos);
2351 return rc;
2352}
2353EXPORT_SYMBOL(neigh_seq_next);
2354
2355void neigh_seq_stop(struct seq_file *seq, void *v)
Eric Dumazet9a429c42008-01-01 21:58:02 -08002356 __releases(tbl->lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357{
2358 struct neigh_seq_state *state = seq->private;
2359 struct neigh_table *tbl = state->tbl;
2360
2361 read_unlock_bh(&tbl->lock);
2362}
2363EXPORT_SYMBOL(neigh_seq_stop);
2364
2365/* statistics via seq_file */
2366
2367static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
2368{
2369 struct proc_dir_entry *pde = seq->private;
2370 struct neigh_table *tbl = pde->data;
2371 int cpu;
2372
2373 if (*pos == 0)
2374 return SEQ_START_TOKEN;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002375
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) {
2377 if (!cpu_possible(cpu))
2378 continue;
2379 *pos = cpu+1;
2380 return per_cpu_ptr(tbl->stats, cpu);
2381 }
2382 return NULL;
2383}
2384
2385static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2386{
2387 struct proc_dir_entry *pde = seq->private;
2388 struct neigh_table *tbl = pde->data;
2389 int cpu;
2390
2391 for (cpu = *pos; cpu < NR_CPUS; ++cpu) {
2392 if (!cpu_possible(cpu))
2393 continue;
2394 *pos = cpu+1;
2395 return per_cpu_ptr(tbl->stats, cpu);
2396 }
2397 return NULL;
2398}
2399
2400static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
2401{
2402
2403}
2404
2405static int neigh_stat_seq_show(struct seq_file *seq, void *v)
2406{
2407 struct proc_dir_entry *pde = seq->private;
2408 struct neigh_table *tbl = pde->data;
2409 struct neigh_statistics *st = v;
2410
2411 if (v == SEQ_START_TOKEN) {
Olaf Rempel5bec0032005-04-28 12:16:08 -07002412 seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 return 0;
2414 }
2415
2416 seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
2417 "%08lx %08lx %08lx %08lx\n",
2418 atomic_read(&tbl->entries),
2419
2420 st->allocs,
2421 st->destroys,
2422 st->hash_grows,
2423
2424 st->lookups,
2425 st->hits,
2426
2427 st->res_failed,
2428
2429 st->rcv_probes_mcast,
2430 st->rcv_probes_ucast,
2431
2432 st->periodic_gc_runs,
2433 st->forced_gc_runs
2434 );
2435
2436 return 0;
2437}
2438
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002439static const struct seq_operations neigh_stat_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 .start = neigh_stat_seq_start,
2441 .next = neigh_stat_seq_next,
2442 .stop = neigh_stat_seq_stop,
2443 .show = neigh_stat_seq_show,
2444};
2445
2446static int neigh_stat_seq_open(struct inode *inode, struct file *file)
2447{
2448 int ret = seq_open(file, &neigh_stat_seq_ops);
2449
2450 if (!ret) {
2451 struct seq_file *sf = file->private_data;
2452 sf->private = PDE(inode);
2453 }
2454 return ret;
2455};
2456
Arjan van de Ven9a321442007-02-12 00:55:35 -08002457static const struct file_operations neigh_stat_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 .owner = THIS_MODULE,
2459 .open = neigh_stat_seq_open,
2460 .read = seq_read,
2461 .llseek = seq_lseek,
2462 .release = seq_release,
2463};
2464
2465#endif /* CONFIG_PROC_FS */
2466
Thomas Graf339bf982006-11-10 14:10:15 -08002467static inline size_t neigh_nlmsg_size(void)
2468{
2469 return NLMSG_ALIGN(sizeof(struct ndmsg))
2470 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2471 + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2472 + nla_total_size(sizeof(struct nda_cacheinfo))
2473 + nla_total_size(4); /* NDA_PROBES */
2474}
2475
Thomas Grafb8673312006-08-15 00:33:14 -07002476static void __neigh_notify(struct neighbour *n, int type, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477{
Eric W. Biederman426b5302008-01-24 00:13:18 -08002478 struct net *net = n->dev->nd_net;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002479 struct sk_buff *skb;
Thomas Grafb8673312006-08-15 00:33:14 -07002480 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481
Thomas Graf339bf982006-11-10 14:10:15 -08002482 skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002483 if (skb == NULL)
Thomas Grafb8673312006-08-15 00:33:14 -07002484 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485
Thomas Grafb8673312006-08-15 00:33:14 -07002486 err = neigh_fill_info(skb, n, 0, 0, type, flags);
Patrick McHardy26932562007-01-31 23:16:40 -08002487 if (err < 0) {
2488 /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
2489 WARN_ON(err == -EMSGSIZE);
2490 kfree_skb(skb);
2491 goto errout;
2492 }
Eric W. Biederman426b5302008-01-24 00:13:18 -08002493 err = rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
Thomas Grafb8673312006-08-15 00:33:14 -07002494errout:
2495 if (err < 0)
Eric W. Biederman426b5302008-01-24 00:13:18 -08002496 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
Thomas Grafb8673312006-08-15 00:33:14 -07002497}
2498
Thomas Grafd961db32007-08-08 23:12:56 -07002499#ifdef CONFIG_ARPD
Thomas Grafb8673312006-08-15 00:33:14 -07002500void neigh_app_ns(struct neighbour *n)
2501{
2502 __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504#endif /* CONFIG_ARPD */
2505
2506#ifdef CONFIG_SYSCTL
2507
2508static struct neigh_sysctl_table {
2509 struct ctl_table_header *sysctl_header;
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002510 struct ctl_table neigh_vars[__NET_NEIGH_MAX];
2511 char *dev_name;
Brian Haleyab32ea52006-09-22 14:15:41 -07002512} neigh_sysctl_template __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 .neigh_vars = {
2514 {
2515 .ctl_name = NET_NEIGH_MCAST_SOLICIT,
2516 .procname = "mcast_solicit",
2517 .maxlen = sizeof(int),
2518 .mode = 0644,
2519 .proc_handler = &proc_dointvec,
2520 },
2521 {
2522 .ctl_name = NET_NEIGH_UCAST_SOLICIT,
2523 .procname = "ucast_solicit",
2524 .maxlen = sizeof(int),
2525 .mode = 0644,
2526 .proc_handler = &proc_dointvec,
2527 },
2528 {
2529 .ctl_name = NET_NEIGH_APP_SOLICIT,
2530 .procname = "app_solicit",
2531 .maxlen = sizeof(int),
2532 .mode = 0644,
2533 .proc_handler = &proc_dointvec,
2534 },
2535 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 .procname = "retrans_time",
2537 .maxlen = sizeof(int),
2538 .mode = 0644,
2539 .proc_handler = &proc_dointvec_userhz_jiffies,
2540 },
2541 {
2542 .ctl_name = NET_NEIGH_REACHABLE_TIME,
2543 .procname = "base_reachable_time",
2544 .maxlen = sizeof(int),
2545 .mode = 0644,
2546 .proc_handler = &proc_dointvec_jiffies,
2547 .strategy = &sysctl_jiffies,
2548 },
2549 {
2550 .ctl_name = NET_NEIGH_DELAY_PROBE_TIME,
2551 .procname = "delay_first_probe_time",
2552 .maxlen = sizeof(int),
2553 .mode = 0644,
2554 .proc_handler = &proc_dointvec_jiffies,
2555 .strategy = &sysctl_jiffies,
2556 },
2557 {
2558 .ctl_name = NET_NEIGH_GC_STALE_TIME,
2559 .procname = "gc_stale_time",
2560 .maxlen = sizeof(int),
2561 .mode = 0644,
2562 .proc_handler = &proc_dointvec_jiffies,
2563 .strategy = &sysctl_jiffies,
2564 },
2565 {
2566 .ctl_name = NET_NEIGH_UNRES_QLEN,
2567 .procname = "unres_qlen",
2568 .maxlen = sizeof(int),
2569 .mode = 0644,
2570 .proc_handler = &proc_dointvec,
2571 },
2572 {
2573 .ctl_name = NET_NEIGH_PROXY_QLEN,
2574 .procname = "proxy_qlen",
2575 .maxlen = sizeof(int),
2576 .mode = 0644,
2577 .proc_handler = &proc_dointvec,
2578 },
2579 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 .procname = "anycast_delay",
2581 .maxlen = sizeof(int),
2582 .mode = 0644,
2583 .proc_handler = &proc_dointvec_userhz_jiffies,
2584 },
2585 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 .procname = "proxy_delay",
2587 .maxlen = sizeof(int),
2588 .mode = 0644,
2589 .proc_handler = &proc_dointvec_userhz_jiffies,
2590 },
2591 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 .procname = "locktime",
2593 .maxlen = sizeof(int),
2594 .mode = 0644,
2595 .proc_handler = &proc_dointvec_userhz_jiffies,
2596 },
2597 {
Eric W. Biedermand12af672007-10-18 03:05:25 -07002598 .ctl_name = NET_NEIGH_RETRANS_TIME_MS,
2599 .procname = "retrans_time_ms",
2600 .maxlen = sizeof(int),
2601 .mode = 0644,
2602 .proc_handler = &proc_dointvec_ms_jiffies,
2603 .strategy = &sysctl_ms_jiffies,
2604 },
2605 {
2606 .ctl_name = NET_NEIGH_REACHABLE_TIME_MS,
2607 .procname = "base_reachable_time_ms",
2608 .maxlen = sizeof(int),
2609 .mode = 0644,
2610 .proc_handler = &proc_dointvec_ms_jiffies,
2611 .strategy = &sysctl_ms_jiffies,
2612 },
2613 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 .ctl_name = NET_NEIGH_GC_INTERVAL,
2615 .procname = "gc_interval",
2616 .maxlen = sizeof(int),
2617 .mode = 0644,
2618 .proc_handler = &proc_dointvec_jiffies,
2619 .strategy = &sysctl_jiffies,
2620 },
2621 {
2622 .ctl_name = NET_NEIGH_GC_THRESH1,
2623 .procname = "gc_thresh1",
2624 .maxlen = sizeof(int),
2625 .mode = 0644,
2626 .proc_handler = &proc_dointvec,
2627 },
2628 {
2629 .ctl_name = NET_NEIGH_GC_THRESH2,
2630 .procname = "gc_thresh2",
2631 .maxlen = sizeof(int),
2632 .mode = 0644,
2633 .proc_handler = &proc_dointvec,
2634 },
2635 {
2636 .ctl_name = NET_NEIGH_GC_THRESH3,
2637 .procname = "gc_thresh3",
2638 .maxlen = sizeof(int),
2639 .mode = 0644,
2640 .proc_handler = &proc_dointvec,
2641 },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002642 {},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 },
2644};
2645
2646int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002647 int p_id, int pdev_id, char *p_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 proc_handler *handler, ctl_handler *strategy)
2649{
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002650 struct neigh_sysctl_table *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 const char *dev_name_source = NULL;
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002652
2653#define NEIGH_CTL_PATH_ROOT 0
2654#define NEIGH_CTL_PATH_PROTO 1
2655#define NEIGH_CTL_PATH_NEIGH 2
2656#define NEIGH_CTL_PATH_DEV 3
2657
2658 struct ctl_path neigh_path[] = {
2659 { .procname = "net", .ctl_name = CTL_NET, },
2660 { .procname = "proto", .ctl_name = 0, },
2661 { .procname = "neigh", .ctl_name = 0, },
2662 { .procname = "default", .ctl_name = NET_PROTO_CONF_DEFAULT, },
2663 { },
2664 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002666 t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 if (!t)
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002668 goto err;
2669
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 t->neigh_vars[0].data = &p->mcast_probes;
2671 t->neigh_vars[1].data = &p->ucast_probes;
2672 t->neigh_vars[2].data = &p->app_probes;
2673 t->neigh_vars[3].data = &p->retrans_time;
2674 t->neigh_vars[4].data = &p->base_reachable_time;
2675 t->neigh_vars[5].data = &p->delay_probe_time;
2676 t->neigh_vars[6].data = &p->gc_staletime;
2677 t->neigh_vars[7].data = &p->queue_len;
2678 t->neigh_vars[8].data = &p->proxy_qlen;
2679 t->neigh_vars[9].data = &p->anycast_delay;
2680 t->neigh_vars[10].data = &p->proxy_delay;
2681 t->neigh_vars[11].data = &p->locktime;
Eric W. Biedermand12af672007-10-18 03:05:25 -07002682 t->neigh_vars[12].data = &p->retrans_time;
2683 t->neigh_vars[13].data = &p->base_reachable_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
2685 if (dev) {
2686 dev_name_source = dev->name;
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002687 neigh_path[NEIGH_CTL_PATH_DEV].ctl_name = dev->ifindex;
Eric W. Biedermand12af672007-10-18 03:05:25 -07002688 /* Terminate the table early */
2689 memset(&t->neigh_vars[14], 0, sizeof(t->neigh_vars[14]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 } else {
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002691 dev_name_source = neigh_path[NEIGH_CTL_PATH_DEV].procname;
Eric W. Biedermand12af672007-10-18 03:05:25 -07002692 t->neigh_vars[14].data = (int *)(p + 1);
2693 t->neigh_vars[15].data = (int *)(p + 1) + 1;
2694 t->neigh_vars[16].data = (int *)(p + 1) + 2;
2695 t->neigh_vars[17].data = (int *)(p + 1) + 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 }
2697
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698
2699 if (handler || strategy) {
2700 /* RetransTime */
2701 t->neigh_vars[3].proc_handler = handler;
2702 t->neigh_vars[3].strategy = strategy;
2703 t->neigh_vars[3].extra1 = dev;
Eric W. Biedermand12af672007-10-18 03:05:25 -07002704 if (!strategy)
2705 t->neigh_vars[3].ctl_name = CTL_UNNUMBERED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 /* ReachableTime */
2707 t->neigh_vars[4].proc_handler = handler;
2708 t->neigh_vars[4].strategy = strategy;
2709 t->neigh_vars[4].extra1 = dev;
Eric W. Biedermand12af672007-10-18 03:05:25 -07002710 if (!strategy)
2711 t->neigh_vars[4].ctl_name = CTL_UNNUMBERED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 /* RetransTime (in milliseconds)*/
Eric W. Biedermand12af672007-10-18 03:05:25 -07002713 t->neigh_vars[12].proc_handler = handler;
2714 t->neigh_vars[12].strategy = strategy;
2715 t->neigh_vars[12].extra1 = dev;
2716 if (!strategy)
2717 t->neigh_vars[12].ctl_name = CTL_UNNUMBERED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 /* ReachableTime (in milliseconds) */
Eric W. Biedermand12af672007-10-18 03:05:25 -07002719 t->neigh_vars[13].proc_handler = handler;
2720 t->neigh_vars[13].strategy = strategy;
2721 t->neigh_vars[13].extra1 = dev;
2722 if (!strategy)
2723 t->neigh_vars[13].ctl_name = CTL_UNNUMBERED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 }
2725
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002726 t->dev_name = kstrdup(dev_name_source, GFP_KERNEL);
2727 if (!t->dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002730 neigh_path[NEIGH_CTL_PATH_DEV].procname = t->dev_name;
2731 neigh_path[NEIGH_CTL_PATH_NEIGH].ctl_name = pdev_id;
2732 neigh_path[NEIGH_CTL_PATH_PROTO].procname = p_name;
2733 neigh_path[NEIGH_CTL_PATH_PROTO].ctl_name = p_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002735 t->sysctl_header = register_sysctl_paths(neigh_path, t->neigh_vars);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002736 if (!t->sysctl_header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 goto free_procname;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002738
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 p->sysctl_table = t;
2740 return 0;
2741
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002742free_procname:
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002743 kfree(t->dev_name);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002744free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 kfree(t);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002746err:
2747 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748}
2749
2750void neigh_sysctl_unregister(struct neigh_parms *p)
2751{
2752 if (p->sysctl_table) {
2753 struct neigh_sysctl_table *t = p->sysctl_table;
2754 p->sysctl_table = NULL;
2755 unregister_sysctl_table(t->sysctl_header);
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002756 kfree(t->dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 kfree(t);
2758 }
2759}
2760
2761#endif /* CONFIG_SYSCTL */
2762
Thomas Grafc8822a42007-03-22 11:50:06 -07002763static int __init neigh_init(void)
2764{
2765 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL);
2766 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL);
2767 rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info);
2768
2769 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info);
2770 rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL);
2771
2772 return 0;
2773}
2774
2775subsys_initcall(neigh_init);
2776
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777EXPORT_SYMBOL(__neigh_event_send);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778EXPORT_SYMBOL(neigh_changeaddr);
2779EXPORT_SYMBOL(neigh_compat_output);
2780EXPORT_SYMBOL(neigh_connected_output);
2781EXPORT_SYMBOL(neigh_create);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782EXPORT_SYMBOL(neigh_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783EXPORT_SYMBOL(neigh_event_ns);
2784EXPORT_SYMBOL(neigh_ifdown);
2785EXPORT_SYMBOL(neigh_lookup);
2786EXPORT_SYMBOL(neigh_lookup_nodev);
2787EXPORT_SYMBOL(neigh_parms_alloc);
2788EXPORT_SYMBOL(neigh_parms_release);
2789EXPORT_SYMBOL(neigh_rand_reach_time);
2790EXPORT_SYMBOL(neigh_resolve_output);
2791EXPORT_SYMBOL(neigh_table_clear);
2792EXPORT_SYMBOL(neigh_table_init);
Simon Kelleybd89efc2006-05-12 14:56:08 -07002793EXPORT_SYMBOL(neigh_table_init_no_netlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794EXPORT_SYMBOL(neigh_update);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795EXPORT_SYMBOL(pneigh_enqueue);
2796EXPORT_SYMBOL(pneigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797
2798#ifdef CONFIG_ARPD
2799EXPORT_SYMBOL(neigh_app_ns);
2800#endif
2801#ifdef CONFIG_SYSCTL
2802EXPORT_SYMBOL(neigh_sysctl_register);
2803EXPORT_SYMBOL(neigh_sysctl_unregister);
2804#endif