blob: d102f6d9abdcf7878d73cc75a9f1b23fc84ed4d0 [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);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63static struct neigh_table *neigh_tables;
Amos Waterland45fc3b12005-09-24 16:53:16 -070064#ifdef CONFIG_PROC_FS
Arjan van de Ven9a321442007-02-12 00:55:35 -080065static const struct file_operations neigh_stat_seq_fops;
Amos Waterland45fc3b12005-09-24 16:53:16 -070066#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68/*
69 Neighbour hash table buckets are protected with rwlock tbl->lock.
70
71 - All the scans/updates to hash buckets MUST be made under this lock.
72 - NOTHING clever should be made under this lock: no callbacks
73 to protocol backends, no attempts to send something to network.
74 It will result in deadlocks, if backend/driver wants to use neighbour
75 cache.
76 - If the entry requires some non-trivial actions, increase
77 its reference count and release table lock.
78
79 Neighbour entries are protected:
80 - with reference count.
81 - with rwlock neigh->lock
82
83 Reference count prevents destruction.
84
85 neigh->lock mainly serializes ll address data and its validity state.
86 However, the same lock is used to protect another entry fields:
87 - timer
88 - resolution queue
89
90 Again, nothing clever shall be made under neigh->lock,
91 the most complicated procedure, which we allow is dev->hard_header.
92 It is supposed, that dev->hard_header is simplistic and does
93 not make callbacks to neighbour tables.
94
95 The last lock is neigh_tbl_lock. It is pure SMP lock, protecting
96 list of neighbour tables. This list is used only in process context,
97 */
98
99static DEFINE_RWLOCK(neigh_tbl_lock);
100
101static int neigh_blackhole(struct sk_buff *skb)
102{
103 kfree_skb(skb);
104 return -ENETDOWN;
105}
106
Thomas Graf4f494552007-08-08 23:12:36 -0700107static void neigh_cleanup_and_release(struct neighbour *neigh)
108{
109 if (neigh->parms->neigh_cleanup)
110 neigh->parms->neigh_cleanup(neigh);
111
Thomas Grafd961db32007-08-08 23:12:56 -0700112 __neigh_notify(neigh, RTM_DELNEIGH, 0);
Thomas Graf4f494552007-08-08 23:12:36 -0700113 neigh_release(neigh);
114}
115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116/*
117 * It is random distribution in the interval (1/2)*base...(3/2)*base.
118 * It corresponds to default IPv6 settings and is not overridable,
119 * because it is really reasonable choice.
120 */
121
122unsigned long neigh_rand_reach_time(unsigned long base)
123{
124 return (base ? (net_random() % base) + (base >> 1) : 0);
125}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900126EXPORT_SYMBOL(neigh_rand_reach_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128
129static int neigh_forced_gc(struct neigh_table *tbl)
130{
131 int shrunk = 0;
132 int i;
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}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900245EXPORT_SYMBOL(neigh_changeaddr);
Herbert Xu49636bb2005-10-23 17:18:00 +1000246
247int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
248{
249 write_lock_bh(&tbl->lock);
250 neigh_flush_dev(tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 pneigh_ifdown(tbl, dev);
252 write_unlock_bh(&tbl->lock);
253
254 del_timer_sync(&tbl->proxy_timer);
255 pneigh_queue_purge(&tbl->proxy_queue);
256 return 0;
257}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900258EXPORT_SYMBOL(neigh_ifdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
260static struct neighbour *neigh_alloc(struct neigh_table *tbl)
261{
262 struct neighbour *n = NULL;
263 unsigned long now = jiffies;
264 int entries;
265
266 entries = atomic_inc_return(&tbl->entries) - 1;
267 if (entries >= tbl->gc_thresh3 ||
268 (entries >= tbl->gc_thresh2 &&
269 time_after(now, tbl->last_flush + 5 * HZ))) {
270 if (!neigh_forced_gc(tbl) &&
271 entries >= tbl->gc_thresh3)
272 goto out_entries;
273 }
274
Robert P. J. Dayc3762222007-02-10 01:45:03 -0800275 n = kmem_cache_zalloc(tbl->kmem_cachep, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 if (!n)
277 goto out_entries;
278
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 skb_queue_head_init(&n->arp_queue);
280 rwlock_init(&n->lock);
281 n->updated = n->used = now;
282 n->nud_state = NUD_NONE;
283 n->output = neigh_blackhole;
284 n->parms = neigh_parms_clone(&tbl->parms);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800285 setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 NEIGH_CACHE_STAT_INC(tbl, allocs);
288 n->tbl = tbl;
289 atomic_set(&n->refcnt, 1);
290 n->dead = 1;
291out:
292 return n;
293
294out_entries:
295 atomic_dec(&tbl->entries);
296 goto out;
297}
298
299static struct neighbour **neigh_hash_alloc(unsigned int entries)
300{
301 unsigned long size = entries * sizeof(struct neighbour *);
302 struct neighbour **ret;
303
304 if (size <= PAGE_SIZE) {
Andrew Morton77d04bd2006-04-07 14:52:59 -0700305 ret = kzalloc(size, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 } else {
307 ret = (struct neighbour **)
Andrew Morton77d04bd2006-04-07 14:52:59 -0700308 __get_free_pages(GFP_ATOMIC|__GFP_ZERO, get_order(size));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 return ret;
311}
312
313static void neigh_hash_free(struct neighbour **hash, unsigned int entries)
314{
315 unsigned long size = entries * sizeof(struct neighbour *);
316
317 if (size <= PAGE_SIZE)
318 kfree(hash);
319 else
320 free_pages((unsigned long)hash, get_order(size));
321}
322
323static void neigh_hash_grow(struct neigh_table *tbl, unsigned long new_entries)
324{
325 struct neighbour **new_hash, **old_hash;
326 unsigned int i, new_hash_mask, old_entries;
327
328 NEIGH_CACHE_STAT_INC(tbl, hash_grows);
329
vignesh babuc3609d52007-08-24 22:27:55 -0700330 BUG_ON(!is_power_of_2(new_entries));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 new_hash = neigh_hash_alloc(new_entries);
332 if (!new_hash)
333 return;
334
335 old_entries = tbl->hash_mask + 1;
336 new_hash_mask = new_entries - 1;
337 old_hash = tbl->hash_buckets;
338
339 get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd));
340 for (i = 0; i < old_entries; i++) {
341 struct neighbour *n, *next;
342
343 for (n = old_hash[i]; n; n = next) {
344 unsigned int hash_val = tbl->hash(n->primary_key, n->dev);
345
346 hash_val &= new_hash_mask;
347 next = n->next;
348
349 n->next = new_hash[hash_val];
350 new_hash[hash_val] = n;
351 }
352 }
353 tbl->hash_buckets = new_hash;
354 tbl->hash_mask = new_hash_mask;
355
356 neigh_hash_free(old_hash, old_entries);
357}
358
359struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
360 struct net_device *dev)
361{
362 struct neighbour *n;
363 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800364 u32 hash_val;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 NEIGH_CACHE_STAT_INC(tbl, lookups);
367
368 read_lock_bh(&tbl->lock);
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800369 hash_val = tbl->hash(pkey, dev);
Julian Anastasovc5e29462006-10-03 15:49:46 -0700370 for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
372 neigh_hold(n);
373 NEIGH_CACHE_STAT_INC(tbl, hits);
374 break;
375 }
376 }
377 read_unlock_bh(&tbl->lock);
378 return n;
379}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900380EXPORT_SYMBOL(neigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Eric W. Biederman426b5302008-01-24 00:13:18 -0800382struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
383 const void *pkey)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
385 struct neighbour *n;
386 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800387 u32 hash_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
389 NEIGH_CACHE_STAT_INC(tbl, lookups);
390
391 read_lock_bh(&tbl->lock);
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800392 hash_val = tbl->hash(pkey, NULL);
Julian Anastasovc5e29462006-10-03 15:49:46 -0700393 for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800394 if (!memcmp(n->primary_key, pkey, key_len) &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900395 net_eq(dev_net(n->dev), net)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 neigh_hold(n);
397 NEIGH_CACHE_STAT_INC(tbl, hits);
398 break;
399 }
400 }
401 read_unlock_bh(&tbl->lock);
402 return n;
403}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900404EXPORT_SYMBOL(neigh_lookup_nodev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
406struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
407 struct net_device *dev)
408{
409 u32 hash_val;
410 int key_len = tbl->key_len;
411 int error;
412 struct neighbour *n1, *rc, *n = neigh_alloc(tbl);
413
414 if (!n) {
415 rc = ERR_PTR(-ENOBUFS);
416 goto out;
417 }
418
419 memcpy(n->primary_key, pkey, key_len);
420 n->dev = dev;
421 dev_hold(dev);
422
423 /* Protocol specific setup. */
424 if (tbl->constructor && (error = tbl->constructor(n)) < 0) {
425 rc = ERR_PTR(error);
426 goto out_neigh_release;
427 }
428
429 /* Device specific setup. */
430 if (n->parms->neigh_setup &&
431 (error = n->parms->neigh_setup(n)) < 0) {
432 rc = ERR_PTR(error);
433 goto out_neigh_release;
434 }
435
436 n->confirmed = jiffies - (n->parms->base_reachable_time << 1);
437
438 write_lock_bh(&tbl->lock);
439
440 if (atomic_read(&tbl->entries) > (tbl->hash_mask + 1))
441 neigh_hash_grow(tbl, (tbl->hash_mask + 1) << 1);
442
443 hash_val = tbl->hash(pkey, dev) & tbl->hash_mask;
444
445 if (n->parms->dead) {
446 rc = ERR_PTR(-EINVAL);
447 goto out_tbl_unlock;
448 }
449
450 for (n1 = tbl->hash_buckets[hash_val]; n1; n1 = n1->next) {
451 if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
452 neigh_hold(n1);
453 rc = n1;
454 goto out_tbl_unlock;
455 }
456 }
457
458 n->next = tbl->hash_buckets[hash_val];
459 tbl->hash_buckets[hash_val] = n;
460 n->dead = 0;
461 neigh_hold(n);
462 write_unlock_bh(&tbl->lock);
463 NEIGH_PRINTK2("neigh %p is created.\n", n);
464 rc = n;
465out:
466 return rc;
467out_tbl_unlock:
468 write_unlock_bh(&tbl->lock);
469out_neigh_release:
470 neigh_release(n);
471 goto out;
472}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900473EXPORT_SYMBOL(neigh_create);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900475static u32 pneigh_hash(const void *pkey, int key_len)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700476{
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700477 u32 hash_val = *(u32 *)(pkey + key_len - 4);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700478 hash_val ^= (hash_val >> 16);
479 hash_val ^= hash_val >> 8;
480 hash_val ^= hash_val >> 4;
481 hash_val &= PNEIGH_HASHMASK;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900482 return hash_val;
483}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700484
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900485static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
486 struct net *net,
487 const void *pkey,
488 int key_len,
489 struct net_device *dev)
490{
491 while (n) {
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700492 if (!memcmp(n->key, pkey, key_len) &&
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900493 net_eq(pneigh_net(n), net) &&
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700494 (n->dev == dev || !n->dev))
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900495 return n;
496 n = n->next;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700497 }
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900498 return NULL;
499}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700500
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900501struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
502 struct net *net, const void *pkey, struct net_device *dev)
503{
504 int key_len = tbl->key_len;
505 u32 hash_val = pneigh_hash(pkey, key_len);
506
507 return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
508 net, pkey, key_len, dev);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700509}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900510EXPORT_SYMBOL_GPL(__pneigh_lookup);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700511
Eric W. Biederman426b5302008-01-24 00:13:18 -0800512struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
513 struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 struct net_device *dev, int creat)
515{
516 struct pneigh_entry *n;
517 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900518 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
520 read_lock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900521 n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
522 net, pkey, key_len, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 read_unlock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900524
525 if (n || !creat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 goto out;
527
Pavel Emelyanov4ae28942007-10-15 12:54:15 -0700528 ASSERT_RTNL();
529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
531 if (!n)
532 goto out;
533
Eric Dumazete42ea982008-11-12 00:54:54 -0800534 write_pnet(&n->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 memcpy(n->key, pkey, key_len);
536 n->dev = dev;
537 if (dev)
538 dev_hold(dev);
539
540 if (tbl->pconstructor && tbl->pconstructor(n)) {
541 if (dev)
542 dev_put(dev);
Denis V. Lunevda12f732008-02-20 00:26:16 -0800543 release_net(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 kfree(n);
545 n = NULL;
546 goto out;
547 }
548
549 write_lock_bh(&tbl->lock);
550 n->next = tbl->phash_buckets[hash_val];
551 tbl->phash_buckets[hash_val] = n;
552 write_unlock_bh(&tbl->lock);
553out:
554 return n;
555}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900556EXPORT_SYMBOL(pneigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557
558
Eric W. Biederman426b5302008-01-24 00:13:18 -0800559int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 struct net_device *dev)
561{
562 struct pneigh_entry *n, **np;
563 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900564 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
566 write_lock_bh(&tbl->lock);
567 for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
568 np = &n->next) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800569 if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900570 net_eq(pneigh_net(n), net)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 *np = n->next;
572 write_unlock_bh(&tbl->lock);
573 if (tbl->pdestructor)
574 tbl->pdestructor(n);
575 if (n->dev)
576 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900577 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 kfree(n);
579 return 0;
580 }
581 }
582 write_unlock_bh(&tbl->lock);
583 return -ENOENT;
584}
585
586static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
587{
588 struct pneigh_entry *n, **np;
589 u32 h;
590
591 for (h = 0; h <= PNEIGH_HASHMASK; h++) {
592 np = &tbl->phash_buckets[h];
593 while ((n = *np) != NULL) {
594 if (!dev || n->dev == dev) {
595 *np = n->next;
596 if (tbl->pdestructor)
597 tbl->pdestructor(n);
598 if (n->dev)
599 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900600 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 kfree(n);
602 continue;
603 }
604 np = &n->next;
605 }
606 }
607 return -ENOENT;
608}
609
Denis V. Lunev06f05112008-01-24 00:30:58 -0800610static void neigh_parms_destroy(struct neigh_parms *parms);
611
612static inline void neigh_parms_put(struct neigh_parms *parms)
613{
614 if (atomic_dec_and_test(&parms->refcnt))
615 neigh_parms_destroy(parms);
616}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618/*
619 * neighbour must already be out of the table;
620 *
621 */
622void neigh_destroy(struct neighbour *neigh)
623{
624 struct hh_cache *hh;
625
626 NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
627
628 if (!neigh->dead) {
629 printk(KERN_WARNING
630 "Destroying alive neighbour %p\n", neigh);
631 dump_stack();
632 return;
633 }
634
635 if (neigh_del_timer(neigh))
636 printk(KERN_WARNING "Impossible event.\n");
637
638 while ((hh = neigh->hh) != NULL) {
639 neigh->hh = hh->hh_next;
640 hh->hh_next = NULL;
Stephen Hemminger3644f0c2006-12-07 15:08:17 -0800641
642 write_seqlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 hh->hh_output = neigh_blackhole;
Stephen Hemminger3644f0c2006-12-07 15:08:17 -0800644 write_sequnlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 if (atomic_dec_and_test(&hh->hh_refcnt))
646 kfree(hh);
647 }
648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 skb_queue_purge(&neigh->arp_queue);
650
651 dev_put(neigh->dev);
652 neigh_parms_put(neigh->parms);
653
654 NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh);
655
656 atomic_dec(&neigh->tbl->entries);
657 kmem_cache_free(neigh->tbl->kmem_cachep, neigh);
658}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900659EXPORT_SYMBOL(neigh_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
661/* Neighbour state is suspicious;
662 disable fast path.
663
664 Called with write_locked neigh.
665 */
666static void neigh_suspect(struct neighbour *neigh)
667{
668 struct hh_cache *hh;
669
670 NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
671
672 neigh->output = neigh->ops->output;
673
674 for (hh = neigh->hh; hh; hh = hh->hh_next)
675 hh->hh_output = neigh->ops->output;
676}
677
678/* Neighbour state is OK;
679 enable fast path.
680
681 Called with write_locked neigh.
682 */
683static void neigh_connect(struct neighbour *neigh)
684{
685 struct hh_cache *hh;
686
687 NEIGH_PRINTK2("neigh %p is connected.\n", neigh);
688
689 neigh->output = neigh->ops->connected_output;
690
691 for (hh = neigh->hh; hh; hh = hh->hh_next)
692 hh->hh_output = neigh->ops->hh_output;
693}
694
Eric Dumazete4c4e442009-07-30 03:15:07 +0000695static void neigh_periodic_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696{
Eric Dumazete4c4e442009-07-30 03:15:07 +0000697 struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 struct neighbour *n, **np;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000699 unsigned int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
701 NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
702
Eric Dumazete4c4e442009-07-30 03:15:07 +0000703 write_lock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705 /*
706 * periodically recompute ReachableTime from random function
707 */
708
Eric Dumazete4c4e442009-07-30 03:15:07 +0000709 if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 struct neigh_parms *p;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000711 tbl->last_rand = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 for (p = &tbl->parms; p; p = p->next)
713 p->reachable_time =
714 neigh_rand_reach_time(p->base_reachable_time);
715 }
716
Eric Dumazete4c4e442009-07-30 03:15:07 +0000717 for (i = 0 ; i <= tbl->hash_mask; i++) {
718 np = &tbl->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Eric Dumazete4c4e442009-07-30 03:15:07 +0000720 while ((n = *np) != NULL) {
721 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
Eric Dumazete4c4e442009-07-30 03:15:07 +0000723 write_lock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Eric Dumazete4c4e442009-07-30 03:15:07 +0000725 state = n->nud_state;
726 if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
727 write_unlock(&n->lock);
728 goto next_elt;
729 }
730
731 if (time_before(n->used, n->confirmed))
732 n->used = n->confirmed;
733
734 if (atomic_read(&n->refcnt) == 1 &&
735 (state == NUD_FAILED ||
736 time_after(jiffies, n->used + n->parms->gc_staletime))) {
737 *np = n->next;
738 n->dead = 1;
739 write_unlock(&n->lock);
740 neigh_cleanup_and_release(n);
741 continue;
742 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 write_unlock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
745next_elt:
Eric Dumazete4c4e442009-07-30 03:15:07 +0000746 np = &n->next;
747 }
748 /*
749 * It's fine to release lock here, even if hash table
750 * grows while we are preempted.
751 */
752 write_unlock_bh(&tbl->lock);
753 cond_resched();
754 write_lock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900756 /* Cycle through all hash buckets every base_reachable_time/2 ticks.
757 * ARP entry timeouts range from 1/2 base_reachable_time to 3/2
758 * base_reachable_time.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 */
Eric Dumazete4c4e442009-07-30 03:15:07 +0000760 schedule_delayed_work(&tbl->gc_work,
761 tbl->parms.base_reachable_time >> 1);
762 write_unlock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763}
764
765static __inline__ int neigh_max_probes(struct neighbour *n)
766{
767 struct neigh_parms *p = n->parms;
768 return (n->nud_state & NUD_PROBE ?
769 p->ucast_probes :
770 p->ucast_probes + p->app_probes + p->mcast_probes);
771}
772
Timo Teras5ef12d92009-06-11 04:16:28 -0700773static void neigh_invalidate(struct neighbour *neigh)
774{
775 struct sk_buff *skb;
776
777 NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
778 NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
779 neigh->updated = jiffies;
780
781 /* It is very thin place. report_unreachable is very complicated
782 routine. Particularly, it can hit the same neighbour entry!
783
784 So that, we try to be accurate and avoid dead loop. --ANK
785 */
786 while (neigh->nud_state == NUD_FAILED &&
787 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
788 write_unlock(&neigh->lock);
789 neigh->ops->error_report(neigh, skb);
790 write_lock(&neigh->lock);
791 }
792 skb_queue_purge(&neigh->arp_queue);
793}
794
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795/* Called when a timer expires for a neighbour entry. */
796
797static void neigh_timer_handler(unsigned long arg)
798{
799 unsigned long now, next;
800 struct neighbour *neigh = (struct neighbour *)arg;
801 unsigned state;
802 int notify = 0;
803
804 write_lock(&neigh->lock);
805
806 state = neigh->nud_state;
807 now = jiffies;
808 next = now + HZ;
809
810 if (!(state & NUD_IN_TIMER)) {
811#ifndef CONFIG_SMP
812 printk(KERN_WARNING "neigh: timer & !nud_in_timer\n");
813#endif
814 goto out;
815 }
816
817 if (state & NUD_REACHABLE) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900818 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 neigh->confirmed + neigh->parms->reachable_time)) {
820 NEIGH_PRINTK2("neigh %p is still alive.\n", neigh);
821 next = neigh->confirmed + neigh->parms->reachable_time;
822 } else if (time_before_eq(now,
823 neigh->used + neigh->parms->delay_probe_time)) {
824 NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
825 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800826 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 neigh_suspect(neigh);
828 next = now + neigh->parms->delay_probe_time;
829 } else {
830 NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
831 neigh->nud_state = NUD_STALE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800832 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 neigh_suspect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700834 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 }
836 } else if (state & NUD_DELAY) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900837 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 neigh->confirmed + neigh->parms->delay_probe_time)) {
839 NEIGH_PRINTK2("neigh %p is now reachable.\n", neigh);
840 neigh->nud_state = NUD_REACHABLE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800841 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 neigh_connect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700843 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 next = neigh->confirmed + neigh->parms->reachable_time;
845 } else {
846 NEIGH_PRINTK2("neigh %p is probed.\n", neigh);
847 neigh->nud_state = NUD_PROBE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800848 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 atomic_set(&neigh->probes, 0);
850 next = now + neigh->parms->retrans_time;
851 }
852 } else {
853 /* NUD_PROBE|NUD_INCOMPLETE */
854 next = now + neigh->parms->retrans_time;
855 }
856
857 if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
858 atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 neigh->nud_state = NUD_FAILED;
860 notify = 1;
Timo Teras5ef12d92009-06-11 04:16:28 -0700861 neigh_invalidate(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 }
863
864 if (neigh->nud_state & NUD_IN_TIMER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 if (time_before(next, jiffies + HZ/2))
866 next = jiffies + HZ/2;
Herbert Xu6fb99742005-10-23 16:37:48 +1000867 if (!mod_timer(&neigh->timer, next))
868 neigh_hold(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 }
870 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
871 struct sk_buff *skb = skb_peek(&neigh->arp_queue);
David S. Miller9ff56602008-02-17 18:39:54 -0800872 /* keep skb alive even if arp_queue overflows */
873 if (skb)
Frank Blaschka7e367632008-03-03 12:16:04 -0800874 skb = skb_copy(skb, GFP_ATOMIC);
David S. Miller9ff56602008-02-17 18:39:54 -0800875 write_unlock(&neigh->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 neigh->ops->solicit(neigh, skb);
877 atomic_inc(&neigh->probes);
Wei Yongjunf3fbbe02009-02-25 00:37:32 +0000878 kfree_skb(skb);
David S. Miller9ff56602008-02-17 18:39:54 -0800879 } else {
David S. Miller69cc64d2008-02-11 21:45:44 -0800880out:
David S. Miller9ff56602008-02-17 18:39:54 -0800881 write_unlock(&neigh->lock);
882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
Thomas Grafd961db32007-08-08 23:12:56 -0700884 if (notify)
885 neigh_update_notify(neigh);
886
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 neigh_release(neigh);
888}
889
890int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
891{
892 int rc;
893 unsigned long now;
894
895 write_lock_bh(&neigh->lock);
896
897 rc = 0;
898 if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
899 goto out_unlock_bh;
900
901 now = jiffies;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900902
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
904 if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
905 atomic_set(&neigh->probes, neigh->parms->ucast_probes);
906 neigh->nud_state = NUD_INCOMPLETE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800907 neigh->updated = jiffies;
David S. Miller667347f2005-09-27 12:07:44 -0700908 neigh_add_timer(neigh, now + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 } else {
910 neigh->nud_state = NUD_FAILED;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800911 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 write_unlock_bh(&neigh->lock);
913
Wei Yongjunf3fbbe02009-02-25 00:37:32 +0000914 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 return 1;
916 }
917 } else if (neigh->nud_state & NUD_STALE) {
918 NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800920 neigh->updated = jiffies;
David S. Miller667347f2005-09-27 12:07:44 -0700921 neigh_add_timer(neigh,
922 jiffies + neigh->parms->delay_probe_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 }
924
925 if (neigh->nud_state == NUD_INCOMPLETE) {
926 if (skb) {
927 if (skb_queue_len(&neigh->arp_queue) >=
928 neigh->parms->queue_len) {
929 struct sk_buff *buff;
David S. Millerf72051b2008-09-23 01:11:18 -0700930 buff = __skb_dequeue(&neigh->arp_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 kfree_skb(buff);
Neil Horman9a6d2762008-07-16 20:50:49 -0700932 NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 }
934 __skb_queue_tail(&neigh->arp_queue, skb);
935 }
936 rc = 1;
937 }
938out_unlock_bh:
939 write_unlock_bh(&neigh->lock);
940 return rc;
941}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900942EXPORT_SYMBOL(__neigh_event_send);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
Stephen Hemmingere92b43a2006-08-17 18:17:37 -0700944static void neigh_update_hhs(struct neighbour *neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945{
946 struct hh_cache *hh;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -0700947 void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
948 = neigh->dev->header_ops->cache_update;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
950 if (update) {
951 for (hh = neigh->hh; hh; hh = hh->hh_next) {
Stephen Hemminger3644f0c2006-12-07 15:08:17 -0800952 write_seqlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 update(hh, neigh->dev, neigh->ha);
Stephen Hemminger3644f0c2006-12-07 15:08:17 -0800954 write_sequnlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 }
956 }
957}
958
959
960
961/* Generic update routine.
962 -- lladdr is new lladdr or NULL, if it is not supplied.
963 -- new is new state.
964 -- flags
965 NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
966 if it is different.
967 NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900968 lladdr instead of overriding it
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 if it is different.
970 It also allows to retain current state
971 if lladdr is unchanged.
972 NEIGH_UPDATE_F_ADMIN means that the change is administrative.
973
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900974 NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 NTF_ROUTER flag.
976 NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
977 a router.
978
979 Caller MUST hold reference count on the entry.
980 */
981
982int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
983 u32 flags)
984{
985 u8 old;
986 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 int notify = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 struct net_device *dev;
989 int update_isrouter = 0;
990
991 write_lock_bh(&neigh->lock);
992
993 dev = neigh->dev;
994 old = neigh->nud_state;
995 err = -EPERM;
996
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900997 if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 (old & (NUD_NOARP | NUD_PERMANENT)))
999 goto out;
1000
1001 if (!(new & NUD_VALID)) {
1002 neigh_del_timer(neigh);
1003 if (old & NUD_CONNECTED)
1004 neigh_suspect(neigh);
1005 neigh->nud_state = new;
1006 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 notify = old & NUD_VALID;
Timo Teras5ef12d92009-06-11 04:16:28 -07001008 if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
1009 (new & NUD_FAILED)) {
1010 neigh_invalidate(neigh);
1011 notify = 1;
1012 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 goto out;
1014 }
1015
1016 /* Compare new lladdr with cached one */
1017 if (!dev->addr_len) {
1018 /* First case: device needs no address. */
1019 lladdr = neigh->ha;
1020 } else if (lladdr) {
1021 /* The second case: if something is already cached
1022 and a new address is proposed:
1023 - compare new & old
1024 - if they are different, check override flag
1025 */
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001026 if ((old & NUD_VALID) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 !memcmp(lladdr, neigh->ha, dev->addr_len))
1028 lladdr = neigh->ha;
1029 } else {
1030 /* No address is supplied; if we know something,
1031 use it, otherwise discard the request.
1032 */
1033 err = -EINVAL;
1034 if (!(old & NUD_VALID))
1035 goto out;
1036 lladdr = neigh->ha;
1037 }
1038
1039 if (new & NUD_CONNECTED)
1040 neigh->confirmed = jiffies;
1041 neigh->updated = jiffies;
1042
1043 /* If entry was valid and address is not changed,
1044 do not change entry state, if new one is STALE.
1045 */
1046 err = 0;
1047 update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
1048 if (old & NUD_VALID) {
1049 if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
1050 update_isrouter = 0;
1051 if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
1052 (old & NUD_CONNECTED)) {
1053 lladdr = neigh->ha;
1054 new = NUD_STALE;
1055 } else
1056 goto out;
1057 } else {
1058 if (lladdr == neigh->ha && new == NUD_STALE &&
1059 ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||
1060 (old & NUD_CONNECTED))
1061 )
1062 new = old;
1063 }
1064 }
1065
1066 if (new != old) {
1067 neigh_del_timer(neigh);
Pavel Emelyanova43d8992007-12-20 15:49:05 -08001068 if (new & NUD_IN_TIMER)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001069 neigh_add_timer(neigh, (jiffies +
1070 ((new & NUD_REACHABLE) ?
David S. Miller667347f2005-09-27 12:07:44 -07001071 neigh->parms->reachable_time :
1072 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 neigh->nud_state = new;
1074 }
1075
1076 if (lladdr != neigh->ha) {
1077 memcpy(&neigh->ha, lladdr, dev->addr_len);
1078 neigh_update_hhs(neigh);
1079 if (!(new & NUD_CONNECTED))
1080 neigh->confirmed = jiffies -
1081 (neigh->parms->base_reachable_time << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 }
1084 if (new == old)
1085 goto out;
1086 if (new & NUD_CONNECTED)
1087 neigh_connect(neigh);
1088 else
1089 neigh_suspect(neigh);
1090 if (!(old & NUD_VALID)) {
1091 struct sk_buff *skb;
1092
1093 /* Again: avoid dead loop if something went wrong */
1094
1095 while (neigh->nud_state & NUD_VALID &&
1096 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
1097 struct neighbour *n1 = neigh;
1098 write_unlock_bh(&neigh->lock);
1099 /* On shaper/eql skb->dst->neighbour != neigh :( */
Eric Dumazetadf30902009-06-02 05:19:30 +00001100 if (skb_dst(skb) && skb_dst(skb)->neighbour)
1101 n1 = skb_dst(skb)->neighbour;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 n1->output(skb);
1103 write_lock_bh(&neigh->lock);
1104 }
1105 skb_queue_purge(&neigh->arp_queue);
1106 }
1107out:
1108 if (update_isrouter) {
1109 neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?
1110 (neigh->flags | NTF_ROUTER) :
1111 (neigh->flags & ~NTF_ROUTER);
1112 }
1113 write_unlock_bh(&neigh->lock);
Tom Tucker8d717402006-07-30 20:43:36 -07001114
1115 if (notify)
Thomas Grafd961db32007-08-08 23:12:56 -07001116 neigh_update_notify(neigh);
1117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 return err;
1119}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001120EXPORT_SYMBOL(neigh_update);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
1122struct neighbour *neigh_event_ns(struct neigh_table *tbl,
1123 u8 *lladdr, void *saddr,
1124 struct net_device *dev)
1125{
1126 struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
1127 lladdr || !dev->addr_len);
1128 if (neigh)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001129 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 NEIGH_UPDATE_F_OVERRIDE);
1131 return neigh;
1132}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001133EXPORT_SYMBOL(neigh_event_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
1135static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
Al Virod77072e2006-09-28 14:20:34 -07001136 __be16 protocol)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137{
1138 struct hh_cache *hh;
1139 struct net_device *dev = dst->dev;
1140
1141 for (hh = n->hh; hh; hh = hh->hh_next)
1142 if (hh->hh_type == protocol)
1143 break;
1144
Andrew Morton77d04bd2006-04-07 14:52:59 -07001145 if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) {
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001146 seqlock_init(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 hh->hh_type = protocol;
1148 atomic_set(&hh->hh_refcnt, 0);
1149 hh->hh_next = NULL;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001150
1151 if (dev->header_ops->cache(n, hh)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 kfree(hh);
1153 hh = NULL;
1154 } else {
1155 atomic_inc(&hh->hh_refcnt);
1156 hh->hh_next = n->hh;
1157 n->hh = hh;
1158 if (n->nud_state & NUD_CONNECTED)
1159 hh->hh_output = n->ops->hh_output;
1160 else
1161 hh->hh_output = n->ops->output;
1162 }
1163 }
1164 if (hh) {
1165 atomic_inc(&hh->hh_refcnt);
1166 dst->hh = hh;
1167 }
1168}
1169
1170/* This function can be used in contexts, where only old dev_queue_xmit
1171 worked, f.e. if you want to override normal output path (eql, shaper),
1172 but resolution is not made yet.
1173 */
1174
1175int neigh_compat_output(struct sk_buff *skb)
1176{
1177 struct net_device *dev = skb->dev;
1178
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001179 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
Stephen Hemminger0c4e8582007-10-09 01:36:32 -07001181 if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
1182 skb->len) < 0 &&
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001183 dev->header_ops->rebuild(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 return 0;
1185
1186 return dev_queue_xmit(skb);
1187}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001188EXPORT_SYMBOL(neigh_compat_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
1190/* Slow and careful. */
1191
1192int neigh_resolve_output(struct sk_buff *skb)
1193{
Eric Dumazetadf30902009-06-02 05:19:30 +00001194 struct dst_entry *dst = skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 struct neighbour *neigh;
1196 int rc = 0;
1197
1198 if (!dst || !(neigh = dst->neighbour))
1199 goto discard;
1200
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001201 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202
1203 if (!neigh_event_send(neigh, skb)) {
1204 int err;
1205 struct net_device *dev = neigh->dev;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001206 if (dev->header_ops->cache && !dst->hh) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 write_lock_bh(&neigh->lock);
1208 if (!dst->hh)
1209 neigh_hh_init(neigh, dst, dst->ops->protocol);
Stephen Hemminger0c4e8582007-10-09 01:36:32 -07001210 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1211 neigh->ha, NULL, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 write_unlock_bh(&neigh->lock);
1213 } else {
1214 read_lock_bh(&neigh->lock);
Stephen Hemminger0c4e8582007-10-09 01:36:32 -07001215 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1216 neigh->ha, NULL, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 read_unlock_bh(&neigh->lock);
1218 }
1219 if (err >= 0)
1220 rc = neigh->ops->queue_xmit(skb);
1221 else
1222 goto out_kfree_skb;
1223 }
1224out:
1225 return rc;
1226discard:
1227 NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
1228 dst, dst ? dst->neighbour : NULL);
1229out_kfree_skb:
1230 rc = -EINVAL;
1231 kfree_skb(skb);
1232 goto out;
1233}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001234EXPORT_SYMBOL(neigh_resolve_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
1236/* As fast as possible without hh cache */
1237
1238int neigh_connected_output(struct sk_buff *skb)
1239{
1240 int err;
Eric Dumazetadf30902009-06-02 05:19:30 +00001241 struct dst_entry *dst = skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 struct neighbour *neigh = dst->neighbour;
1243 struct net_device *dev = neigh->dev;
1244
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001245 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
1247 read_lock_bh(&neigh->lock);
Stephen Hemminger0c4e8582007-10-09 01:36:32 -07001248 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1249 neigh->ha, NULL, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 read_unlock_bh(&neigh->lock);
1251 if (err >= 0)
1252 err = neigh->ops->queue_xmit(skb);
1253 else {
1254 err = -EINVAL;
1255 kfree_skb(skb);
1256 }
1257 return err;
1258}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001259EXPORT_SYMBOL(neigh_connected_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
1261static void neigh_proxy_process(unsigned long arg)
1262{
1263 struct neigh_table *tbl = (struct neigh_table *)arg;
1264 long sched_next = 0;
1265 unsigned long now = jiffies;
David S. Millerf72051b2008-09-23 01:11:18 -07001266 struct sk_buff *skb, *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267
1268 spin_lock(&tbl->proxy_queue.lock);
1269
David S. Millerf72051b2008-09-23 01:11:18 -07001270 skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1271 long tdif = NEIGH_CB(skb)->sched_next - now;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 if (tdif <= 0) {
David S. Millerf72051b2008-09-23 01:11:18 -07001274 struct net_device *dev = skb->dev;
1275 __skb_unlink(skb, &tbl->proxy_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 if (tbl->proxy_redo && netif_running(dev))
David S. Millerf72051b2008-09-23 01:11:18 -07001277 tbl->proxy_redo(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 else
David S. Millerf72051b2008-09-23 01:11:18 -07001279 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
1281 dev_put(dev);
1282 } else if (!sched_next || tdif < sched_next)
1283 sched_next = tdif;
1284 }
1285 del_timer(&tbl->proxy_timer);
1286 if (sched_next)
1287 mod_timer(&tbl->proxy_timer, jiffies + sched_next);
1288 spin_unlock(&tbl->proxy_queue.lock);
1289}
1290
1291void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
1292 struct sk_buff *skb)
1293{
1294 unsigned long now = jiffies;
1295 unsigned long sched_next = now + (net_random() % p->proxy_delay);
1296
1297 if (tbl->proxy_queue.qlen > p->proxy_qlen) {
1298 kfree_skb(skb);
1299 return;
1300 }
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001301
1302 NEIGH_CB(skb)->sched_next = sched_next;
1303 NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
1305 spin_lock(&tbl->proxy_queue.lock);
1306 if (del_timer(&tbl->proxy_timer)) {
1307 if (time_before(tbl->proxy_timer.expires, sched_next))
1308 sched_next = tbl->proxy_timer.expires;
1309 }
Eric Dumazetadf30902009-06-02 05:19:30 +00001310 skb_dst_drop(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 dev_hold(skb->dev);
1312 __skb_queue_tail(&tbl->proxy_queue, skb);
1313 mod_timer(&tbl->proxy_timer, sched_next);
1314 spin_unlock(&tbl->proxy_queue.lock);
1315}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001316EXPORT_SYMBOL(pneigh_enqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001318static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
Eric W. Biederman426b5302008-01-24 00:13:18 -08001319 struct net *net, int ifindex)
1320{
1321 struct neigh_parms *p;
1322
1323 for (p = &tbl->parms; p; p = p->next) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09001324 if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
Eric W. Biederman426b5302008-01-24 00:13:18 -08001325 (!p->dev && !ifindex))
1326 return p;
1327 }
1328
1329 return NULL;
1330}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
1332struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1333 struct neigh_table *tbl)
1334{
Eric W. Biederman426b5302008-01-24 00:13:18 -08001335 struct neigh_parms *p, *ref;
Stephen Hemminger00829822008-11-20 20:14:53 -08001336 struct net *net = dev_net(dev);
1337 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001339 ref = lookup_neigh_parms(tbl, net, 0);
Eric W. Biederman426b5302008-01-24 00:13:18 -08001340 if (!ref)
1341 return NULL;
1342
1343 p = kmemdup(ref, sizeof(*p), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 if (p) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 p->tbl = tbl;
1346 atomic_set(&p->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 p->reachable_time =
1348 neigh_rand_reach_time(p->base_reachable_time);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001349
Stephen Hemminger00829822008-11-20 20:14:53 -08001350 if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001351 kfree(p);
1352 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 }
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001354
1355 dev_hold(dev);
1356 p->dev = dev;
Eric Dumazete42ea982008-11-12 00:54:54 -08001357 write_pnet(&p->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 p->sysctl_table = NULL;
1359 write_lock_bh(&tbl->lock);
1360 p->next = tbl->parms.next;
1361 tbl->parms.next = p;
1362 write_unlock_bh(&tbl->lock);
1363 }
1364 return p;
1365}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001366EXPORT_SYMBOL(neigh_parms_alloc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
1368static void neigh_rcu_free_parms(struct rcu_head *head)
1369{
1370 struct neigh_parms *parms =
1371 container_of(head, struct neigh_parms, rcu_head);
1372
1373 neigh_parms_put(parms);
1374}
1375
1376void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
1377{
1378 struct neigh_parms **p;
1379
1380 if (!parms || parms == &tbl->parms)
1381 return;
1382 write_lock_bh(&tbl->lock);
1383 for (p = &tbl->parms.next; *p; p = &(*p)->next) {
1384 if (*p == parms) {
1385 *p = parms->next;
1386 parms->dead = 1;
1387 write_unlock_bh(&tbl->lock);
David S. Millercecbb632008-01-20 16:39:03 -08001388 if (parms->dev)
1389 dev_put(parms->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
1391 return;
1392 }
1393 }
1394 write_unlock_bh(&tbl->lock);
1395 NEIGH_PRINTK1("neigh_parms_release: not found\n");
1396}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001397EXPORT_SYMBOL(neigh_parms_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
Denis V. Lunev06f05112008-01-24 00:30:58 -08001399static void neigh_parms_destroy(struct neigh_parms *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400{
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +09001401 release_net(neigh_parms_net(parms));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 kfree(parms);
1403}
1404
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001405static struct lock_class_key neigh_table_proxy_queue_class;
1406
Simon Kelleybd89efc2006-05-12 14:56:08 -07001407void neigh_table_init_no_netlink(struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408{
1409 unsigned long now = jiffies;
1410 unsigned long phsize;
1411
Eric Dumazete42ea982008-11-12 00:54:54 -08001412 write_pnet(&tbl->parms.net, &init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 atomic_set(&tbl->parms.refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 tbl->parms.reachable_time =
1415 neigh_rand_reach_time(tbl->parms.base_reachable_time);
1416
1417 if (!tbl->kmem_cachep)
Alexey Dobriyane5d679f332006-08-26 19:25:52 -07001418 tbl->kmem_cachep =
1419 kmem_cache_create(tbl->id, tbl->entry_size, 0,
1420 SLAB_HWCACHE_ALIGN|SLAB_PANIC,
Paul Mundt20c2df82007-07-20 10:11:58 +09001421 NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 tbl->stats = alloc_percpu(struct neigh_statistics);
1423 if (!tbl->stats)
1424 panic("cannot create neighbour cache statistics");
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001425
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426#ifdef CONFIG_PROC_FS
Alexey Dobriyan9b739ba2008-11-11 16:47:44 -08001427 if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat,
1428 &neigh_stat_seq_fops, tbl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 panic("cannot create neighbour proc dir entry");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430#endif
1431
1432 tbl->hash_mask = 1;
1433 tbl->hash_buckets = neigh_hash_alloc(tbl->hash_mask + 1);
1434
1435 phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
Andrew Morton77d04bd2006-04-07 14:52:59 -07001436 tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437
1438 if (!tbl->hash_buckets || !tbl->phash_buckets)
1439 panic("cannot allocate neighbour cache hashes");
1440
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd));
1442
1443 rwlock_init(&tbl->lock);
Eric Dumazete4c4e442009-07-30 03:15:07 +00001444 INIT_DELAYED_WORK_DEFERRABLE(&tbl->gc_work, neigh_periodic_work);
1445 schedule_delayed_work(&tbl->gc_work, tbl->parms.reachable_time);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001446 setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl);
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001447 skb_queue_head_init_class(&tbl->proxy_queue,
1448 &neigh_table_proxy_queue_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449
1450 tbl->last_flush = now;
1451 tbl->last_rand = now + tbl->parms.reachable_time * 20;
Simon Kelleybd89efc2006-05-12 14:56:08 -07001452}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001453EXPORT_SYMBOL(neigh_table_init_no_netlink);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001454
1455void neigh_table_init(struct neigh_table *tbl)
1456{
1457 struct neigh_table *tmp;
1458
1459 neigh_table_init_no_netlink(tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 write_lock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001461 for (tmp = neigh_tables; tmp; tmp = tmp->next) {
1462 if (tmp->family == tbl->family)
1463 break;
1464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 tbl->next = neigh_tables;
1466 neigh_tables = tbl;
1467 write_unlock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001468
1469 if (unlikely(tmp)) {
1470 printk(KERN_ERR "NEIGH: Registering multiple tables for "
1471 "family %d\n", tbl->family);
1472 dump_stack();
1473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001475EXPORT_SYMBOL(neigh_table_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
1477int neigh_table_clear(struct neigh_table *tbl)
1478{
1479 struct neigh_table **tp;
1480
1481 /* It is not clean... Fix it to unload IPv6 module safely */
Eric Dumazete4c4e442009-07-30 03:15:07 +00001482 cancel_delayed_work(&tbl->gc_work);
1483 flush_scheduled_work();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 del_timer_sync(&tbl->proxy_timer);
1485 pneigh_queue_purge(&tbl->proxy_queue);
1486 neigh_ifdown(tbl, NULL);
1487 if (atomic_read(&tbl->entries))
1488 printk(KERN_CRIT "neighbour leakage\n");
1489 write_lock(&neigh_tbl_lock);
1490 for (tp = &neigh_tables; *tp; tp = &(*tp)->next) {
1491 if (*tp == tbl) {
1492 *tp = tbl->next;
1493 break;
1494 }
1495 }
1496 write_unlock(&neigh_tbl_lock);
1497
1498 neigh_hash_free(tbl->hash_buckets, tbl->hash_mask + 1);
1499 tbl->hash_buckets = NULL;
1500
1501 kfree(tbl->phash_buckets);
1502 tbl->phash_buckets = NULL;
1503
Alexey Dobriyan3f192b52007-11-05 21:28:13 -08001504 remove_proc_entry(tbl->id, init_net.proc_net_stat);
1505
Kirill Korotaev3fcde742006-09-01 01:34:10 -07001506 free_percpu(tbl->stats);
1507 tbl->stats = NULL;
1508
Randy Dunlapbfb85c92007-10-21 16:24:27 -07001509 kmem_cache_destroy(tbl->kmem_cachep);
1510 tbl->kmem_cachep = NULL;
1511
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 return 0;
1513}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001514EXPORT_SYMBOL(neigh_table_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515
Thomas Grafc8822a42007-03-22 11:50:06 -07001516static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001518 struct net *net = sock_net(skb->sk);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001519 struct ndmsg *ndm;
1520 struct nlattr *dst_attr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 struct neigh_table *tbl;
1522 struct net_device *dev = NULL;
Thomas Grafa14a49d2006-08-07 17:53:08 -07001523 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
Thomas Grafa14a49d2006-08-07 17:53:08 -07001525 if (nlmsg_len(nlh) < sizeof(*ndm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 goto out;
1527
Thomas Grafa14a49d2006-08-07 17:53:08 -07001528 dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
1529 if (dst_attr == NULL)
1530 goto out;
1531
1532 ndm = nlmsg_data(nlh);
1533 if (ndm->ndm_ifindex) {
Eric W. Biederman881d9662007-09-17 11:56:21 -07001534 dev = dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001535 if (dev == NULL) {
1536 err = -ENODEV;
1537 goto out;
1538 }
1539 }
1540
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 read_lock(&neigh_tbl_lock);
1542 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Grafa14a49d2006-08-07 17:53:08 -07001543 struct neighbour *neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
1545 if (tbl->family != ndm->ndm_family)
1546 continue;
1547 read_unlock(&neigh_tbl_lock);
1548
Thomas Grafa14a49d2006-08-07 17:53:08 -07001549 if (nla_len(dst_attr) < tbl->key_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 goto out_dev_put;
1551
1552 if (ndm->ndm_flags & NTF_PROXY) {
Eric W. Biederman426b5302008-01-24 00:13:18 -08001553 err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 goto out_dev_put;
1555 }
1556
Thomas Grafa14a49d2006-08-07 17:53:08 -07001557 if (dev == NULL)
1558 goto out_dev_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
Thomas Grafa14a49d2006-08-07 17:53:08 -07001560 neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1561 if (neigh == NULL) {
1562 err = -ENOENT;
1563 goto out_dev_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 }
Thomas Grafa14a49d2006-08-07 17:53:08 -07001565
1566 err = neigh_update(neigh, NULL, NUD_FAILED,
1567 NEIGH_UPDATE_F_OVERRIDE |
1568 NEIGH_UPDATE_F_ADMIN);
1569 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 goto out_dev_put;
1571 }
1572 read_unlock(&neigh_tbl_lock);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001573 err = -EAFNOSUPPORT;
1574
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575out_dev_put:
1576 if (dev)
1577 dev_put(dev);
1578out:
1579 return err;
1580}
1581
Thomas Grafc8822a42007-03-22 11:50:06 -07001582static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001584 struct net *net = sock_net(skb->sk);
Thomas Graf5208deb2006-08-07 17:55:40 -07001585 struct ndmsg *ndm;
1586 struct nlattr *tb[NDA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 struct neigh_table *tbl;
1588 struct net_device *dev = NULL;
Thomas Graf5208deb2006-08-07 17:55:40 -07001589 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
Thomas Graf5208deb2006-08-07 17:55:40 -07001591 err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
1592 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 goto out;
1594
Thomas Graf5208deb2006-08-07 17:55:40 -07001595 err = -EINVAL;
1596 if (tb[NDA_DST] == NULL)
1597 goto out;
1598
1599 ndm = nlmsg_data(nlh);
1600 if (ndm->ndm_ifindex) {
Eric W. Biederman881d9662007-09-17 11:56:21 -07001601 dev = dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Graf5208deb2006-08-07 17:55:40 -07001602 if (dev == NULL) {
1603 err = -ENODEV;
1604 goto out;
1605 }
1606
1607 if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
1608 goto out_dev_put;
1609 }
1610
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 read_lock(&neigh_tbl_lock);
1612 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Graf5208deb2006-08-07 17:55:40 -07001613 int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
1614 struct neighbour *neigh;
1615 void *dst, *lladdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616
1617 if (tbl->family != ndm->ndm_family)
1618 continue;
1619 read_unlock(&neigh_tbl_lock);
1620
Thomas Graf5208deb2006-08-07 17:55:40 -07001621 if (nla_len(tb[NDA_DST]) < tbl->key_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 goto out_dev_put;
Thomas Graf5208deb2006-08-07 17:55:40 -07001623 dst = nla_data(tb[NDA_DST]);
1624 lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625
1626 if (ndm->ndm_flags & NTF_PROXY) {
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001627 struct pneigh_entry *pn;
1628
1629 err = -ENOBUFS;
Eric W. Biederman426b5302008-01-24 00:13:18 -08001630 pn = pneigh_lookup(tbl, net, dst, dev, 1);
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001631 if (pn) {
1632 pn->flags = ndm->ndm_flags;
1633 err = 0;
1634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 goto out_dev_put;
1636 }
1637
Thomas Graf5208deb2006-08-07 17:55:40 -07001638 if (dev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 goto out_dev_put;
Thomas Graf5208deb2006-08-07 17:55:40 -07001640
1641 neigh = neigh_lookup(tbl, dst, dev);
1642 if (neigh == NULL) {
1643 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
1644 err = -ENOENT;
1645 goto out_dev_put;
1646 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001647
Thomas Graf5208deb2006-08-07 17:55:40 -07001648 neigh = __neigh_lookup_errno(tbl, dst, dev);
1649 if (IS_ERR(neigh)) {
1650 err = PTR_ERR(neigh);
1651 goto out_dev_put;
1652 }
1653 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 if (nlh->nlmsg_flags & NLM_F_EXCL) {
1655 err = -EEXIST;
Thomas Graf5208deb2006-08-07 17:55:40 -07001656 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 goto out_dev_put;
1658 }
Thomas Graf5208deb2006-08-07 17:55:40 -07001659
1660 if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
1661 flags &= ~NEIGH_UPDATE_F_OVERRIDE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 }
1663
Eric Biederman0c5c2d32009-03-04 00:03:08 -08001664 if (ndm->ndm_flags & NTF_USE) {
1665 neigh_event_send(neigh, NULL);
1666 err = 0;
1667 } else
1668 err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
Thomas Graf5208deb2006-08-07 17:55:40 -07001669 neigh_release(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 goto out_dev_put;
1671 }
1672
1673 read_unlock(&neigh_tbl_lock);
Thomas Graf5208deb2006-08-07 17:55:40 -07001674 err = -EAFNOSUPPORT;
1675
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676out_dev_put:
1677 if (dev)
1678 dev_put(dev);
1679out:
1680 return err;
1681}
1682
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001683static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1684{
Thomas Grafca860fb2006-08-07 18:00:18 -07001685 struct nlattr *nest;
1686
1687 nest = nla_nest_start(skb, NDTA_PARMS);
1688 if (nest == NULL)
1689 return -ENOBUFS;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001690
1691 if (parms->dev)
Thomas Grafca860fb2006-08-07 18:00:18 -07001692 NLA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001693
Thomas Grafca860fb2006-08-07 18:00:18 -07001694 NLA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt));
1695 NLA_PUT_U32(skb, NDTPA_QUEUE_LEN, parms->queue_len);
1696 NLA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen);
1697 NLA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes);
1698 NLA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes);
1699 NLA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes);
1700 NLA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time);
1701 NLA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001702 parms->base_reachable_time);
Thomas Grafca860fb2006-08-07 18:00:18 -07001703 NLA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime);
1704 NLA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time);
1705 NLA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time);
1706 NLA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay);
1707 NLA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay);
1708 NLA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001709
Thomas Grafca860fb2006-08-07 18:00:18 -07001710 return nla_nest_end(skb, nest);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001711
Thomas Grafca860fb2006-08-07 18:00:18 -07001712nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07001713 nla_nest_cancel(skb, nest);
1714 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001715}
1716
Thomas Grafca860fb2006-08-07 18:00:18 -07001717static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
1718 u32 pid, u32 seq, int type, int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001719{
1720 struct nlmsghdr *nlh;
1721 struct ndtmsg *ndtmsg;
1722
Thomas Grafca860fb2006-08-07 18:00:18 -07001723 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1724 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001725 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001726
Thomas Grafca860fb2006-08-07 18:00:18 -07001727 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001728
1729 read_lock_bh(&tbl->lock);
1730 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001731 ndtmsg->ndtm_pad1 = 0;
1732 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001733
Thomas Grafca860fb2006-08-07 18:00:18 -07001734 NLA_PUT_STRING(skb, NDTA_NAME, tbl->id);
1735 NLA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval);
1736 NLA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1);
1737 NLA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2);
1738 NLA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001739
1740 {
1741 unsigned long now = jiffies;
1742 unsigned int flush_delta = now - tbl->last_flush;
1743 unsigned int rand_delta = now - tbl->last_rand;
1744
1745 struct ndt_config ndc = {
1746 .ndtc_key_len = tbl->key_len,
1747 .ndtc_entry_size = tbl->entry_size,
1748 .ndtc_entries = atomic_read(&tbl->entries),
1749 .ndtc_last_flush = jiffies_to_msecs(flush_delta),
1750 .ndtc_last_rand = jiffies_to_msecs(rand_delta),
1751 .ndtc_hash_rnd = tbl->hash_rnd,
1752 .ndtc_hash_mask = tbl->hash_mask,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001753 .ndtc_proxy_qlen = tbl->proxy_queue.qlen,
1754 };
1755
Thomas Grafca860fb2006-08-07 18:00:18 -07001756 NLA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001757 }
1758
1759 {
1760 int cpu;
1761 struct ndt_stats ndst;
1762
1763 memset(&ndst, 0, sizeof(ndst));
1764
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001765 for_each_possible_cpu(cpu) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001766 struct neigh_statistics *st;
1767
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001768 st = per_cpu_ptr(tbl->stats, cpu);
1769 ndst.ndts_allocs += st->allocs;
1770 ndst.ndts_destroys += st->destroys;
1771 ndst.ndts_hash_grows += st->hash_grows;
1772 ndst.ndts_res_failed += st->res_failed;
1773 ndst.ndts_lookups += st->lookups;
1774 ndst.ndts_hits += st->hits;
1775 ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast;
1776 ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast;
1777 ndst.ndts_periodic_gc_runs += st->periodic_gc_runs;
1778 ndst.ndts_forced_gc_runs += st->forced_gc_runs;
1779 }
1780
Thomas Grafca860fb2006-08-07 18:00:18 -07001781 NLA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001782 }
1783
1784 BUG_ON(tbl->parms.dev);
1785 if (neightbl_fill_parms(skb, &tbl->parms) < 0)
Thomas Grafca860fb2006-08-07 18:00:18 -07001786 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001787
1788 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001789 return nlmsg_end(skb, nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001790
Thomas Grafca860fb2006-08-07 18:00:18 -07001791nla_put_failure:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001792 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001793 nlmsg_cancel(skb, nlh);
1794 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001795}
1796
Thomas Grafca860fb2006-08-07 18:00:18 -07001797static int neightbl_fill_param_info(struct sk_buff *skb,
1798 struct neigh_table *tbl,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001799 struct neigh_parms *parms,
Thomas Grafca860fb2006-08-07 18:00:18 -07001800 u32 pid, u32 seq, int type,
1801 unsigned int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001802{
1803 struct ndtmsg *ndtmsg;
1804 struct nlmsghdr *nlh;
1805
Thomas Grafca860fb2006-08-07 18:00:18 -07001806 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1807 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001808 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001809
Thomas Grafca860fb2006-08-07 18:00:18 -07001810 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001811
1812 read_lock_bh(&tbl->lock);
1813 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001814 ndtmsg->ndtm_pad1 = 0;
1815 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001816
Thomas Grafca860fb2006-08-07 18:00:18 -07001817 if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
1818 neightbl_fill_parms(skb, parms) < 0)
1819 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001820
1821 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001822 return nlmsg_end(skb, nlh);
1823errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001824 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001825 nlmsg_cancel(skb, nlh);
1826 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001827}
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001828
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001829static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001830 [NDTA_NAME] = { .type = NLA_STRING },
1831 [NDTA_THRESH1] = { .type = NLA_U32 },
1832 [NDTA_THRESH2] = { .type = NLA_U32 },
1833 [NDTA_THRESH3] = { .type = NLA_U32 },
1834 [NDTA_GC_INTERVAL] = { .type = NLA_U64 },
1835 [NDTA_PARMS] = { .type = NLA_NESTED },
1836};
1837
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001838static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001839 [NDTPA_IFINDEX] = { .type = NLA_U32 },
1840 [NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
1841 [NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
1842 [NDTPA_APP_PROBES] = { .type = NLA_U32 },
1843 [NDTPA_UCAST_PROBES] = { .type = NLA_U32 },
1844 [NDTPA_MCAST_PROBES] = { .type = NLA_U32 },
1845 [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 },
1846 [NDTPA_GC_STALETIME] = { .type = NLA_U64 },
1847 [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 },
1848 [NDTPA_RETRANS_TIME] = { .type = NLA_U64 },
1849 [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
1850 [NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
1851 [NDTPA_LOCKTIME] = { .type = NLA_U64 },
1852};
1853
Thomas Grafc8822a42007-03-22 11:50:06 -07001854static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001855{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001856 struct net *net = sock_net(skb->sk);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001857 struct neigh_table *tbl;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001858 struct ndtmsg *ndtmsg;
1859 struct nlattr *tb[NDTA_MAX+1];
1860 int err;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001861
Thomas Graf6b3f8672006-08-07 17:58:53 -07001862 err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
1863 nl_neightbl_policy);
1864 if (err < 0)
1865 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001866
Thomas Graf6b3f8672006-08-07 17:58:53 -07001867 if (tb[NDTA_NAME] == NULL) {
1868 err = -EINVAL;
1869 goto errout;
1870 }
1871
1872 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001873 read_lock(&neigh_tbl_lock);
1874 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
1875 if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
1876 continue;
1877
Thomas Graf6b3f8672006-08-07 17:58:53 -07001878 if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001879 break;
1880 }
1881
1882 if (tbl == NULL) {
1883 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001884 goto errout_locked;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001885 }
1886
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001887 /*
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001888 * We acquire tbl->lock to be nice to the periodic timers and
1889 * make sure they always see a consistent set of values.
1890 */
1891 write_lock_bh(&tbl->lock);
1892
Thomas Graf6b3f8672006-08-07 17:58:53 -07001893 if (tb[NDTA_PARMS]) {
1894 struct nlattr *tbp[NDTPA_MAX+1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001895 struct neigh_parms *p;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001896 int i, ifindex = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001897
Thomas Graf6b3f8672006-08-07 17:58:53 -07001898 err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
1899 nl_ntbl_parm_policy);
1900 if (err < 0)
1901 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001902
Thomas Graf6b3f8672006-08-07 17:58:53 -07001903 if (tbp[NDTPA_IFINDEX])
1904 ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001905
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001906 p = lookup_neigh_parms(tbl, net, ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001907 if (p == NULL) {
1908 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001909 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001910 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001911
Thomas Graf6b3f8672006-08-07 17:58:53 -07001912 for (i = 1; i <= NDTPA_MAX; i++) {
1913 if (tbp[i] == NULL)
1914 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001915
Thomas Graf6b3f8672006-08-07 17:58:53 -07001916 switch (i) {
1917 case NDTPA_QUEUE_LEN:
1918 p->queue_len = nla_get_u32(tbp[i]);
1919 break;
1920 case NDTPA_PROXY_QLEN:
1921 p->proxy_qlen = nla_get_u32(tbp[i]);
1922 break;
1923 case NDTPA_APP_PROBES:
1924 p->app_probes = nla_get_u32(tbp[i]);
1925 break;
1926 case NDTPA_UCAST_PROBES:
1927 p->ucast_probes = nla_get_u32(tbp[i]);
1928 break;
1929 case NDTPA_MCAST_PROBES:
1930 p->mcast_probes = nla_get_u32(tbp[i]);
1931 break;
1932 case NDTPA_BASE_REACHABLE_TIME:
1933 p->base_reachable_time = nla_get_msecs(tbp[i]);
1934 break;
1935 case NDTPA_GC_STALETIME:
1936 p->gc_staletime = nla_get_msecs(tbp[i]);
1937 break;
1938 case NDTPA_DELAY_PROBE_TIME:
1939 p->delay_probe_time = nla_get_msecs(tbp[i]);
1940 break;
1941 case NDTPA_RETRANS_TIME:
1942 p->retrans_time = nla_get_msecs(tbp[i]);
1943 break;
1944 case NDTPA_ANYCAST_DELAY:
1945 p->anycast_delay = nla_get_msecs(tbp[i]);
1946 break;
1947 case NDTPA_PROXY_DELAY:
1948 p->proxy_delay = nla_get_msecs(tbp[i]);
1949 break;
1950 case NDTPA_LOCKTIME:
1951 p->locktime = nla_get_msecs(tbp[i]);
1952 break;
1953 }
1954 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001955 }
1956
Thomas Graf6b3f8672006-08-07 17:58:53 -07001957 if (tb[NDTA_THRESH1])
1958 tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
1959
1960 if (tb[NDTA_THRESH2])
1961 tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
1962
1963 if (tb[NDTA_THRESH3])
1964 tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
1965
1966 if (tb[NDTA_GC_INTERVAL])
1967 tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
1968
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001969 err = 0;
1970
Thomas Graf6b3f8672006-08-07 17:58:53 -07001971errout_tbl_lock:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001972 write_unlock_bh(&tbl->lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07001973errout_locked:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001974 read_unlock(&neigh_tbl_lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07001975errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001976 return err;
1977}
1978
Thomas Grafc8822a42007-03-22 11:50:06 -07001979static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001980{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001981 struct net *net = sock_net(skb->sk);
Thomas Grafca860fb2006-08-07 18:00:18 -07001982 int family, tidx, nidx = 0;
1983 int tbl_skip = cb->args[0];
1984 int neigh_skip = cb->args[1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001985 struct neigh_table *tbl;
1986
Thomas Grafca860fb2006-08-07 18:00:18 -07001987 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001988
1989 read_lock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001990 for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001991 struct neigh_parms *p;
1992
Thomas Grafca860fb2006-08-07 18:00:18 -07001993 if (tidx < tbl_skip || (family && tbl->family != family))
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001994 continue;
1995
Thomas Grafca860fb2006-08-07 18:00:18 -07001996 if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).pid,
1997 cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
1998 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001999 break;
2000
Eric W. Biederman426b5302008-01-24 00:13:18 -08002001 for (nidx = 0, p = tbl->parms.next; p; p = p->next) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002002 if (!net_eq(neigh_parms_net(p), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002003 continue;
2004
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002005 if (nidx < neigh_skip)
2006 goto next;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002007
Thomas Grafca860fb2006-08-07 18:00:18 -07002008 if (neightbl_fill_param_info(skb, tbl, p,
2009 NETLINK_CB(cb->skb).pid,
2010 cb->nlh->nlmsg_seq,
2011 RTM_NEWNEIGHTBL,
2012 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002013 goto out;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002014 next:
2015 nidx++;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002016 }
2017
Thomas Grafca860fb2006-08-07 18:00:18 -07002018 neigh_skip = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002019 }
2020out:
2021 read_unlock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07002022 cb->args[0] = tidx;
2023 cb->args[1] = nidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002024
2025 return skb->len;
2026}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027
Thomas Graf8b8aec52006-08-07 17:56:37 -07002028static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
2029 u32 pid, u32 seq, int type, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030{
2031 unsigned long now = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 struct nda_cacheinfo ci;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002033 struct nlmsghdr *nlh;
2034 struct ndmsg *ndm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035
Thomas Graf8b8aec52006-08-07 17:56:37 -07002036 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2037 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002038 return -EMSGSIZE;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002039
2040 ndm = nlmsg_data(nlh);
2041 ndm->ndm_family = neigh->ops->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002042 ndm->ndm_pad1 = 0;
2043 ndm->ndm_pad2 = 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002044 ndm->ndm_flags = neigh->flags;
2045 ndm->ndm_type = neigh->type;
2046 ndm->ndm_ifindex = neigh->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047
Thomas Graf8b8aec52006-08-07 17:56:37 -07002048 NLA_PUT(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key);
2049
2050 read_lock_bh(&neigh->lock);
2051 ndm->ndm_state = neigh->nud_state;
2052 if ((neigh->nud_state & NUD_VALID) &&
2053 nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, neigh->ha) < 0) {
2054 read_unlock_bh(&neigh->lock);
2055 goto nla_put_failure;
2056 }
2057
Stephen Hemmingerb9f5f522008-06-03 16:03:15 -07002058 ci.ndm_used = jiffies_to_clock_t(now - neigh->used);
2059 ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2060 ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002061 ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1;
2062 read_unlock_bh(&neigh->lock);
2063
2064 NLA_PUT_U32(skb, NDA_PROBES, atomic_read(&neigh->probes));
2065 NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
2066
2067 return nlmsg_end(skb, nlh);
2068
2069nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002070 nlmsg_cancel(skb, nlh);
2071 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072}
2073
Thomas Grafd961db32007-08-08 23:12:56 -07002074static void neigh_update_notify(struct neighbour *neigh)
2075{
2076 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
2077 __neigh_notify(neigh, RTM_NEWNEIGH, 0);
2078}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
2080static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2081 struct netlink_callback *cb)
2082{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002083 struct net * net = sock_net(skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 struct neighbour *n;
2085 int rc, h, s_h = cb->args[1];
2086 int idx, s_idx = idx = cb->args[2];
2087
Julian Anastasovc5e29462006-10-03 15:49:46 -07002088 read_lock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 for (h = 0; h <= tbl->hash_mask; h++) {
2090 if (h < s_h)
2091 continue;
2092 if (h > s_h)
2093 s_idx = 0;
Eric W. Biederman426b5302008-01-24 00:13:18 -08002094 for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next) {
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002095 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002096 continue;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002097 if (idx < s_idx)
2098 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid,
2100 cb->nlh->nlmsg_seq,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07002101 RTM_NEWNEIGH,
2102 NLM_F_MULTI) <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 read_unlock_bh(&tbl->lock);
2104 rc = -1;
2105 goto out;
2106 }
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002107 next:
2108 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 }
Julian Anastasovc5e29462006-10-03 15:49:46 -07002111 read_unlock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 rc = skb->len;
2113out:
2114 cb->args[1] = h;
2115 cb->args[2] = idx;
2116 return rc;
2117}
2118
Thomas Grafc8822a42007-03-22 11:50:06 -07002119static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120{
2121 struct neigh_table *tbl;
2122 int t, family, s_t;
2123
2124 read_lock(&neigh_tbl_lock);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002125 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 s_t = cb->args[0];
2127
2128 for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) {
2129 if (t < s_t || (family && tbl->family != family))
2130 continue;
2131 if (t > s_t)
2132 memset(&cb->args[1], 0, sizeof(cb->args) -
2133 sizeof(cb->args[0]));
2134 if (neigh_dump_table(tbl, skb, cb) < 0)
2135 break;
2136 }
2137 read_unlock(&neigh_tbl_lock);
2138
2139 cb->args[0] = t;
2140 return skb->len;
2141}
2142
2143void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
2144{
2145 int chain;
2146
2147 read_lock_bh(&tbl->lock);
2148 for (chain = 0; chain <= tbl->hash_mask; chain++) {
2149 struct neighbour *n;
2150
2151 for (n = tbl->hash_buckets[chain]; n; n = n->next)
2152 cb(n, cookie);
2153 }
2154 read_unlock_bh(&tbl->lock);
2155}
2156EXPORT_SYMBOL(neigh_for_each);
2157
2158/* The tbl->lock must be held as a writer and BH disabled. */
2159void __neigh_for_each_release(struct neigh_table *tbl,
2160 int (*cb)(struct neighbour *))
2161{
2162 int chain;
2163
2164 for (chain = 0; chain <= tbl->hash_mask; chain++) {
2165 struct neighbour *n, **np;
2166
2167 np = &tbl->hash_buckets[chain];
2168 while ((n = *np) != NULL) {
2169 int release;
2170
2171 write_lock(&n->lock);
2172 release = cb(n);
2173 if (release) {
2174 *np = n->next;
2175 n->dead = 1;
2176 } else
2177 np = &n->next;
2178 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -07002179 if (release)
2180 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 }
2182 }
2183}
2184EXPORT_SYMBOL(__neigh_for_each_release);
2185
2186#ifdef CONFIG_PROC_FS
2187
2188static struct neighbour *neigh_get_first(struct seq_file *seq)
2189{
2190 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002191 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 struct neigh_table *tbl = state->tbl;
2193 struct neighbour *n = NULL;
2194 int bucket = state->bucket;
2195
2196 state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
2197 for (bucket = 0; bucket <= tbl->hash_mask; bucket++) {
2198 n = tbl->hash_buckets[bucket];
2199
2200 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002201 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002202 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 if (state->neigh_sub_iter) {
2204 loff_t fakep = 0;
2205 void *v;
2206
2207 v = state->neigh_sub_iter(state, n, &fakep);
2208 if (!v)
2209 goto next;
2210 }
2211 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2212 break;
2213 if (n->nud_state & ~NUD_NOARP)
2214 break;
2215 next:
2216 n = n->next;
2217 }
2218
2219 if (n)
2220 break;
2221 }
2222 state->bucket = bucket;
2223
2224 return n;
2225}
2226
2227static struct neighbour *neigh_get_next(struct seq_file *seq,
2228 struct neighbour *n,
2229 loff_t *pos)
2230{
2231 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002232 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 struct neigh_table *tbl = state->tbl;
2234
2235 if (state->neigh_sub_iter) {
2236 void *v = state->neigh_sub_iter(state, n, pos);
2237 if (v)
2238 return n;
2239 }
2240 n = n->next;
2241
2242 while (1) {
2243 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002244 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002245 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 if (state->neigh_sub_iter) {
2247 void *v = state->neigh_sub_iter(state, n, pos);
2248 if (v)
2249 return n;
2250 goto next;
2251 }
2252 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2253 break;
2254
2255 if (n->nud_state & ~NUD_NOARP)
2256 break;
2257 next:
2258 n = n->next;
2259 }
2260
2261 if (n)
2262 break;
2263
2264 if (++state->bucket > tbl->hash_mask)
2265 break;
2266
2267 n = tbl->hash_buckets[state->bucket];
2268 }
2269
2270 if (n && pos)
2271 --(*pos);
2272 return n;
2273}
2274
2275static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
2276{
2277 struct neighbour *n = neigh_get_first(seq);
2278
2279 if (n) {
Chris Larson745e2032008-08-03 01:10:55 -07002280 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 while (*pos) {
2282 n = neigh_get_next(seq, n, pos);
2283 if (!n)
2284 break;
2285 }
2286 }
2287 return *pos ? NULL : n;
2288}
2289
2290static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
2291{
2292 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002293 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 struct neigh_table *tbl = state->tbl;
2295 struct pneigh_entry *pn = NULL;
2296 int bucket = state->bucket;
2297
2298 state->flags |= NEIGH_SEQ_IS_PNEIGH;
2299 for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
2300 pn = tbl->phash_buckets[bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002301 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002302 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 if (pn)
2304 break;
2305 }
2306 state->bucket = bucket;
2307
2308 return pn;
2309}
2310
2311static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
2312 struct pneigh_entry *pn,
2313 loff_t *pos)
2314{
2315 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002316 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 struct neigh_table *tbl = state->tbl;
2318
2319 pn = pn->next;
2320 while (!pn) {
2321 if (++state->bucket > PNEIGH_HASHMASK)
2322 break;
2323 pn = tbl->phash_buckets[state->bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002324 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002325 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 if (pn)
2327 break;
2328 }
2329
2330 if (pn && pos)
2331 --(*pos);
2332
2333 return pn;
2334}
2335
2336static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
2337{
2338 struct pneigh_entry *pn = pneigh_get_first(seq);
2339
2340 if (pn) {
Chris Larson745e2032008-08-03 01:10:55 -07002341 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 while (*pos) {
2343 pn = pneigh_get_next(seq, pn, pos);
2344 if (!pn)
2345 break;
2346 }
2347 }
2348 return *pos ? NULL : pn;
2349}
2350
2351static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
2352{
2353 struct neigh_seq_state *state = seq->private;
2354 void *rc;
Chris Larson745e2032008-08-03 01:10:55 -07002355 loff_t idxpos = *pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356
Chris Larson745e2032008-08-03 01:10:55 -07002357 rc = neigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
Chris Larson745e2032008-08-03 01:10:55 -07002359 rc = pneigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
2361 return rc;
2362}
2363
2364void *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 -08002365 __acquires(tbl->lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366{
2367 struct neigh_seq_state *state = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368
2369 state->tbl = tbl;
2370 state->bucket = 0;
2371 state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
2372
2373 read_lock_bh(&tbl->lock);
2374
Chris Larson745e2032008-08-03 01:10:55 -07002375 return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376}
2377EXPORT_SYMBOL(neigh_seq_start);
2378
2379void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2380{
2381 struct neigh_seq_state *state;
2382 void *rc;
2383
2384 if (v == SEQ_START_TOKEN) {
Chris Larsonbff69732008-08-03 01:02:41 -07002385 rc = neigh_get_first(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 goto out;
2387 }
2388
2389 state = seq->private;
2390 if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
2391 rc = neigh_get_next(seq, v, NULL);
2392 if (rc)
2393 goto out;
2394 if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
2395 rc = pneigh_get_first(seq);
2396 } else {
2397 BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
2398 rc = pneigh_get_next(seq, v, NULL);
2399 }
2400out:
2401 ++(*pos);
2402 return rc;
2403}
2404EXPORT_SYMBOL(neigh_seq_next);
2405
2406void neigh_seq_stop(struct seq_file *seq, void *v)
Eric Dumazet9a429c42008-01-01 21:58:02 -08002407 __releases(tbl->lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408{
2409 struct neigh_seq_state *state = seq->private;
2410 struct neigh_table *tbl = state->tbl;
2411
2412 read_unlock_bh(&tbl->lock);
2413}
2414EXPORT_SYMBOL(neigh_seq_stop);
2415
2416/* statistics via seq_file */
2417
2418static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
2419{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002420 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 int cpu;
2422
2423 if (*pos == 0)
2424 return SEQ_START_TOKEN;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002425
Rusty Russell0f23174a2008-12-29 12:23:42 +00002426 for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 if (!cpu_possible(cpu))
2428 continue;
2429 *pos = cpu+1;
2430 return per_cpu_ptr(tbl->stats, cpu);
2431 }
2432 return NULL;
2433}
2434
2435static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2436{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002437 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 int cpu;
2439
Rusty Russell0f23174a2008-12-29 12:23:42 +00002440 for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 if (!cpu_possible(cpu))
2442 continue;
2443 *pos = cpu+1;
2444 return per_cpu_ptr(tbl->stats, cpu);
2445 }
2446 return NULL;
2447}
2448
2449static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
2450{
2451
2452}
2453
2454static int neigh_stat_seq_show(struct seq_file *seq, void *v)
2455{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002456 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 struct neigh_statistics *st = v;
2458
2459 if (v == SEQ_START_TOKEN) {
Neil Horman9a6d2762008-07-16 20:50:49 -07002460 seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs unresolved_discards\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 return 0;
2462 }
2463
2464 seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
Neil Horman9a6d2762008-07-16 20:50:49 -07002465 "%08lx %08lx %08lx %08lx %08lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 atomic_read(&tbl->entries),
2467
2468 st->allocs,
2469 st->destroys,
2470 st->hash_grows,
2471
2472 st->lookups,
2473 st->hits,
2474
2475 st->res_failed,
2476
2477 st->rcv_probes_mcast,
2478 st->rcv_probes_ucast,
2479
2480 st->periodic_gc_runs,
Neil Horman9a6d2762008-07-16 20:50:49 -07002481 st->forced_gc_runs,
2482 st->unres_discards
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 );
2484
2485 return 0;
2486}
2487
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002488static const struct seq_operations neigh_stat_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 .start = neigh_stat_seq_start,
2490 .next = neigh_stat_seq_next,
2491 .stop = neigh_stat_seq_stop,
2492 .show = neigh_stat_seq_show,
2493};
2494
2495static int neigh_stat_seq_open(struct inode *inode, struct file *file)
2496{
2497 int ret = seq_open(file, &neigh_stat_seq_ops);
2498
2499 if (!ret) {
2500 struct seq_file *sf = file->private_data;
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002501 sf->private = PDE(inode)->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 }
2503 return ret;
2504};
2505
Arjan van de Ven9a321442007-02-12 00:55:35 -08002506static const struct file_operations neigh_stat_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 .owner = THIS_MODULE,
2508 .open = neigh_stat_seq_open,
2509 .read = seq_read,
2510 .llseek = seq_lseek,
2511 .release = seq_release,
2512};
2513
2514#endif /* CONFIG_PROC_FS */
2515
Thomas Graf339bf982006-11-10 14:10:15 -08002516static inline size_t neigh_nlmsg_size(void)
2517{
2518 return NLMSG_ALIGN(sizeof(struct ndmsg))
2519 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2520 + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2521 + nla_total_size(sizeof(struct nda_cacheinfo))
2522 + nla_total_size(4); /* NDA_PROBES */
2523}
2524
Thomas Grafb8673312006-08-15 00:33:14 -07002525static void __neigh_notify(struct neighbour *n, int type, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002527 struct net *net = dev_net(n->dev);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002528 struct sk_buff *skb;
Thomas Grafb8673312006-08-15 00:33:14 -07002529 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530
Thomas Graf339bf982006-11-10 14:10:15 -08002531 skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002532 if (skb == NULL)
Thomas Grafb8673312006-08-15 00:33:14 -07002533 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534
Thomas Grafb8673312006-08-15 00:33:14 -07002535 err = neigh_fill_info(skb, n, 0, 0, type, flags);
Patrick McHardy26932562007-01-31 23:16:40 -08002536 if (err < 0) {
2537 /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
2538 WARN_ON(err == -EMSGSIZE);
2539 kfree_skb(skb);
2540 goto errout;
2541 }
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002542 rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
2543 return;
Thomas Grafb8673312006-08-15 00:33:14 -07002544errout:
2545 if (err < 0)
Eric W. Biederman426b5302008-01-24 00:13:18 -08002546 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
Thomas Grafb8673312006-08-15 00:33:14 -07002547}
2548
Thomas Grafd961db32007-08-08 23:12:56 -07002549#ifdef CONFIG_ARPD
Thomas Grafb8673312006-08-15 00:33:14 -07002550void neigh_app_ns(struct neighbour *n)
2551{
2552 __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09002554EXPORT_SYMBOL(neigh_app_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555#endif /* CONFIG_ARPD */
2556
2557#ifdef CONFIG_SYSCTL
2558
Eric W. Biederman54716e32010-02-14 03:27:03 +00002559#define NEIGH_VARS_MAX 19
2560
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561static struct neigh_sysctl_table {
2562 struct ctl_table_header *sysctl_header;
Eric W. Biederman54716e32010-02-14 03:27:03 +00002563 struct ctl_table neigh_vars[NEIGH_VARS_MAX];
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002564 char *dev_name;
Brian Haleyab32ea52006-09-22 14:15:41 -07002565} neigh_sysctl_template __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 .neigh_vars = {
2567 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 .procname = "mcast_solicit",
2569 .maxlen = sizeof(int),
2570 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002571 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 },
2573 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 .procname = "ucast_solicit",
2575 .maxlen = sizeof(int),
2576 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002577 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 },
2579 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 .procname = "app_solicit",
2581 .maxlen = sizeof(int),
2582 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002583 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 },
2585 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 .procname = "retrans_time",
2587 .maxlen = sizeof(int),
2588 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002589 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 },
2591 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 .procname = "base_reachable_time",
2593 .maxlen = sizeof(int),
2594 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002595 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 },
2597 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 .procname = "delay_first_probe_time",
2599 .maxlen = sizeof(int),
2600 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002601 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 },
2603 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 .procname = "gc_stale_time",
2605 .maxlen = sizeof(int),
2606 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002607 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 },
2609 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 .procname = "unres_qlen",
2611 .maxlen = sizeof(int),
2612 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002613 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 },
2615 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 .procname = "proxy_qlen",
2617 .maxlen = sizeof(int),
2618 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002619 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 },
2621 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 .procname = "anycast_delay",
2623 .maxlen = sizeof(int),
2624 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002625 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 },
2627 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 .procname = "proxy_delay",
2629 .maxlen = sizeof(int),
2630 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002631 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 },
2633 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 .procname = "locktime",
2635 .maxlen = sizeof(int),
2636 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002637 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 },
2639 {
Eric W. Biedermand12af672007-10-18 03:05:25 -07002640 .procname = "retrans_time_ms",
2641 .maxlen = sizeof(int),
2642 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002643 .proc_handler = proc_dointvec_ms_jiffies,
Eric W. Biedermand12af672007-10-18 03:05:25 -07002644 },
2645 {
Eric W. Biedermand12af672007-10-18 03:05:25 -07002646 .procname = "base_reachable_time_ms",
2647 .maxlen = sizeof(int),
2648 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002649 .proc_handler = proc_dointvec_ms_jiffies,
Eric W. Biedermand12af672007-10-18 03:05:25 -07002650 },
2651 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 .procname = "gc_interval",
2653 .maxlen = sizeof(int),
2654 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002655 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 },
2657 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 .procname = "gc_thresh1",
2659 .maxlen = sizeof(int),
2660 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002661 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 },
2663 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 .procname = "gc_thresh2",
2665 .maxlen = sizeof(int),
2666 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002667 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 },
2669 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 .procname = "gc_thresh3",
2671 .maxlen = sizeof(int),
2672 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002673 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002675 {},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 },
2677};
2678
2679int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
Eric W. Biederman54716e32010-02-14 03:27:03 +00002680 char *p_name, proc_handler *handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681{
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002682 struct neigh_sysctl_table *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 const char *dev_name_source = NULL;
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002684
2685#define NEIGH_CTL_PATH_ROOT 0
2686#define NEIGH_CTL_PATH_PROTO 1
2687#define NEIGH_CTL_PATH_NEIGH 2
2688#define NEIGH_CTL_PATH_DEV 3
2689
2690 struct ctl_path neigh_path[] = {
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002691 { .procname = "net", },
2692 { .procname = "proto", },
2693 { .procname = "neigh", },
2694 { .procname = "default", },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002695 { },
2696 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002698 t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 if (!t)
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002700 goto err;
2701
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 t->neigh_vars[0].data = &p->mcast_probes;
2703 t->neigh_vars[1].data = &p->ucast_probes;
2704 t->neigh_vars[2].data = &p->app_probes;
2705 t->neigh_vars[3].data = &p->retrans_time;
2706 t->neigh_vars[4].data = &p->base_reachable_time;
2707 t->neigh_vars[5].data = &p->delay_probe_time;
2708 t->neigh_vars[6].data = &p->gc_staletime;
2709 t->neigh_vars[7].data = &p->queue_len;
2710 t->neigh_vars[8].data = &p->proxy_qlen;
2711 t->neigh_vars[9].data = &p->anycast_delay;
2712 t->neigh_vars[10].data = &p->proxy_delay;
2713 t->neigh_vars[11].data = &p->locktime;
Eric W. Biedermand12af672007-10-18 03:05:25 -07002714 t->neigh_vars[12].data = &p->retrans_time;
2715 t->neigh_vars[13].data = &p->base_reachable_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
2717 if (dev) {
2718 dev_name_source = dev->name;
Eric W. Biedermand12af672007-10-18 03:05:25 -07002719 /* Terminate the table early */
2720 memset(&t->neigh_vars[14], 0, sizeof(t->neigh_vars[14]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 } else {
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002722 dev_name_source = neigh_path[NEIGH_CTL_PATH_DEV].procname;
Eric W. Biedermand12af672007-10-18 03:05:25 -07002723 t->neigh_vars[14].data = (int *)(p + 1);
2724 t->neigh_vars[15].data = (int *)(p + 1) + 1;
2725 t->neigh_vars[16].data = (int *)(p + 1) + 2;
2726 t->neigh_vars[17].data = (int *)(p + 1) + 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 }
2728
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002730 if (handler) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 /* RetransTime */
2732 t->neigh_vars[3].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 t->neigh_vars[3].extra1 = dev;
2734 /* ReachableTime */
2735 t->neigh_vars[4].proc_handler = handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 t->neigh_vars[4].extra1 = dev;
2737 /* RetransTime (in milliseconds)*/
Eric W. Biedermand12af672007-10-18 03:05:25 -07002738 t->neigh_vars[12].proc_handler = handler;
Eric W. Biedermand12af672007-10-18 03:05:25 -07002739 t->neigh_vars[12].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 /* ReachableTime (in milliseconds) */
Eric W. Biedermand12af672007-10-18 03:05:25 -07002741 t->neigh_vars[13].proc_handler = handler;
Eric W. Biedermand12af672007-10-18 03:05:25 -07002742 t->neigh_vars[13].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 }
2744
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002745 t->dev_name = kstrdup(dev_name_source, GFP_KERNEL);
2746 if (!t->dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002749 neigh_path[NEIGH_CTL_PATH_DEV].procname = t->dev_name;
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002750 neigh_path[NEIGH_CTL_PATH_PROTO].procname = p_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751
Denis V. Lunev4ab438f2008-02-28 20:48:01 -08002752 t->sysctl_header =
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +09002753 register_net_sysctl_table(neigh_parms_net(p), neigh_path, t->neigh_vars);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002754 if (!t->sysctl_header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 goto free_procname;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002756
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 p->sysctl_table = t;
2758 return 0;
2759
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002760free_procname:
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002761 kfree(t->dev_name);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002762free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 kfree(t);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002764err:
2765 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09002767EXPORT_SYMBOL(neigh_sysctl_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768
2769void neigh_sysctl_unregister(struct neigh_parms *p)
2770{
2771 if (p->sysctl_table) {
2772 struct neigh_sysctl_table *t = p->sysctl_table;
2773 p->sysctl_table = NULL;
2774 unregister_sysctl_table(t->sysctl_header);
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002775 kfree(t->dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 kfree(t);
2777 }
2778}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09002779EXPORT_SYMBOL(neigh_sysctl_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780
2781#endif /* CONFIG_SYSCTL */
2782
Thomas Grafc8822a42007-03-22 11:50:06 -07002783static int __init neigh_init(void)
2784{
2785 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL);
2786 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL);
2787 rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info);
2788
2789 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info);
2790 rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL);
2791
2792 return 0;
2793}
2794
2795subsys_initcall(neigh_init);
2796