blob: 661ad12e0cc9d6a730e194edc82c64dac91dbf75 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Generic address resolution entity
3 *
4 * Authors:
5 * Pedro Roque <roque@di.fc.ul.pt>
6 * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 *
13 * Fixes:
14 * Vitaly E. Lavrov releasing NULL neighbor in neigh_add.
15 * Harald Welte Add neighbour cache statistics like rtstat
16 */
17
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090018#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/types.h>
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/socket.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/netdevice.h>
24#include <linux/proc_fs.h>
25#ifdef CONFIG_SYSCTL
26#include <linux/sysctl.h>
27#endif
28#include <linux/times.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020029#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <net/neighbour.h>
31#include <net/dst.h>
32#include <net/sock.h>
Tom Tucker8d717402006-07-30 20:43:36 -070033#include <net/netevent.h>
Thomas Grafa14a49d2006-08-07 17:53:08 -070034#include <net/netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/rtnetlink.h>
36#include <linux/random.h>
Paulo Marques543537b2005-06-23 00:09:02 -070037#include <linux/string.h>
vignesh babuc3609d52007-08-24 22:27:55 -070038#include <linux/log2.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40#define NEIGH_DEBUG 1
41
42#define NEIGH_PRINTK(x...) printk(x)
43#define NEIGH_NOPRINTK(x...) do { ; } while(0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#define NEIGH_PRINTK1 NEIGH_NOPRINTK
45#define NEIGH_PRINTK2 NEIGH_NOPRINTK
46
47#if NEIGH_DEBUG >= 1
48#undef NEIGH_PRINTK1
49#define NEIGH_PRINTK1 NEIGH_PRINTK
50#endif
51#if NEIGH_DEBUG >= 2
52#undef NEIGH_PRINTK2
53#define NEIGH_PRINTK2 NEIGH_PRINTK
54#endif
55
56#define PNEIGH_HASHMASK 0xF
57
58static void neigh_timer_handler(unsigned long arg);
Thomas Grafd961db32007-08-08 23:12:56 -070059static void __neigh_notify(struct neighbour *n, int type, int flags);
60static void neigh_update_notify(struct neighbour *neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -070061static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63static struct neigh_table *neigh_tables;
Amos Waterland45fc3b12005-09-24 16:53:16 -070064#ifdef CONFIG_PROC_FS
Arjan van de Ven9a321442007-02-12 00:55:35 -080065static const struct file_operations neigh_stat_seq_fops;
Amos Waterland45fc3b12005-09-24 16:53:16 -070066#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68/*
69 Neighbour hash table buckets are protected with rwlock tbl->lock.
70
71 - All the scans/updates to hash buckets MUST be made under this lock.
72 - NOTHING clever should be made under this lock: no callbacks
73 to protocol backends, no attempts to send something to network.
74 It will result in deadlocks, if backend/driver wants to use neighbour
75 cache.
76 - If the entry requires some non-trivial actions, increase
77 its reference count and release table lock.
78
79 Neighbour entries are protected:
80 - with reference count.
81 - with rwlock neigh->lock
82
83 Reference count prevents destruction.
84
85 neigh->lock mainly serializes ll address data and its validity state.
86 However, the same lock is used to protect another entry fields:
87 - timer
88 - resolution queue
89
90 Again, nothing clever shall be made under neigh->lock,
91 the most complicated procedure, which we allow is dev->hard_header.
92 It is supposed, that dev->hard_header is simplistic and does
93 not make callbacks to neighbour tables.
94
95 The last lock is neigh_tbl_lock. It is pure SMP lock, protecting
96 list of neighbour tables. This list is used only in process context,
97 */
98
99static DEFINE_RWLOCK(neigh_tbl_lock);
100
David S. Miller8f40b162011-07-17 13:34:11 -0700101static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102{
103 kfree_skb(skb);
104 return -ENETDOWN;
105}
106
Thomas Graf4f494552007-08-08 23:12:36 -0700107static void neigh_cleanup_and_release(struct neighbour *neigh)
108{
109 if (neigh->parms->neigh_cleanup)
110 neigh->parms->neigh_cleanup(neigh);
111
Thomas Grafd961db32007-08-08 23:12:56 -0700112 __neigh_notify(neigh, RTM_DELNEIGH, 0);
Thomas Graf4f494552007-08-08 23:12:36 -0700113 neigh_release(neigh);
114}
115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116/*
117 * It is random distribution in the interval (1/2)*base...(3/2)*base.
118 * It corresponds to default IPv6 settings and is not overridable,
119 * because it is really reasonable choice.
120 */
121
122unsigned long neigh_rand_reach_time(unsigned long base)
123{
Eric Dumazeta02cec22010-09-22 20:43:57 +0000124 return base ? (net_random() % base) + (base >> 1) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900126EXPORT_SYMBOL(neigh_rand_reach_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128
129static int neigh_forced_gc(struct neigh_table *tbl)
130{
131 int shrunk = 0;
132 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000133 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
135 NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
136
137 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000138 nht = rcu_dereference_protected(tbl->nht,
139 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700140 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700141 struct neighbour *n;
142 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000144 np = &nht->hash_buckets[i];
Eric Dumazet767e97e2010-10-06 17:49:21 -0700145 while ((n = rcu_dereference_protected(*np,
146 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 /* Neighbour record may be discarded if:
148 * - nobody refers to it.
149 * - it is not permanent
150 */
151 write_lock(&n->lock);
152 if (atomic_read(&n->refcnt) == 1 &&
153 !(n->nud_state & NUD_PERMANENT)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700154 rcu_assign_pointer(*np,
155 rcu_dereference_protected(n->next,
156 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 n->dead = 1;
158 shrunk = 1;
159 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700160 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 continue;
162 }
163 write_unlock(&n->lock);
164 np = &n->next;
165 }
166 }
167
168 tbl->last_flush = jiffies;
169
170 write_unlock_bh(&tbl->lock);
171
172 return shrunk;
173}
174
Pavel Emelyanova43d8992007-12-20 15:49:05 -0800175static void neigh_add_timer(struct neighbour *n, unsigned long when)
176{
177 neigh_hold(n);
178 if (unlikely(mod_timer(&n->timer, when))) {
179 printk("NEIGH: BUG, double timer add, state is %x\n",
180 n->nud_state);
181 dump_stack();
182 }
183}
184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185static int neigh_del_timer(struct neighbour *n)
186{
187 if ((n->nud_state & NUD_IN_TIMER) &&
188 del_timer(&n->timer)) {
189 neigh_release(n);
190 return 1;
191 }
192 return 0;
193}
194
195static void pneigh_queue_purge(struct sk_buff_head *list)
196{
197 struct sk_buff *skb;
198
199 while ((skb = skb_dequeue(list)) != NULL) {
200 dev_put(skb->dev);
201 kfree_skb(skb);
202 }
203}
204
Herbert Xu49636bb2005-10-23 17:18:00 +1000205static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206{
207 int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000208 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000210 nht = rcu_dereference_protected(tbl->nht,
211 lockdep_is_held(&tbl->lock));
212
David S. Millercd089332011-07-11 01:28:12 -0700213 for (i = 0; i < (1 << nht->hash_shift); i++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700214 struct neighbour *n;
215 struct neighbour __rcu **np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Eric Dumazet767e97e2010-10-06 17:49:21 -0700217 while ((n = rcu_dereference_protected(*np,
218 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 if (dev && n->dev != dev) {
220 np = &n->next;
221 continue;
222 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700223 rcu_assign_pointer(*np,
224 rcu_dereference_protected(n->next,
225 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 write_lock(&n->lock);
227 neigh_del_timer(n);
228 n->dead = 1;
229
230 if (atomic_read(&n->refcnt) != 1) {
231 /* The most unpleasant situation.
232 We must destroy neighbour entry,
233 but someone still uses it.
234
235 The destroy will be delayed until
236 the last user releases us, but
237 we must kill timers etc. and move
238 it to safe state.
239 */
240 skb_queue_purge(&n->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000241 n->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 n->output = neigh_blackhole;
243 if (n->nud_state & NUD_VALID)
244 n->nud_state = NUD_NOARP;
245 else
246 n->nud_state = NUD_NONE;
247 NEIGH_PRINTK2("neigh %p is stray.\n", n);
248 }
249 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -0700250 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 }
252 }
Herbert Xu49636bb2005-10-23 17:18:00 +1000253}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Herbert Xu49636bb2005-10-23 17:18:00 +1000255void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
256{
257 write_lock_bh(&tbl->lock);
258 neigh_flush_dev(tbl, dev);
259 write_unlock_bh(&tbl->lock);
260}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900261EXPORT_SYMBOL(neigh_changeaddr);
Herbert Xu49636bb2005-10-23 17:18:00 +1000262
263int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
264{
265 write_lock_bh(&tbl->lock);
266 neigh_flush_dev(tbl, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 pneigh_ifdown(tbl, dev);
268 write_unlock_bh(&tbl->lock);
269
270 del_timer_sync(&tbl->proxy_timer);
271 pneigh_queue_purge(&tbl->proxy_queue);
272 return 0;
273}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900274EXPORT_SYMBOL(neigh_ifdown);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
276static struct neighbour *neigh_alloc(struct neigh_table *tbl)
277{
278 struct neighbour *n = NULL;
279 unsigned long now = jiffies;
280 int entries;
281
282 entries = atomic_inc_return(&tbl->entries) - 1;
283 if (entries >= tbl->gc_thresh3 ||
284 (entries >= tbl->gc_thresh2 &&
285 time_after(now, tbl->last_flush + 5 * HZ))) {
286 if (!neigh_forced_gc(tbl) &&
287 entries >= tbl->gc_thresh3)
288 goto out_entries;
289 }
290
David Miller5b8b0062011-07-25 00:01:22 +0000291 n = kzalloc(tbl->entry_size, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 if (!n)
293 goto out_entries;
294
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 skb_queue_head_init(&n->arp_queue);
296 rwlock_init(&n->lock);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +0000297 seqlock_init(&n->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 n->updated = n->used = now;
299 n->nud_state = NUD_NONE;
300 n->output = neigh_blackhole;
David S. Millerf6b72b62011-07-14 07:53:20 -0700301 seqlock_init(&n->hh.hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 n->parms = neigh_parms_clone(&tbl->parms);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800303 setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 NEIGH_CACHE_STAT_INC(tbl, allocs);
306 n->tbl = tbl;
307 atomic_set(&n->refcnt, 1);
308 n->dead = 1;
309out:
310 return n;
311
312out_entries:
313 atomic_dec(&tbl->entries);
314 goto out;
315}
316
David S. Millercd089332011-07-11 01:28:12 -0700317static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
David S. Millercd089332011-07-11 01:28:12 -0700319 size_t size = (1 << shift) * sizeof(struct neighbour *);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000320 struct neigh_hash_table *ret;
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000321 struct neighbour __rcu **buckets;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000323 ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
324 if (!ret)
325 return NULL;
326 if (size <= PAGE_SIZE)
327 buckets = kzalloc(size, GFP_ATOMIC);
328 else
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000329 buckets = (struct neighbour __rcu **)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000330 __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
331 get_order(size));
332 if (!buckets) {
333 kfree(ret);
334 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 }
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000336 ret->hash_buckets = buckets;
David S. Millercd089332011-07-11 01:28:12 -0700337 ret->hash_shift = shift;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000338 get_random_bytes(&ret->hash_rnd, sizeof(ret->hash_rnd));
David S. Millerf610b742011-07-11 01:37:28 -0700339 ret->hash_rnd |= 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 return ret;
341}
342
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000343static void neigh_hash_free_rcu(struct rcu_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000345 struct neigh_hash_table *nht = container_of(head,
346 struct neigh_hash_table,
347 rcu);
David S. Millercd089332011-07-11 01:28:12 -0700348 size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
Eric Dumazet6193d2b2011-01-19 22:02:47 +0000349 struct neighbour __rcu **buckets = nht->hash_buckets;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
351 if (size <= PAGE_SIZE)
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000352 kfree(buckets);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 else
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000354 free_pages((unsigned long)buckets, get_order(size));
355 kfree(nht);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356}
357
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000358static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
David S. Millercd089332011-07-11 01:28:12 -0700359 unsigned long new_shift)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360{
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000361 unsigned int i, hash;
362 struct neigh_hash_table *new_nht, *old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
364 NEIGH_CACHE_STAT_INC(tbl, hash_grows);
365
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000366 old_nht = rcu_dereference_protected(tbl->nht,
367 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -0700368 new_nht = neigh_hash_alloc(new_shift);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000369 if (!new_nht)
370 return old_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
David S. Millercd089332011-07-11 01:28:12 -0700372 for (i = 0; i < (1 << old_nht->hash_shift); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 struct neighbour *n, *next;
374
Eric Dumazet767e97e2010-10-06 17:49:21 -0700375 for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
376 lockdep_is_held(&tbl->lock));
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000377 n != NULL;
378 n = next) {
379 hash = tbl->hash(n->primary_key, n->dev,
380 new_nht->hash_rnd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
David S. Millercd089332011-07-11 01:28:12 -0700382 hash >>= (32 - new_nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700383 next = rcu_dereference_protected(n->next,
384 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Eric Dumazet767e97e2010-10-06 17:49:21 -0700386 rcu_assign_pointer(n->next,
387 rcu_dereference_protected(
388 new_nht->hash_buckets[hash],
389 lockdep_is_held(&tbl->lock)));
390 rcu_assign_pointer(new_nht->hash_buckets[hash], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 }
392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000394 rcu_assign_pointer(tbl->nht, new_nht);
395 call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
396 return new_nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397}
398
399struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
400 struct net_device *dev)
401{
402 struct neighbour *n;
403 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800404 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000405 struct neigh_hash_table *nht;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900406
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 NEIGH_CACHE_STAT_INC(tbl, lookups);
408
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000409 rcu_read_lock_bh();
410 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700411 hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700412
413 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
414 n != NULL;
415 n = rcu_dereference_bh(n->next)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700417 if (!atomic_inc_not_zero(&n->refcnt))
418 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 NEIGH_CACHE_STAT_INC(tbl, hits);
420 break;
421 }
422 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700423
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000424 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 return n;
426}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900427EXPORT_SYMBOL(neigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
Eric W. Biederman426b5302008-01-24 00:13:18 -0800429struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
430 const void *pkey)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431{
432 struct neighbour *n;
433 int key_len = tbl->key_len;
Pavel Emelyanovbc4bf5f2008-02-23 19:57:02 -0800434 u32 hash_val;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000435 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
437 NEIGH_CACHE_STAT_INC(tbl, lookups);
438
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000439 rcu_read_lock_bh();
440 nht = rcu_dereference_bh(tbl->nht);
David S. Millercd089332011-07-11 01:28:12 -0700441 hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700442
443 for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
444 n != NULL;
445 n = rcu_dereference_bh(n->next)) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800446 if (!memcmp(n->primary_key, pkey, key_len) &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900447 net_eq(dev_net(n->dev), net)) {
Eric Dumazet767e97e2010-10-06 17:49:21 -0700448 if (!atomic_inc_not_zero(&n->refcnt))
449 n = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 NEIGH_CACHE_STAT_INC(tbl, hits);
451 break;
452 }
453 }
Eric Dumazet767e97e2010-10-06 17:49:21 -0700454
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000455 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 return n;
457}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900458EXPORT_SYMBOL(neigh_lookup_nodev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
460struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
461 struct net_device *dev)
462{
463 u32 hash_val;
464 int key_len = tbl->key_len;
465 int error;
466 struct neighbour *n1, *rc, *n = neigh_alloc(tbl);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000467 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
469 if (!n) {
470 rc = ERR_PTR(-ENOBUFS);
471 goto out;
472 }
473
474 memcpy(n->primary_key, pkey, key_len);
475 n->dev = dev;
476 dev_hold(dev);
477
478 /* Protocol specific setup. */
479 if (tbl->constructor && (error = tbl->constructor(n)) < 0) {
480 rc = ERR_PTR(error);
481 goto out_neigh_release;
482 }
483
484 /* Device specific setup. */
485 if (n->parms->neigh_setup &&
486 (error = n->parms->neigh_setup(n)) < 0) {
487 rc = ERR_PTR(error);
488 goto out_neigh_release;
489 }
490
491 n->confirmed = jiffies - (n->parms->base_reachable_time << 1);
492
493 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000494 nht = rcu_dereference_protected(tbl->nht,
495 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
David S. Millercd089332011-07-11 01:28:12 -0700497 if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
498 nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
David S. Millercd089332011-07-11 01:28:12 -0700500 hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
502 if (n->parms->dead) {
503 rc = ERR_PTR(-EINVAL);
504 goto out_tbl_unlock;
505 }
506
Eric Dumazet767e97e2010-10-06 17:49:21 -0700507 for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
508 lockdep_is_held(&tbl->lock));
509 n1 != NULL;
510 n1 = rcu_dereference_protected(n1->next,
511 lockdep_is_held(&tbl->lock))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
513 neigh_hold(n1);
514 rc = n1;
515 goto out_tbl_unlock;
516 }
517 }
518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 n->dead = 0;
520 neigh_hold(n);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700521 rcu_assign_pointer(n->next,
522 rcu_dereference_protected(nht->hash_buckets[hash_val],
523 lockdep_is_held(&tbl->lock)));
524 rcu_assign_pointer(nht->hash_buckets[hash_val], n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 write_unlock_bh(&tbl->lock);
526 NEIGH_PRINTK2("neigh %p is created.\n", n);
527 rc = n;
528out:
529 return rc;
530out_tbl_unlock:
531 write_unlock_bh(&tbl->lock);
532out_neigh_release:
533 neigh_release(n);
534 goto out;
535}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900536EXPORT_SYMBOL(neigh_create);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900538static u32 pneigh_hash(const void *pkey, int key_len)
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700539{
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700540 u32 hash_val = *(u32 *)(pkey + key_len - 4);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700541 hash_val ^= (hash_val >> 16);
542 hash_val ^= hash_val >> 8;
543 hash_val ^= hash_val >> 4;
544 hash_val &= PNEIGH_HASHMASK;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900545 return hash_val;
546}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700547
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900548static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
549 struct net *net,
550 const void *pkey,
551 int key_len,
552 struct net_device *dev)
553{
554 while (n) {
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700555 if (!memcmp(n->key, pkey, key_len) &&
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900556 net_eq(pneigh_net(n), net) &&
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700557 (n->dev == dev || !n->dev))
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900558 return n;
559 n = n->next;
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700560 }
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900561 return NULL;
562}
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700563
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900564struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
565 struct net *net, const void *pkey, struct net_device *dev)
566{
567 int key_len = tbl->key_len;
568 u32 hash_val = pneigh_hash(pkey, key_len);
569
570 return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
571 net, pkey, key_len, dev);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700572}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900573EXPORT_SYMBOL_GPL(__pneigh_lookup);
Pavel Emelyanovfa86d322008-03-24 14:48:59 -0700574
Eric W. Biederman426b5302008-01-24 00:13:18 -0800575struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
576 struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 struct net_device *dev, int creat)
578{
579 struct pneigh_entry *n;
580 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900581 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
583 read_lock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900584 n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
585 net, pkey, key_len, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 read_unlock_bh(&tbl->lock);
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900587
588 if (n || !creat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 goto out;
590
Pavel Emelyanov4ae28942007-10-15 12:54:15 -0700591 ASSERT_RTNL();
592
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
594 if (!n)
595 goto out;
596
Eric Dumazete42ea982008-11-12 00:54:54 -0800597 write_pnet(&n->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 memcpy(n->key, pkey, key_len);
599 n->dev = dev;
600 if (dev)
601 dev_hold(dev);
602
603 if (tbl->pconstructor && tbl->pconstructor(n)) {
604 if (dev)
605 dev_put(dev);
Denis V. Lunevda12f732008-02-20 00:26:16 -0800606 release_net(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 kfree(n);
608 n = NULL;
609 goto out;
610 }
611
612 write_lock_bh(&tbl->lock);
613 n->next = tbl->phash_buckets[hash_val];
614 tbl->phash_buckets[hash_val] = n;
615 write_unlock_bh(&tbl->lock);
616out:
617 return n;
618}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900619EXPORT_SYMBOL(pneigh_lookup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
621
Eric W. Biederman426b5302008-01-24 00:13:18 -0800622int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 struct net_device *dev)
624{
625 struct pneigh_entry *n, **np;
626 int key_len = tbl->key_len;
YOSHIFUJI Hideakibe01d652008-03-28 12:46:53 +0900627 u32 hash_val = pneigh_hash(pkey, key_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629 write_lock_bh(&tbl->lock);
630 for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
631 np = &n->next) {
Eric W. Biederman426b5302008-01-24 00:13:18 -0800632 if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +0900633 net_eq(pneigh_net(n), net)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 *np = n->next;
635 write_unlock_bh(&tbl->lock);
636 if (tbl->pdestructor)
637 tbl->pdestructor(n);
638 if (n->dev)
639 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900640 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 kfree(n);
642 return 0;
643 }
644 }
645 write_unlock_bh(&tbl->lock);
646 return -ENOENT;
647}
648
649static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
650{
651 struct pneigh_entry *n, **np;
652 u32 h;
653
654 for (h = 0; h <= PNEIGH_HASHMASK; h++) {
655 np = &tbl->phash_buckets[h];
656 while ((n = *np) != NULL) {
657 if (!dev || n->dev == dev) {
658 *np = n->next;
659 if (tbl->pdestructor)
660 tbl->pdestructor(n);
661 if (n->dev)
662 dev_put(n->dev);
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +0900663 release_net(pneigh_net(n));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 kfree(n);
665 continue;
666 }
667 np = &n->next;
668 }
669 }
670 return -ENOENT;
671}
672
Denis V. Lunev06f05112008-01-24 00:30:58 -0800673static void neigh_parms_destroy(struct neigh_parms *parms);
674
675static inline void neigh_parms_put(struct neigh_parms *parms)
676{
677 if (atomic_dec_and_test(&parms->refcnt))
678 neigh_parms_destroy(parms);
679}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681/*
682 * neighbour must already be out of the table;
683 *
684 */
685void neigh_destroy(struct neighbour *neigh)
686{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
688
689 if (!neigh->dead) {
690 printk(KERN_WARNING
691 "Destroying alive neighbour %p\n", neigh);
692 dump_stack();
693 return;
694 }
695
696 if (neigh_del_timer(neigh))
697 printk(KERN_WARNING "Impossible event.\n");
698
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000700 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 dev_put(neigh->dev);
703 neigh_parms_put(neigh->parms);
704
705 NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh);
706
707 atomic_dec(&neigh->tbl->entries);
David Miller5b8b0062011-07-25 00:01:22 +0000708 kfree_rcu(neigh, rcu);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +0900710EXPORT_SYMBOL(neigh_destroy);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712/* Neighbour state is suspicious;
713 disable fast path.
714
715 Called with write_locked neigh.
716 */
717static void neigh_suspect(struct neighbour *neigh)
718{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
720
721 neigh->output = neigh->ops->output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722}
723
724/* Neighbour state is OK;
725 enable fast path.
726
727 Called with write_locked neigh.
728 */
729static void neigh_connect(struct neighbour *neigh)
730{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 NEIGH_PRINTK2("neigh %p is connected.\n", neigh);
732
733 neigh->output = neigh->ops->connected_output;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734}
735
Eric Dumazete4c4e442009-07-30 03:15:07 +0000736static void neigh_periodic_work(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737{
Eric Dumazete4c4e442009-07-30 03:15:07 +0000738 struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
Eric Dumazet767e97e2010-10-06 17:49:21 -0700739 struct neighbour *n;
740 struct neighbour __rcu **np;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000741 unsigned int i;
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000742 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
744 NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
745
Eric Dumazete4c4e442009-07-30 03:15:07 +0000746 write_lock_bh(&tbl->lock);
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000747 nht = rcu_dereference_protected(tbl->nht,
748 lockdep_is_held(&tbl->lock));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
750 /*
751 * periodically recompute ReachableTime from random function
752 */
753
Eric Dumazete4c4e442009-07-30 03:15:07 +0000754 if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 struct neigh_parms *p;
Eric Dumazete4c4e442009-07-30 03:15:07 +0000756 tbl->last_rand = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 for (p = &tbl->parms; p; p = p->next)
758 p->reachable_time =
759 neigh_rand_reach_time(p->base_reachable_time);
760 }
761
David S. Millercd089332011-07-11 01:28:12 -0700762 for (i = 0 ; i < (1 << nht->hash_shift); i++) {
Eric Dumazetd6bf7812010-10-04 06:15:44 +0000763 np = &nht->hash_buckets[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
Eric Dumazet767e97e2010-10-06 17:49:21 -0700765 while ((n = rcu_dereference_protected(*np,
766 lockdep_is_held(&tbl->lock))) != NULL) {
Eric Dumazete4c4e442009-07-30 03:15:07 +0000767 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
Eric Dumazete4c4e442009-07-30 03:15:07 +0000769 write_lock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Eric Dumazete4c4e442009-07-30 03:15:07 +0000771 state = n->nud_state;
772 if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
773 write_unlock(&n->lock);
774 goto next_elt;
775 }
776
777 if (time_before(n->used, n->confirmed))
778 n->used = n->confirmed;
779
780 if (atomic_read(&n->refcnt) == 1 &&
781 (state == NUD_FAILED ||
782 time_after(jiffies, n->used + n->parms->gc_staletime))) {
783 *np = n->next;
784 n->dead = 1;
785 write_unlock(&n->lock);
786 neigh_cleanup_and_release(n);
787 continue;
788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 write_unlock(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791next_elt:
Eric Dumazete4c4e442009-07-30 03:15:07 +0000792 np = &n->next;
793 }
794 /*
795 * It's fine to release lock here, even if hash table
796 * grows while we are preempted.
797 */
798 write_unlock_bh(&tbl->lock);
799 cond_resched();
800 write_lock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900802 /* Cycle through all hash buckets every base_reachable_time/2 ticks.
803 * ARP entry timeouts range from 1/2 base_reachable_time to 3/2
804 * base_reachable_time.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 */
Eric Dumazete4c4e442009-07-30 03:15:07 +0000806 schedule_delayed_work(&tbl->gc_work,
807 tbl->parms.base_reachable_time >> 1);
808 write_unlock_bh(&tbl->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809}
810
811static __inline__ int neigh_max_probes(struct neighbour *n)
812{
813 struct neigh_parms *p = n->parms;
Eric Dumazeta02cec22010-09-22 20:43:57 +0000814 return (n->nud_state & NUD_PROBE) ?
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 p->ucast_probes :
Eric Dumazeta02cec22010-09-22 20:43:57 +0000816 p->ucast_probes + p->app_probes + p->mcast_probes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817}
818
Timo Teras5ef12d92009-06-11 04:16:28 -0700819static void neigh_invalidate(struct neighbour *neigh)
Eric Dumazet0a141502010-03-09 19:40:54 +0000820 __releases(neigh->lock)
821 __acquires(neigh->lock)
Timo Teras5ef12d92009-06-11 04:16:28 -0700822{
823 struct sk_buff *skb;
824
825 NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
826 NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
827 neigh->updated = jiffies;
828
829 /* It is very thin place. report_unreachable is very complicated
830 routine. Particularly, it can hit the same neighbour entry!
831
832 So that, we try to be accurate and avoid dead loop. --ANK
833 */
834 while (neigh->nud_state == NUD_FAILED &&
835 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
836 write_unlock(&neigh->lock);
837 neigh->ops->error_report(neigh, skb);
838 write_lock(&neigh->lock);
839 }
840 skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000841 neigh->arp_queue_len_bytes = 0;
Timo Teras5ef12d92009-06-11 04:16:28 -0700842}
843
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000844static void neigh_probe(struct neighbour *neigh)
845 __releases(neigh->lock)
846{
847 struct sk_buff *skb = skb_peek(&neigh->arp_queue);
848 /* keep skb alive even if arp_queue overflows */
849 if (skb)
850 skb = skb_copy(skb, GFP_ATOMIC);
851 write_unlock(&neigh->lock);
852 neigh->ops->solicit(neigh, skb);
853 atomic_inc(&neigh->probes);
854 kfree_skb(skb);
855}
856
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857/* Called when a timer expires for a neighbour entry. */
858
859static void neigh_timer_handler(unsigned long arg)
860{
861 unsigned long now, next;
862 struct neighbour *neigh = (struct neighbour *)arg;
863 unsigned state;
864 int notify = 0;
865
866 write_lock(&neigh->lock);
867
868 state = neigh->nud_state;
869 now = jiffies;
870 next = now + HZ;
871
David S. Miller045f7b32011-11-01 17:45:55 -0400872 if (!(state & NUD_IN_TIMER))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
875 if (state & NUD_REACHABLE) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900876 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 neigh->confirmed + neigh->parms->reachable_time)) {
878 NEIGH_PRINTK2("neigh %p is still alive.\n", neigh);
879 next = neigh->confirmed + neigh->parms->reachable_time;
880 } else if (time_before_eq(now,
881 neigh->used + neigh->parms->delay_probe_time)) {
882 NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
883 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800884 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 neigh_suspect(neigh);
886 next = now + neigh->parms->delay_probe_time;
887 } else {
888 NEIGH_PRINTK2("neigh %p is suspected.\n", neigh);
889 neigh->nud_state = NUD_STALE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800890 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 neigh_suspect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700892 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 }
894 } else if (state & NUD_DELAY) {
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +0900895 if (time_before_eq(now,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 neigh->confirmed + neigh->parms->delay_probe_time)) {
897 NEIGH_PRINTK2("neigh %p is now reachable.\n", neigh);
898 neigh->nud_state = NUD_REACHABLE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800899 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 neigh_connect(neigh);
Tom Tucker8d717402006-07-30 20:43:36 -0700901 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 next = neigh->confirmed + neigh->parms->reachable_time;
903 } else {
904 NEIGH_PRINTK2("neigh %p is probed.\n", neigh);
905 neigh->nud_state = NUD_PROBE;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800906 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 atomic_set(&neigh->probes, 0);
908 next = now + neigh->parms->retrans_time;
909 }
910 } else {
911 /* NUD_PROBE|NUD_INCOMPLETE */
912 next = now + neigh->parms->retrans_time;
913 }
914
915 if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
916 atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 neigh->nud_state = NUD_FAILED;
918 notify = 1;
Timo Teras5ef12d92009-06-11 04:16:28 -0700919 neigh_invalidate(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 }
921
922 if (neigh->nud_state & NUD_IN_TIMER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 if (time_before(next, jiffies + HZ/2))
924 next = jiffies + HZ/2;
Herbert Xu6fb99742005-10-23 16:37:48 +1000925 if (!mod_timer(&neigh->timer, next))
926 neigh_hold(neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 }
928 if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000929 neigh_probe(neigh);
David S. Miller9ff56602008-02-17 18:39:54 -0800930 } else {
David S. Miller69cc64d2008-02-11 21:45:44 -0800931out:
David S. Miller9ff56602008-02-17 18:39:54 -0800932 write_unlock(&neigh->lock);
933 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Thomas Grafd961db32007-08-08 23:12:56 -0700935 if (notify)
936 neigh_update_notify(neigh);
937
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 neigh_release(neigh);
939}
940
941int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
942{
943 int rc;
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000944 bool immediate_probe = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 write_lock_bh(&neigh->lock);
947
948 rc = 0;
949 if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
950 goto out_unlock_bh;
951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
953 if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000954 unsigned long next, now = jiffies;
955
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 atomic_set(&neigh->probes, neigh->parms->ucast_probes);
957 neigh->nud_state = NUD_INCOMPLETE;
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000958 neigh->updated = now;
959 next = now + max(neigh->parms->retrans_time, HZ/2);
960 neigh_add_timer(neigh, next);
961 immediate_probe = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 } else {
963 neigh->nud_state = NUD_FAILED;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800964 neigh->updated = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 write_unlock_bh(&neigh->lock);
966
Wei Yongjunf3fbbe02009-02-25 00:37:32 +0000967 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 return 1;
969 }
970 } else if (neigh->nud_state & NUD_STALE) {
971 NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 neigh->nud_state = NUD_DELAY;
YOSHIFUJI Hideaki955aaa22006-03-20 16:52:52 -0800973 neigh->updated = jiffies;
David S. Miller667347f2005-09-27 12:07:44 -0700974 neigh_add_timer(neigh,
975 jiffies + neigh->parms->delay_probe_time);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 }
977
978 if (neigh->nud_state == NUD_INCOMPLETE) {
979 if (skb) {
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000980 while (neigh->arp_queue_len_bytes + skb->truesize >
981 neigh->parms->queue_len_bytes) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 struct sk_buff *buff;
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000983
David S. Millerf72051b2008-09-23 01:11:18 -0700984 buff = __skb_dequeue(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000985 if (!buff)
986 break;
987 neigh->arp_queue_len_bytes -= buff->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 kfree_skb(buff);
Neil Horman9a6d2762008-07-16 20:50:49 -0700989 NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 }
Eric Dumazeta4731132010-05-27 16:09:39 -0700991 skb_dst_force(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 __skb_queue_tail(&neigh->arp_queue, skb);
Eric Dumazet8b5c1712011-11-09 12:07:14 +0000993 neigh->arp_queue_len_bytes += skb->truesize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 }
995 rc = 1;
996 }
997out_unlock_bh:
Eric Dumazetcd28ca02011-08-09 08:15:58 +0000998 if (immediate_probe)
999 neigh_probe(neigh);
1000 else
1001 write_unlock(&neigh->lock);
1002 local_bh_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 return rc;
1004}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001005EXPORT_SYMBOL(__neigh_event_send);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
David S. Millerf6b72b62011-07-14 07:53:20 -07001007static void neigh_update_hhs(struct neighbour *neigh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008{
1009 struct hh_cache *hh;
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001010 void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
Doug Kehn91a72a72010-07-14 18:02:16 -07001011 = NULL;
1012
1013 if (neigh->dev->header_ops)
1014 update = neigh->dev->header_ops->cache_update;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 if (update) {
David S. Millerf6b72b62011-07-14 07:53:20 -07001017 hh = &neigh->hh;
1018 if (hh->hh_len) {
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001019 write_seqlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 update(hh, neigh->dev, neigh->ha);
Stephen Hemminger3644f0c2006-12-07 15:08:17 -08001021 write_sequnlock_bh(&hh->hh_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 }
1023 }
1024}
1025
1026
1027
1028/* Generic update routine.
1029 -- lladdr is new lladdr or NULL, if it is not supplied.
1030 -- new is new state.
1031 -- flags
1032 NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
1033 if it is different.
1034 NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001035 lladdr instead of overriding it
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 if it is different.
1037 It also allows to retain current state
1038 if lladdr is unchanged.
1039 NEIGH_UPDATE_F_ADMIN means that the change is administrative.
1040
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001041 NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 NTF_ROUTER flag.
1043 NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
1044 a router.
1045
1046 Caller MUST hold reference count on the entry.
1047 */
1048
1049int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
1050 u32 flags)
1051{
1052 u8 old;
1053 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 int notify = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 struct net_device *dev;
1056 int update_isrouter = 0;
1057
1058 write_lock_bh(&neigh->lock);
1059
1060 dev = neigh->dev;
1061 old = neigh->nud_state;
1062 err = -EPERM;
1063
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001064 if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 (old & (NUD_NOARP | NUD_PERMANENT)))
1066 goto out;
1067
1068 if (!(new & NUD_VALID)) {
1069 neigh_del_timer(neigh);
1070 if (old & NUD_CONNECTED)
1071 neigh_suspect(neigh);
1072 neigh->nud_state = new;
1073 err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 notify = old & NUD_VALID;
Timo Teras5ef12d92009-06-11 04:16:28 -07001075 if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
1076 (new & NUD_FAILED)) {
1077 neigh_invalidate(neigh);
1078 notify = 1;
1079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 goto out;
1081 }
1082
1083 /* Compare new lladdr with cached one */
1084 if (!dev->addr_len) {
1085 /* First case: device needs no address. */
1086 lladdr = neigh->ha;
1087 } else if (lladdr) {
1088 /* The second case: if something is already cached
1089 and a new address is proposed:
1090 - compare new & old
1091 - if they are different, check override flag
1092 */
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001093 if ((old & NUD_VALID) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 !memcmp(lladdr, neigh->ha, dev->addr_len))
1095 lladdr = neigh->ha;
1096 } else {
1097 /* No address is supplied; if we know something,
1098 use it, otherwise discard the request.
1099 */
1100 err = -EINVAL;
1101 if (!(old & NUD_VALID))
1102 goto out;
1103 lladdr = neigh->ha;
1104 }
1105
1106 if (new & NUD_CONNECTED)
1107 neigh->confirmed = jiffies;
1108 neigh->updated = jiffies;
1109
1110 /* If entry was valid and address is not changed,
1111 do not change entry state, if new one is STALE.
1112 */
1113 err = 0;
1114 update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
1115 if (old & NUD_VALID) {
1116 if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
1117 update_isrouter = 0;
1118 if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
1119 (old & NUD_CONNECTED)) {
1120 lladdr = neigh->ha;
1121 new = NUD_STALE;
1122 } else
1123 goto out;
1124 } else {
1125 if (lladdr == neigh->ha && new == NUD_STALE &&
1126 ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||
1127 (old & NUD_CONNECTED))
1128 )
1129 new = old;
1130 }
1131 }
1132
1133 if (new != old) {
1134 neigh_del_timer(neigh);
Pavel Emelyanova43d8992007-12-20 15:49:05 -08001135 if (new & NUD_IN_TIMER)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001136 neigh_add_timer(neigh, (jiffies +
1137 ((new & NUD_REACHABLE) ?
David S. Miller667347f2005-09-27 12:07:44 -07001138 neigh->parms->reachable_time :
1139 0)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 neigh->nud_state = new;
1141 }
1142
1143 if (lladdr != neigh->ha) {
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001144 write_seqlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 memcpy(&neigh->ha, lladdr, dev->addr_len);
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001146 write_sequnlock(&neigh->ha_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 neigh_update_hhs(neigh);
1148 if (!(new & NUD_CONNECTED))
1149 neigh->confirmed = jiffies -
1150 (neigh->parms->base_reachable_time << 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 notify = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 }
1153 if (new == old)
1154 goto out;
1155 if (new & NUD_CONNECTED)
1156 neigh_connect(neigh);
1157 else
1158 neigh_suspect(neigh);
1159 if (!(old & NUD_VALID)) {
1160 struct sk_buff *skb;
1161
1162 /* Again: avoid dead loop if something went wrong */
1163
1164 while (neigh->nud_state & NUD_VALID &&
1165 (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
David S. Miller69cce1d2011-07-17 23:09:49 -07001166 struct dst_entry *dst = skb_dst(skb);
1167 struct neighbour *n2, *n1 = neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 write_unlock_bh(&neigh->lock);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001169
1170 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 /* On shaper/eql skb->dst->neighbour != neigh :( */
David S. Miller69cce1d2011-07-17 23:09:49 -07001172 if (dst && (n2 = dst_get_neighbour(dst)) != NULL)
1173 n1 = n2;
David S. Miller8f40b162011-07-17 13:34:11 -07001174 n1->output(n1, skb);
roy.qing.li@gmail.come049f282011-10-17 22:32:42 +00001175 rcu_read_unlock();
1176
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 write_lock_bh(&neigh->lock);
1178 }
1179 skb_queue_purge(&neigh->arp_queue);
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001180 neigh->arp_queue_len_bytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 }
1182out:
1183 if (update_isrouter) {
1184 neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?
1185 (neigh->flags | NTF_ROUTER) :
1186 (neigh->flags & ~NTF_ROUTER);
1187 }
1188 write_unlock_bh(&neigh->lock);
Tom Tucker8d717402006-07-30 20:43:36 -07001189
1190 if (notify)
Thomas Grafd961db32007-08-08 23:12:56 -07001191 neigh_update_notify(neigh);
1192
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 return err;
1194}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001195EXPORT_SYMBOL(neigh_update);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
1197struct neighbour *neigh_event_ns(struct neigh_table *tbl,
1198 u8 *lladdr, void *saddr,
1199 struct net_device *dev)
1200{
1201 struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
1202 lladdr || !dev->addr_len);
1203 if (neigh)
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001204 neigh_update(neigh, lladdr, NUD_STALE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 NEIGH_UPDATE_F_OVERRIDE);
1206 return neigh;
1207}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001208EXPORT_SYMBOL(neigh_event_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
Eric Dumazet34d101d2010-10-11 09:16:57 -07001210/* called with read_lock_bh(&n->lock); */
David S. Millerf6b72b62011-07-14 07:53:20 -07001211static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 struct net_device *dev = dst->dev;
David S. Millerf6b72b62011-07-14 07:53:20 -07001214 __be16 prot = dst->ops->protocol;
1215 struct hh_cache *hh = &n->hh;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001216
1217 write_lock_bh(&n->lock);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001218
David S. Millerf6b72b62011-07-14 07:53:20 -07001219 /* Only one thread can come in here and initialize the
1220 * hh_cache entry.
1221 */
David S. Millerb23b5452011-07-16 17:45:02 -07001222 if (!hh->hh_len)
1223 dev->header_ops->cache(n, hh, prot);
David S. Millerf6b72b62011-07-14 07:53:20 -07001224
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001225 write_unlock_bh(&n->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226}
1227
1228/* This function can be used in contexts, where only old dev_queue_xmit
Eric Dumazet767e97e2010-10-06 17:49:21 -07001229 * worked, f.e. if you want to override normal output path (eql, shaper),
1230 * but resolution is not made yet.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 */
1232
David S. Miller8f40b162011-07-17 13:34:11 -07001233int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234{
1235 struct net_device *dev = skb->dev;
1236
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001237 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Stephen Hemminger0c4e8582007-10-09 01:36:32 -07001239 if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
1240 skb->len) < 0 &&
Stephen Hemminger3b04ddd2007-10-09 01:40:57 -07001241 dev->header_ops->rebuild(skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 return 0;
1243
1244 return dev_queue_xmit(skb);
1245}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001246EXPORT_SYMBOL(neigh_compat_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
1248/* Slow and careful. */
1249
David S. Miller8f40b162011-07-17 13:34:11 -07001250int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251{
Eric Dumazetadf30902009-06-02 05:19:30 +00001252 struct dst_entry *dst = skb_dst(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 int rc = 0;
1254
David S. Miller8f40b162011-07-17 13:34:11 -07001255 if (!dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 goto discard;
1257
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001258 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
1260 if (!neigh_event_send(neigh, skb)) {
1261 int err;
1262 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001263 unsigned int seq;
Eric Dumazet34d101d2010-10-11 09:16:57 -07001264
David S. Millerf6b72b62011-07-14 07:53:20 -07001265 if (dev->header_ops->cache && !neigh->hh.hh_len)
1266 neigh_hh_init(neigh, dst);
Eric Dumazet34d101d2010-10-11 09:16:57 -07001267
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001268 do {
1269 seq = read_seqbegin(&neigh->ha_lock);
1270 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1271 neigh->ha, NULL, skb->len);
1272 } while (read_seqretry(&neigh->ha_lock, seq));
Eric Dumazet34d101d2010-10-11 09:16:57 -07001273
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001275 rc = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 else
1277 goto out_kfree_skb;
1278 }
1279out:
1280 return rc;
1281discard:
1282 NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
David S. Miller8f40b162011-07-17 13:34:11 -07001283 dst, neigh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284out_kfree_skb:
1285 rc = -EINVAL;
1286 kfree_skb(skb);
1287 goto out;
1288}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001289EXPORT_SYMBOL(neigh_resolve_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
1291/* As fast as possible without hh cache */
1292
David S. Miller8f40b162011-07-17 13:34:11 -07001293int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 struct net_device *dev = neigh->dev;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001296 unsigned int seq;
David S. Miller8f40b162011-07-17 13:34:11 -07001297 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Arnaldo Carvalho de Melobbe735e2007-03-10 22:16:10 -03001299 __skb_pull(skb, skb_network_offset(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00001301 do {
1302 seq = read_seqbegin(&neigh->ha_lock);
1303 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
1304 neigh->ha, NULL, skb->len);
1305 } while (read_seqretry(&neigh->ha_lock, seq));
1306
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 if (err >= 0)
David S. Miller542d4d62011-07-16 18:06:24 -07001308 err = dev_queue_xmit(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 else {
1310 err = -EINVAL;
1311 kfree_skb(skb);
1312 }
1313 return err;
1314}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001315EXPORT_SYMBOL(neigh_connected_output);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316
David S. Miller8f40b162011-07-17 13:34:11 -07001317int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
1318{
1319 return dev_queue_xmit(skb);
1320}
1321EXPORT_SYMBOL(neigh_direct_output);
1322
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323static void neigh_proxy_process(unsigned long arg)
1324{
1325 struct neigh_table *tbl = (struct neigh_table *)arg;
1326 long sched_next = 0;
1327 unsigned long now = jiffies;
David S. Millerf72051b2008-09-23 01:11:18 -07001328 struct sk_buff *skb, *n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329
1330 spin_lock(&tbl->proxy_queue.lock);
1331
David S. Millerf72051b2008-09-23 01:11:18 -07001332 skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
1333 long tdif = NEIGH_CB(skb)->sched_next - now;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 if (tdif <= 0) {
David S. Millerf72051b2008-09-23 01:11:18 -07001336 struct net_device *dev = skb->dev;
Eric Dumazet20e60742011-08-22 19:32:42 +00001337
David S. Millerf72051b2008-09-23 01:11:18 -07001338 __skb_unlink(skb, &tbl->proxy_queue);
Eric Dumazet20e60742011-08-22 19:32:42 +00001339 if (tbl->proxy_redo && netif_running(dev)) {
1340 rcu_read_lock();
David S. Millerf72051b2008-09-23 01:11:18 -07001341 tbl->proxy_redo(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001342 rcu_read_unlock();
1343 } else {
David S. Millerf72051b2008-09-23 01:11:18 -07001344 kfree_skb(skb);
Eric Dumazet20e60742011-08-22 19:32:42 +00001345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
1347 dev_put(dev);
1348 } else if (!sched_next || tdif < sched_next)
1349 sched_next = tdif;
1350 }
1351 del_timer(&tbl->proxy_timer);
1352 if (sched_next)
1353 mod_timer(&tbl->proxy_timer, jiffies + sched_next);
1354 spin_unlock(&tbl->proxy_queue.lock);
1355}
1356
1357void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
1358 struct sk_buff *skb)
1359{
1360 unsigned long now = jiffies;
1361 unsigned long sched_next = now + (net_random() % p->proxy_delay);
1362
1363 if (tbl->proxy_queue.qlen > p->proxy_qlen) {
1364 kfree_skb(skb);
1365 return;
1366 }
Patrick McHardya61bbcf2005-08-14 17:24:31 -07001367
1368 NEIGH_CB(skb)->sched_next = sched_next;
1369 NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
1371 spin_lock(&tbl->proxy_queue.lock);
1372 if (del_timer(&tbl->proxy_timer)) {
1373 if (time_before(tbl->proxy_timer.expires, sched_next))
1374 sched_next = tbl->proxy_timer.expires;
1375 }
Eric Dumazetadf30902009-06-02 05:19:30 +00001376 skb_dst_drop(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 dev_hold(skb->dev);
1378 __skb_queue_tail(&tbl->proxy_queue, skb);
1379 mod_timer(&tbl->proxy_timer, sched_next);
1380 spin_unlock(&tbl->proxy_queue.lock);
1381}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001382EXPORT_SYMBOL(pneigh_enqueue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001384static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
Eric W. Biederman426b5302008-01-24 00:13:18 -08001385 struct net *net, int ifindex)
1386{
1387 struct neigh_parms *p;
1388
1389 for (p = &tbl->parms; p; p = p->next) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09001390 if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
Eric W. Biederman426b5302008-01-24 00:13:18 -08001391 (!p->dev && !ifindex))
1392 return p;
1393 }
1394
1395 return NULL;
1396}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
1398struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
1399 struct neigh_table *tbl)
1400{
Eric W. Biederman426b5302008-01-24 00:13:18 -08001401 struct neigh_parms *p, *ref;
Stephen Hemminger00829822008-11-20 20:14:53 -08001402 struct net *net = dev_net(dev);
1403 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001405 ref = lookup_neigh_parms(tbl, net, 0);
Eric W. Biederman426b5302008-01-24 00:13:18 -08001406 if (!ref)
1407 return NULL;
1408
1409 p = kmemdup(ref, sizeof(*p), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 if (p) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 p->tbl = tbl;
1412 atomic_set(&p->refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 p->reachable_time =
1414 neigh_rand_reach_time(p->base_reachable_time);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001415
Stephen Hemminger00829822008-11-20 20:14:53 -08001416 if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001417 kfree(p);
1418 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 }
Denis V. Lunev486b51d2008-01-14 22:59:59 -08001420
1421 dev_hold(dev);
1422 p->dev = dev;
Eric Dumazete42ea982008-11-12 00:54:54 -08001423 write_pnet(&p->net, hold_net(net));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 p->sysctl_table = NULL;
1425 write_lock_bh(&tbl->lock);
1426 p->next = tbl->parms.next;
1427 tbl->parms.next = p;
1428 write_unlock_bh(&tbl->lock);
1429 }
1430 return p;
1431}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001432EXPORT_SYMBOL(neigh_parms_alloc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433
1434static void neigh_rcu_free_parms(struct rcu_head *head)
1435{
1436 struct neigh_parms *parms =
1437 container_of(head, struct neigh_parms, rcu_head);
1438
1439 neigh_parms_put(parms);
1440}
1441
1442void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
1443{
1444 struct neigh_parms **p;
1445
1446 if (!parms || parms == &tbl->parms)
1447 return;
1448 write_lock_bh(&tbl->lock);
1449 for (p = &tbl->parms.next; *p; p = &(*p)->next) {
1450 if (*p == parms) {
1451 *p = parms->next;
1452 parms->dead = 1;
1453 write_unlock_bh(&tbl->lock);
David S. Millercecbb632008-01-20 16:39:03 -08001454 if (parms->dev)
1455 dev_put(parms->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
1457 return;
1458 }
1459 }
1460 write_unlock_bh(&tbl->lock);
1461 NEIGH_PRINTK1("neigh_parms_release: not found\n");
1462}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001463EXPORT_SYMBOL(neigh_parms_release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Denis V. Lunev06f05112008-01-24 00:30:58 -08001465static void neigh_parms_destroy(struct neigh_parms *parms)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466{
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +09001467 release_net(neigh_parms_net(parms));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 kfree(parms);
1469}
1470
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001471static struct lock_class_key neigh_table_proxy_queue_class;
1472
Simon Kelleybd89efc2006-05-12 14:56:08 -07001473void neigh_table_init_no_netlink(struct neigh_table *tbl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474{
1475 unsigned long now = jiffies;
1476 unsigned long phsize;
1477
Eric Dumazete42ea982008-11-12 00:54:54 -08001478 write_pnet(&tbl->parms.net, &init_net);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 atomic_set(&tbl->parms.refcnt, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 tbl->parms.reachable_time =
1481 neigh_rand_reach_time(tbl->parms.base_reachable_time);
1482
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 tbl->stats = alloc_percpu(struct neigh_statistics);
1484 if (!tbl->stats)
1485 panic("cannot create neighbour cache statistics");
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001486
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487#ifdef CONFIG_PROC_FS
Alexey Dobriyan9b739ba2008-11-11 16:47:44 -08001488 if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat,
1489 &neigh_stat_seq_fops, tbl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 panic("cannot create neighbour proc dir entry");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491#endif
1492
David S. Millercd089332011-07-11 01:28:12 -07001493 RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494
1495 phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
Andrew Morton77d04bd2006-04-07 14:52:59 -07001496 tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001498 if (!tbl->nht || !tbl->phash_buckets)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 panic("cannot allocate neighbour cache hashes");
1500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 rwlock_init(&tbl->lock);
Eric Dumazete4c4e442009-07-30 03:15:07 +00001502 INIT_DELAYED_WORK_DEFERRABLE(&tbl->gc_work, neigh_periodic_work);
1503 schedule_delayed_work(&tbl->gc_work, tbl->parms.reachable_time);
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08001504 setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl);
Pavel Emelianovc2ecba72007-04-17 12:45:31 -07001505 skb_queue_head_init_class(&tbl->proxy_queue,
1506 &neigh_table_proxy_queue_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507
1508 tbl->last_flush = now;
1509 tbl->last_rand = now + tbl->parms.reachable_time * 20;
Simon Kelleybd89efc2006-05-12 14:56:08 -07001510}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001511EXPORT_SYMBOL(neigh_table_init_no_netlink);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001512
1513void neigh_table_init(struct neigh_table *tbl)
1514{
1515 struct neigh_table *tmp;
1516
1517 neigh_table_init_no_netlink(tbl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 write_lock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001519 for (tmp = neigh_tables; tmp; tmp = tmp->next) {
1520 if (tmp->family == tbl->family)
1521 break;
1522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 tbl->next = neigh_tables;
1524 neigh_tables = tbl;
1525 write_unlock(&neigh_tbl_lock);
Simon Kelleybd89efc2006-05-12 14:56:08 -07001526
1527 if (unlikely(tmp)) {
1528 printk(KERN_ERR "NEIGH: Registering multiple tables for "
1529 "family %d\n", tbl->family);
1530 dump_stack();
1531 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001533EXPORT_SYMBOL(neigh_table_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
1535int neigh_table_clear(struct neigh_table *tbl)
1536{
1537 struct neigh_table **tp;
1538
1539 /* It is not clean... Fix it to unload IPv6 module safely */
Tejun Heoa5c30b32010-10-19 06:04:42 +00001540 cancel_delayed_work_sync(&tbl->gc_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 del_timer_sync(&tbl->proxy_timer);
1542 pneigh_queue_purge(&tbl->proxy_queue);
1543 neigh_ifdown(tbl, NULL);
1544 if (atomic_read(&tbl->entries))
1545 printk(KERN_CRIT "neighbour leakage\n");
1546 write_lock(&neigh_tbl_lock);
1547 for (tp = &neigh_tables; *tp; tp = &(*tp)->next) {
1548 if (*tp == tbl) {
1549 *tp = tbl->next;
1550 break;
1551 }
1552 }
1553 write_unlock(&neigh_tbl_lock);
1554
Eric Dumazet6193d2b2011-01-19 22:02:47 +00001555 call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
1556 neigh_hash_free_rcu);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001557 tbl->nht = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
1559 kfree(tbl->phash_buckets);
1560 tbl->phash_buckets = NULL;
1561
Alexey Dobriyan3f192b52007-11-05 21:28:13 -08001562 remove_proc_entry(tbl->id, init_net.proc_net_stat);
1563
Kirill Korotaev3fcde742006-09-01 01:34:10 -07001564 free_percpu(tbl->stats);
1565 tbl->stats = NULL;
1566
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 return 0;
1568}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09001569EXPORT_SYMBOL(neigh_table_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570
Thomas Grafc8822a42007-03-22 11:50:06 -07001571static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001573 struct net *net = sock_net(skb->sk);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001574 struct ndmsg *ndm;
1575 struct nlattr *dst_attr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 struct neigh_table *tbl;
1577 struct net_device *dev = NULL;
Thomas Grafa14a49d2006-08-07 17:53:08 -07001578 int err = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
Eric Dumazet110b2492010-10-04 04:27:36 +00001580 ASSERT_RTNL();
Thomas Grafa14a49d2006-08-07 17:53:08 -07001581 if (nlmsg_len(nlh) < sizeof(*ndm))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 goto out;
1583
Thomas Grafa14a49d2006-08-07 17:53:08 -07001584 dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
1585 if (dst_attr == NULL)
1586 goto out;
1587
1588 ndm = nlmsg_data(nlh);
1589 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001590 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001591 if (dev == NULL) {
1592 err = -ENODEV;
1593 goto out;
1594 }
1595 }
1596
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 read_lock(&neigh_tbl_lock);
1598 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Grafa14a49d2006-08-07 17:53:08 -07001599 struct neighbour *neigh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600
1601 if (tbl->family != ndm->ndm_family)
1602 continue;
1603 read_unlock(&neigh_tbl_lock);
1604
Thomas Grafa14a49d2006-08-07 17:53:08 -07001605 if (nla_len(dst_attr) < tbl->key_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001606 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607
1608 if (ndm->ndm_flags & NTF_PROXY) {
Eric W. Biederman426b5302008-01-24 00:13:18 -08001609 err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
Eric Dumazet110b2492010-10-04 04:27:36 +00001610 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 }
1612
Thomas Grafa14a49d2006-08-07 17:53:08 -07001613 if (dev == NULL)
Eric Dumazet110b2492010-10-04 04:27:36 +00001614 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615
Thomas Grafa14a49d2006-08-07 17:53:08 -07001616 neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
1617 if (neigh == NULL) {
1618 err = -ENOENT;
Eric Dumazet110b2492010-10-04 04:27:36 +00001619 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 }
Thomas Grafa14a49d2006-08-07 17:53:08 -07001621
1622 err = neigh_update(neigh, NULL, NUD_FAILED,
1623 NEIGH_UPDATE_F_OVERRIDE |
1624 NEIGH_UPDATE_F_ADMIN);
1625 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001626 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 }
1628 read_unlock(&neigh_tbl_lock);
Thomas Grafa14a49d2006-08-07 17:53:08 -07001629 err = -EAFNOSUPPORT;
1630
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631out:
1632 return err;
1633}
1634
Thomas Grafc8822a42007-03-22 11:50:06 -07001635static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001637 struct net *net = sock_net(skb->sk);
Thomas Graf5208deb2006-08-07 17:55:40 -07001638 struct ndmsg *ndm;
1639 struct nlattr *tb[NDA_MAX+1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 struct neigh_table *tbl;
1641 struct net_device *dev = NULL;
Thomas Graf5208deb2006-08-07 17:55:40 -07001642 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
Eric Dumazet110b2492010-10-04 04:27:36 +00001644 ASSERT_RTNL();
Thomas Graf5208deb2006-08-07 17:55:40 -07001645 err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
1646 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 goto out;
1648
Thomas Graf5208deb2006-08-07 17:55:40 -07001649 err = -EINVAL;
1650 if (tb[NDA_DST] == NULL)
1651 goto out;
1652
1653 ndm = nlmsg_data(nlh);
1654 if (ndm->ndm_ifindex) {
Eric Dumazet110b2492010-10-04 04:27:36 +00001655 dev = __dev_get_by_index(net, ndm->ndm_ifindex);
Thomas Graf5208deb2006-08-07 17:55:40 -07001656 if (dev == NULL) {
1657 err = -ENODEV;
1658 goto out;
1659 }
1660
1661 if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001662 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001663 }
1664
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 read_lock(&neigh_tbl_lock);
1666 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
Thomas Graf5208deb2006-08-07 17:55:40 -07001667 int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
1668 struct neighbour *neigh;
1669 void *dst, *lladdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671 if (tbl->family != ndm->ndm_family)
1672 continue;
1673 read_unlock(&neigh_tbl_lock);
1674
Thomas Graf5208deb2006-08-07 17:55:40 -07001675 if (nla_len(tb[NDA_DST]) < tbl->key_len)
Eric Dumazet110b2492010-10-04 04:27:36 +00001676 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001677 dst = nla_data(tb[NDA_DST]);
1678 lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679
1680 if (ndm->ndm_flags & NTF_PROXY) {
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001681 struct pneigh_entry *pn;
1682
1683 err = -ENOBUFS;
Eric W. Biederman426b5302008-01-24 00:13:18 -08001684 pn = pneigh_lookup(tbl, net, dst, dev, 1);
Ville Nuorvala62dd9312006-09-22 14:43:19 -07001685 if (pn) {
1686 pn->flags = ndm->ndm_flags;
1687 err = 0;
1688 }
Eric Dumazet110b2492010-10-04 04:27:36 +00001689 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 }
1691
Thomas Graf5208deb2006-08-07 17:55:40 -07001692 if (dev == NULL)
Eric Dumazet110b2492010-10-04 04:27:36 +00001693 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001694
1695 neigh = neigh_lookup(tbl, dst, dev);
1696 if (neigh == NULL) {
1697 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
1698 err = -ENOENT;
Eric Dumazet110b2492010-10-04 04:27:36 +00001699 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001700 }
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001701
Thomas Graf5208deb2006-08-07 17:55:40 -07001702 neigh = __neigh_lookup_errno(tbl, dst, dev);
1703 if (IS_ERR(neigh)) {
1704 err = PTR_ERR(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001705 goto out;
Thomas Graf5208deb2006-08-07 17:55:40 -07001706 }
1707 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 if (nlh->nlmsg_flags & NLM_F_EXCL) {
1709 err = -EEXIST;
Thomas Graf5208deb2006-08-07 17:55:40 -07001710 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001711 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 }
Thomas Graf5208deb2006-08-07 17:55:40 -07001713
1714 if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
1715 flags &= ~NEIGH_UPDATE_F_OVERRIDE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 }
1717
Eric Biederman0c5c2d32009-03-04 00:03:08 -08001718 if (ndm->ndm_flags & NTF_USE) {
1719 neigh_event_send(neigh, NULL);
1720 err = 0;
1721 } else
1722 err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
Thomas Graf5208deb2006-08-07 17:55:40 -07001723 neigh_release(neigh);
Eric Dumazet110b2492010-10-04 04:27:36 +00001724 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 }
1726
1727 read_unlock(&neigh_tbl_lock);
Thomas Graf5208deb2006-08-07 17:55:40 -07001728 err = -EAFNOSUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729out:
1730 return err;
1731}
1732
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001733static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
1734{
Thomas Grafca860fb2006-08-07 18:00:18 -07001735 struct nlattr *nest;
1736
1737 nest = nla_nest_start(skb, NDTA_PARMS);
1738 if (nest == NULL)
1739 return -ENOBUFS;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001740
1741 if (parms->dev)
Thomas Grafca860fb2006-08-07 18:00:18 -07001742 NLA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001743
Thomas Grafca860fb2006-08-07 18:00:18 -07001744 NLA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt));
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001745 NLA_PUT_U32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes);
1746 /* approximative value for deprecated QUEUE_LEN (in packets) */
1747 NLA_PUT_U32(skb, NDTPA_QUEUE_LEN,
1748 DIV_ROUND_UP(parms->queue_len_bytes,
1749 SKB_TRUESIZE(ETH_FRAME_LEN)));
Thomas Grafca860fb2006-08-07 18:00:18 -07001750 NLA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen);
1751 NLA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes);
1752 NLA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes);
1753 NLA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes);
1754 NLA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time);
1755 NLA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001756 parms->base_reachable_time);
Thomas Grafca860fb2006-08-07 18:00:18 -07001757 NLA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime);
1758 NLA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time);
1759 NLA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time);
1760 NLA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay);
1761 NLA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay);
1762 NLA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001763
Thomas Grafca860fb2006-08-07 18:00:18 -07001764 return nla_nest_end(skb, nest);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001765
Thomas Grafca860fb2006-08-07 18:00:18 -07001766nla_put_failure:
Thomas Grafbc3ed282008-06-03 16:36:54 -07001767 nla_nest_cancel(skb, nest);
1768 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001769}
1770
Thomas Grafca860fb2006-08-07 18:00:18 -07001771static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
1772 u32 pid, u32 seq, int type, int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001773{
1774 struct nlmsghdr *nlh;
1775 struct ndtmsg *ndtmsg;
1776
Thomas Grafca860fb2006-08-07 18:00:18 -07001777 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1778 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001779 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001780
Thomas Grafca860fb2006-08-07 18:00:18 -07001781 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001782
1783 read_lock_bh(&tbl->lock);
1784 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001785 ndtmsg->ndtm_pad1 = 0;
1786 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001787
Thomas Grafca860fb2006-08-07 18:00:18 -07001788 NLA_PUT_STRING(skb, NDTA_NAME, tbl->id);
1789 NLA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval);
1790 NLA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1);
1791 NLA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2);
1792 NLA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001793
1794 {
1795 unsigned long now = jiffies;
1796 unsigned int flush_delta = now - tbl->last_flush;
1797 unsigned int rand_delta = now - tbl->last_rand;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001798 struct neigh_hash_table *nht;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001799 struct ndt_config ndc = {
1800 .ndtc_key_len = tbl->key_len,
1801 .ndtc_entry_size = tbl->entry_size,
1802 .ndtc_entries = atomic_read(&tbl->entries),
1803 .ndtc_last_flush = jiffies_to_msecs(flush_delta),
1804 .ndtc_last_rand = jiffies_to_msecs(rand_delta),
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001805 .ndtc_proxy_qlen = tbl->proxy_queue.qlen,
1806 };
1807
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001808 rcu_read_lock_bh();
1809 nht = rcu_dereference_bh(tbl->nht);
1810 ndc.ndtc_hash_rnd = nht->hash_rnd;
David S. Millercd089332011-07-11 01:28:12 -07001811 ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00001812 rcu_read_unlock_bh();
1813
Thomas Grafca860fb2006-08-07 18:00:18 -07001814 NLA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001815 }
1816
1817 {
1818 int cpu;
1819 struct ndt_stats ndst;
1820
1821 memset(&ndst, 0, sizeof(ndst));
1822
KAMEZAWA Hiroyuki6f912042006-04-10 22:52:50 -07001823 for_each_possible_cpu(cpu) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001824 struct neigh_statistics *st;
1825
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001826 st = per_cpu_ptr(tbl->stats, cpu);
1827 ndst.ndts_allocs += st->allocs;
1828 ndst.ndts_destroys += st->destroys;
1829 ndst.ndts_hash_grows += st->hash_grows;
1830 ndst.ndts_res_failed += st->res_failed;
1831 ndst.ndts_lookups += st->lookups;
1832 ndst.ndts_hits += st->hits;
1833 ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast;
1834 ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast;
1835 ndst.ndts_periodic_gc_runs += st->periodic_gc_runs;
1836 ndst.ndts_forced_gc_runs += st->forced_gc_runs;
1837 }
1838
Thomas Grafca860fb2006-08-07 18:00:18 -07001839 NLA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001840 }
1841
1842 BUG_ON(tbl->parms.dev);
1843 if (neightbl_fill_parms(skb, &tbl->parms) < 0)
Thomas Grafca860fb2006-08-07 18:00:18 -07001844 goto nla_put_failure;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001845
1846 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001847 return nlmsg_end(skb, nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001848
Thomas Grafca860fb2006-08-07 18:00:18 -07001849nla_put_failure:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001850 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001851 nlmsg_cancel(skb, nlh);
1852 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001853}
1854
Thomas Grafca860fb2006-08-07 18:00:18 -07001855static int neightbl_fill_param_info(struct sk_buff *skb,
1856 struct neigh_table *tbl,
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001857 struct neigh_parms *parms,
Thomas Grafca860fb2006-08-07 18:00:18 -07001858 u32 pid, u32 seq, int type,
1859 unsigned int flags)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001860{
1861 struct ndtmsg *ndtmsg;
1862 struct nlmsghdr *nlh;
1863
Thomas Grafca860fb2006-08-07 18:00:18 -07001864 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
1865 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08001866 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001867
Thomas Grafca860fb2006-08-07 18:00:18 -07001868 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001869
1870 read_lock_bh(&tbl->lock);
1871 ndtmsg->ndtm_family = tbl->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07001872 ndtmsg->ndtm_pad1 = 0;
1873 ndtmsg->ndtm_pad2 = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001874
Thomas Grafca860fb2006-08-07 18:00:18 -07001875 if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
1876 neightbl_fill_parms(skb, parms) < 0)
1877 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001878
1879 read_unlock_bh(&tbl->lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07001880 return nlmsg_end(skb, nlh);
1881errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001882 read_unlock_bh(&tbl->lock);
Patrick McHardy26932562007-01-31 23:16:40 -08001883 nlmsg_cancel(skb, nlh);
1884 return -EMSGSIZE;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001885}
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001886
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001887static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001888 [NDTA_NAME] = { .type = NLA_STRING },
1889 [NDTA_THRESH1] = { .type = NLA_U32 },
1890 [NDTA_THRESH2] = { .type = NLA_U32 },
1891 [NDTA_THRESH3] = { .type = NLA_U32 },
1892 [NDTA_GC_INTERVAL] = { .type = NLA_U64 },
1893 [NDTA_PARMS] = { .type = NLA_NESTED },
1894};
1895
Patrick McHardyef7c79e2007-06-05 12:38:30 -07001896static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
Thomas Graf6b3f8672006-08-07 17:58:53 -07001897 [NDTPA_IFINDEX] = { .type = NLA_U32 },
1898 [NDTPA_QUEUE_LEN] = { .type = NLA_U32 },
1899 [NDTPA_PROXY_QLEN] = { .type = NLA_U32 },
1900 [NDTPA_APP_PROBES] = { .type = NLA_U32 },
1901 [NDTPA_UCAST_PROBES] = { .type = NLA_U32 },
1902 [NDTPA_MCAST_PROBES] = { .type = NLA_U32 },
1903 [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 },
1904 [NDTPA_GC_STALETIME] = { .type = NLA_U64 },
1905 [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 },
1906 [NDTPA_RETRANS_TIME] = { .type = NLA_U64 },
1907 [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 },
1908 [NDTPA_PROXY_DELAY] = { .type = NLA_U64 },
1909 [NDTPA_LOCKTIME] = { .type = NLA_U64 },
1910};
1911
Thomas Grafc8822a42007-03-22 11:50:06 -07001912static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001913{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09001914 struct net *net = sock_net(skb->sk);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001915 struct neigh_table *tbl;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001916 struct ndtmsg *ndtmsg;
1917 struct nlattr *tb[NDTA_MAX+1];
1918 int err;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001919
Thomas Graf6b3f8672006-08-07 17:58:53 -07001920 err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
1921 nl_neightbl_policy);
1922 if (err < 0)
1923 goto errout;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001924
Thomas Graf6b3f8672006-08-07 17:58:53 -07001925 if (tb[NDTA_NAME] == NULL) {
1926 err = -EINVAL;
1927 goto errout;
1928 }
1929
1930 ndtmsg = nlmsg_data(nlh);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001931 read_lock(&neigh_tbl_lock);
1932 for (tbl = neigh_tables; tbl; tbl = tbl->next) {
1933 if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
1934 continue;
1935
Thomas Graf6b3f8672006-08-07 17:58:53 -07001936 if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001937 break;
1938 }
1939
1940 if (tbl == NULL) {
1941 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001942 goto errout_locked;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001943 }
1944
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09001945 /*
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001946 * We acquire tbl->lock to be nice to the periodic timers and
1947 * make sure they always see a consistent set of values.
1948 */
1949 write_lock_bh(&tbl->lock);
1950
Thomas Graf6b3f8672006-08-07 17:58:53 -07001951 if (tb[NDTA_PARMS]) {
1952 struct nlattr *tbp[NDTPA_MAX+1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001953 struct neigh_parms *p;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001954 int i, ifindex = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001955
Thomas Graf6b3f8672006-08-07 17:58:53 -07001956 err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
1957 nl_ntbl_parm_policy);
1958 if (err < 0)
1959 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001960
Thomas Graf6b3f8672006-08-07 17:58:53 -07001961 if (tbp[NDTPA_IFINDEX])
1962 ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001963
Tobias Klauser97fd5bc2009-07-13 11:17:49 -07001964 p = lookup_neigh_parms(tbl, net, ifindex);
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001965 if (p == NULL) {
1966 err = -ENOENT;
Thomas Graf6b3f8672006-08-07 17:58:53 -07001967 goto errout_tbl_lock;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001968 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001969
Thomas Graf6b3f8672006-08-07 17:58:53 -07001970 for (i = 1; i <= NDTPA_MAX; i++) {
1971 if (tbp[i] == NULL)
1972 continue;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07001973
Thomas Graf6b3f8672006-08-07 17:58:53 -07001974 switch (i) {
1975 case NDTPA_QUEUE_LEN:
Eric Dumazet8b5c1712011-11-09 12:07:14 +00001976 p->queue_len_bytes = nla_get_u32(tbp[i]) *
1977 SKB_TRUESIZE(ETH_FRAME_LEN);
1978 break;
1979 case NDTPA_QUEUE_LENBYTES:
1980 p->queue_len_bytes = nla_get_u32(tbp[i]);
Thomas Graf6b3f8672006-08-07 17:58:53 -07001981 break;
1982 case NDTPA_PROXY_QLEN:
1983 p->proxy_qlen = nla_get_u32(tbp[i]);
1984 break;
1985 case NDTPA_APP_PROBES:
1986 p->app_probes = nla_get_u32(tbp[i]);
1987 break;
1988 case NDTPA_UCAST_PROBES:
1989 p->ucast_probes = nla_get_u32(tbp[i]);
1990 break;
1991 case NDTPA_MCAST_PROBES:
1992 p->mcast_probes = nla_get_u32(tbp[i]);
1993 break;
1994 case NDTPA_BASE_REACHABLE_TIME:
1995 p->base_reachable_time = nla_get_msecs(tbp[i]);
1996 break;
1997 case NDTPA_GC_STALETIME:
1998 p->gc_staletime = nla_get_msecs(tbp[i]);
1999 break;
2000 case NDTPA_DELAY_PROBE_TIME:
2001 p->delay_probe_time = nla_get_msecs(tbp[i]);
2002 break;
2003 case NDTPA_RETRANS_TIME:
2004 p->retrans_time = nla_get_msecs(tbp[i]);
2005 break;
2006 case NDTPA_ANYCAST_DELAY:
2007 p->anycast_delay = nla_get_msecs(tbp[i]);
2008 break;
2009 case NDTPA_PROXY_DELAY:
2010 p->proxy_delay = nla_get_msecs(tbp[i]);
2011 break;
2012 case NDTPA_LOCKTIME:
2013 p->locktime = nla_get_msecs(tbp[i]);
2014 break;
2015 }
2016 }
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002017 }
2018
Thomas Graf6b3f8672006-08-07 17:58:53 -07002019 if (tb[NDTA_THRESH1])
2020 tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
2021
2022 if (tb[NDTA_THRESH2])
2023 tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
2024
2025 if (tb[NDTA_THRESH3])
2026 tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
2027
2028 if (tb[NDTA_GC_INTERVAL])
2029 tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
2030
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002031 err = 0;
2032
Thomas Graf6b3f8672006-08-07 17:58:53 -07002033errout_tbl_lock:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002034 write_unlock_bh(&tbl->lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002035errout_locked:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002036 read_unlock(&neigh_tbl_lock);
Thomas Graf6b3f8672006-08-07 17:58:53 -07002037errout:
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002038 return err;
2039}
2040
Thomas Grafc8822a42007-03-22 11:50:06 -07002041static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002042{
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002043 struct net *net = sock_net(skb->sk);
Thomas Grafca860fb2006-08-07 18:00:18 -07002044 int family, tidx, nidx = 0;
2045 int tbl_skip = cb->args[0];
2046 int neigh_skip = cb->args[1];
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002047 struct neigh_table *tbl;
2048
Thomas Grafca860fb2006-08-07 18:00:18 -07002049 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002050
2051 read_lock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07002052 for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) {
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002053 struct neigh_parms *p;
2054
Thomas Grafca860fb2006-08-07 18:00:18 -07002055 if (tidx < tbl_skip || (family && tbl->family != family))
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002056 continue;
2057
Thomas Grafca860fb2006-08-07 18:00:18 -07002058 if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).pid,
2059 cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
2060 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002061 break;
2062
Eric W. Biederman426b5302008-01-24 00:13:18 -08002063 for (nidx = 0, p = tbl->parms.next; p; p = p->next) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002064 if (!net_eq(neigh_parms_net(p), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002065 continue;
2066
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002067 if (nidx < neigh_skip)
2068 goto next;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002069
Thomas Grafca860fb2006-08-07 18:00:18 -07002070 if (neightbl_fill_param_info(skb, tbl, p,
2071 NETLINK_CB(cb->skb).pid,
2072 cb->nlh->nlmsg_seq,
2073 RTM_NEWNEIGHTBL,
2074 NLM_F_MULTI) <= 0)
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002075 goto out;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002076 next:
2077 nidx++;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002078 }
2079
Thomas Grafca860fb2006-08-07 18:00:18 -07002080 neigh_skip = 0;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002081 }
2082out:
2083 read_unlock(&neigh_tbl_lock);
Thomas Grafca860fb2006-08-07 18:00:18 -07002084 cb->args[0] = tidx;
2085 cb->args[1] = nidx;
Thomas Grafc7fb64d2005-06-18 22:50:55 -07002086
2087 return skb->len;
2088}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089
Thomas Graf8b8aec52006-08-07 17:56:37 -07002090static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
2091 u32 pid, u32 seq, int type, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092{
2093 unsigned long now = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 struct nda_cacheinfo ci;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002095 struct nlmsghdr *nlh;
2096 struct ndmsg *ndm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097
Thomas Graf8b8aec52006-08-07 17:56:37 -07002098 nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
2099 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -08002100 return -EMSGSIZE;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002101
2102 ndm = nlmsg_data(nlh);
2103 ndm->ndm_family = neigh->ops->family;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -07002104 ndm->ndm_pad1 = 0;
2105 ndm->ndm_pad2 = 0;
Thomas Graf8b8aec52006-08-07 17:56:37 -07002106 ndm->ndm_flags = neigh->flags;
2107 ndm->ndm_type = neigh->type;
2108 ndm->ndm_ifindex = neigh->dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109
Thomas Graf8b8aec52006-08-07 17:56:37 -07002110 NLA_PUT(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key);
2111
2112 read_lock_bh(&neigh->lock);
2113 ndm->ndm_state = neigh->nud_state;
Eric Dumazet0ed8ddf2010-10-07 10:44:07 +00002114 if (neigh->nud_state & NUD_VALID) {
2115 char haddr[MAX_ADDR_LEN];
2116
2117 neigh_ha_snapshot(haddr, neigh, neigh->dev);
2118 if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
2119 read_unlock_bh(&neigh->lock);
2120 goto nla_put_failure;
2121 }
Thomas Graf8b8aec52006-08-07 17:56:37 -07002122 }
2123
Stephen Hemmingerb9f5f522008-06-03 16:03:15 -07002124 ci.ndm_used = jiffies_to_clock_t(now - neigh->used);
2125 ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
2126 ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002127 ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1;
2128 read_unlock_bh(&neigh->lock);
2129
2130 NLA_PUT_U32(skb, NDA_PROBES, atomic_read(&neigh->probes));
2131 NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
2132
2133 return nlmsg_end(skb, nlh);
2134
2135nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -08002136 nlmsg_cancel(skb, nlh);
2137 return -EMSGSIZE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138}
2139
Thomas Grafd961db32007-08-08 23:12:56 -07002140static void neigh_update_notify(struct neighbour *neigh)
2141{
2142 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
2143 __neigh_notify(neigh, RTM_NEWNEIGH, 0);
2144}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145
2146static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2147 struct netlink_callback *cb)
2148{
Eric Dumazet767e97e2010-10-06 17:49:21 -07002149 struct net *net = sock_net(skb->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 struct neighbour *n;
2151 int rc, h, s_h = cb->args[1];
2152 int idx, s_idx = idx = cb->args[2];
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002153 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002155 rcu_read_lock_bh();
2156 nht = rcu_dereference_bh(tbl->nht);
2157
David S. Millercd089332011-07-11 01:28:12 -07002158 for (h = 0; h < (1 << nht->hash_shift); h++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 if (h < s_h)
2160 continue;
2161 if (h > s_h)
2162 s_idx = 0;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002163 for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
2164 n != NULL;
2165 n = rcu_dereference_bh(n->next)) {
Octavian Purdila09ad9bc2009-11-25 15:14:13 -08002166 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002167 continue;
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002168 if (idx < s_idx)
2169 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid,
2171 cb->nlh->nlmsg_seq,
Jamal Hadi Salimb6544c02005-06-18 22:54:12 -07002172 RTM_NEWNEIGH,
2173 NLM_F_MULTI) <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 rc = -1;
2175 goto out;
2176 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002177next:
Gautam Kachrooefc683f2009-02-06 00:52:04 -08002178 idx++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 }
2181 rc = skb->len;
2182out:
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002183 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 cb->args[1] = h;
2185 cb->args[2] = idx;
2186 return rc;
2187}
2188
Thomas Grafc8822a42007-03-22 11:50:06 -07002189static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190{
2191 struct neigh_table *tbl;
2192 int t, family, s_t;
2193
2194 read_lock(&neigh_tbl_lock);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002195 family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 s_t = cb->args[0];
2197
2198 for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) {
2199 if (t < s_t || (family && tbl->family != family))
2200 continue;
2201 if (t > s_t)
2202 memset(&cb->args[1], 0, sizeof(cb->args) -
2203 sizeof(cb->args[0]));
2204 if (neigh_dump_table(tbl, skb, cb) < 0)
2205 break;
2206 }
2207 read_unlock(&neigh_tbl_lock);
2208
2209 cb->args[0] = t;
2210 return skb->len;
2211}
2212
2213void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
2214{
2215 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002216 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002218 rcu_read_lock_bh();
2219 nht = rcu_dereference_bh(tbl->nht);
2220
Eric Dumazet767e97e2010-10-06 17:49:21 -07002221 read_lock(&tbl->lock); /* avoid resizes */
David S. Millercd089332011-07-11 01:28:12 -07002222 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 struct neighbour *n;
2224
Eric Dumazet767e97e2010-10-06 17:49:21 -07002225 for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
2226 n != NULL;
2227 n = rcu_dereference_bh(n->next))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 cb(n, cookie);
2229 }
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002230 read_unlock(&tbl->lock);
2231 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232}
2233EXPORT_SYMBOL(neigh_for_each);
2234
2235/* The tbl->lock must be held as a writer and BH disabled. */
2236void __neigh_for_each_release(struct neigh_table *tbl,
2237 int (*cb)(struct neighbour *))
2238{
2239 int chain;
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002240 struct neigh_hash_table *nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002242 nht = rcu_dereference_protected(tbl->nht,
2243 lockdep_is_held(&tbl->lock));
David S. Millercd089332011-07-11 01:28:12 -07002244 for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002245 struct neighbour *n;
2246 struct neighbour __rcu **np;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002248 np = &nht->hash_buckets[chain];
Eric Dumazet767e97e2010-10-06 17:49:21 -07002249 while ((n = rcu_dereference_protected(*np,
2250 lockdep_is_held(&tbl->lock))) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 int release;
2252
2253 write_lock(&n->lock);
2254 release = cb(n);
2255 if (release) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002256 rcu_assign_pointer(*np,
2257 rcu_dereference_protected(n->next,
2258 lockdep_is_held(&tbl->lock)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 n->dead = 1;
2260 } else
2261 np = &n->next;
2262 write_unlock(&n->lock);
Thomas Graf4f494552007-08-08 23:12:36 -07002263 if (release)
2264 neigh_cleanup_and_release(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 }
2266 }
2267}
2268EXPORT_SYMBOL(__neigh_for_each_release);
2269
2270#ifdef CONFIG_PROC_FS
2271
2272static struct neighbour *neigh_get_first(struct seq_file *seq)
2273{
2274 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002275 struct net *net = seq_file_net(seq);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002276 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 struct neighbour *n = NULL;
2278 int bucket = state->bucket;
2279
2280 state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
David S. Millercd089332011-07-11 01:28:12 -07002281 for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
Eric Dumazet767e97e2010-10-06 17:49:21 -07002282 n = rcu_dereference_bh(nht->hash_buckets[bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283
2284 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002285 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002286 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 if (state->neigh_sub_iter) {
2288 loff_t fakep = 0;
2289 void *v;
2290
2291 v = state->neigh_sub_iter(state, n, &fakep);
2292 if (!v)
2293 goto next;
2294 }
2295 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2296 break;
2297 if (n->nud_state & ~NUD_NOARP)
2298 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002299next:
2300 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 }
2302
2303 if (n)
2304 break;
2305 }
2306 state->bucket = bucket;
2307
2308 return n;
2309}
2310
2311static struct neighbour *neigh_get_next(struct seq_file *seq,
2312 struct neighbour *n,
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);
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002317 struct neigh_hash_table *nht = state->nht;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
2319 if (state->neigh_sub_iter) {
2320 void *v = state->neigh_sub_iter(state, n, pos);
2321 if (v)
2322 return n;
2323 }
Eric Dumazet767e97e2010-10-06 17:49:21 -07002324 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325
2326 while (1) {
2327 while (n) {
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002328 if (!net_eq(dev_net(n->dev), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002329 goto next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 if (state->neigh_sub_iter) {
2331 void *v = state->neigh_sub_iter(state, n, pos);
2332 if (v)
2333 return n;
2334 goto next;
2335 }
2336 if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
2337 break;
2338
2339 if (n->nud_state & ~NUD_NOARP)
2340 break;
Eric Dumazet767e97e2010-10-06 17:49:21 -07002341next:
2342 n = rcu_dereference_bh(n->next);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 }
2344
2345 if (n)
2346 break;
2347
David S. Millercd089332011-07-11 01:28:12 -07002348 if (++state->bucket >= (1 << nht->hash_shift))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 break;
2350
Eric Dumazet767e97e2010-10-06 17:49:21 -07002351 n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 }
2353
2354 if (n && pos)
2355 --(*pos);
2356 return n;
2357}
2358
2359static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
2360{
2361 struct neighbour *n = neigh_get_first(seq);
2362
2363 if (n) {
Chris Larson745e2032008-08-03 01:10:55 -07002364 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 while (*pos) {
2366 n = neigh_get_next(seq, n, pos);
2367 if (!n)
2368 break;
2369 }
2370 }
2371 return *pos ? NULL : n;
2372}
2373
2374static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
2375{
2376 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002377 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 struct neigh_table *tbl = state->tbl;
2379 struct pneigh_entry *pn = NULL;
2380 int bucket = state->bucket;
2381
2382 state->flags |= NEIGH_SEQ_IS_PNEIGH;
2383 for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
2384 pn = tbl->phash_buckets[bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002385 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002386 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 if (pn)
2388 break;
2389 }
2390 state->bucket = bucket;
2391
2392 return pn;
2393}
2394
2395static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
2396 struct pneigh_entry *pn,
2397 loff_t *pos)
2398{
2399 struct neigh_seq_state *state = seq->private;
YOSHIFUJI Hideaki12188542008-03-26 02:36:06 +09002400 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 struct neigh_table *tbl = state->tbl;
2402
Jorge Boncompte [DTI2]df07a942011-11-25 13:24:49 -05002403 do {
2404 pn = pn->next;
2405 } while (pn && !net_eq(pneigh_net(pn), net));
2406
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 while (!pn) {
2408 if (++state->bucket > PNEIGH_HASHMASK)
2409 break;
2410 pn = tbl->phash_buckets[state->bucket];
YOSHIFUJI Hideaki878628f2008-03-26 03:57:35 +09002411 while (pn && !net_eq(pneigh_net(pn), net))
Eric W. Biederman426b5302008-01-24 00:13:18 -08002412 pn = pn->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 if (pn)
2414 break;
2415 }
2416
2417 if (pn && pos)
2418 --(*pos);
2419
2420 return pn;
2421}
2422
2423static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
2424{
2425 struct pneigh_entry *pn = pneigh_get_first(seq);
2426
2427 if (pn) {
Chris Larson745e2032008-08-03 01:10:55 -07002428 --(*pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 while (*pos) {
2430 pn = pneigh_get_next(seq, pn, pos);
2431 if (!pn)
2432 break;
2433 }
2434 }
2435 return *pos ? NULL : pn;
2436}
2437
2438static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
2439{
2440 struct neigh_seq_state *state = seq->private;
2441 void *rc;
Chris Larson745e2032008-08-03 01:10:55 -07002442 loff_t idxpos = *pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
Chris Larson745e2032008-08-03 01:10:55 -07002444 rc = neigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
Chris Larson745e2032008-08-03 01:10:55 -07002446 rc = pneigh_get_idx(seq, &idxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447
2448 return rc;
2449}
2450
2451void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002452 __acquires(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453{
2454 struct neigh_seq_state *state = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
2456 state->tbl = tbl;
2457 state->bucket = 0;
2458 state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
2459
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002460 rcu_read_lock_bh();
2461 state->nht = rcu_dereference_bh(tbl->nht);
Eric Dumazet767e97e2010-10-06 17:49:21 -07002462
Chris Larson745e2032008-08-03 01:10:55 -07002463 return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464}
2465EXPORT_SYMBOL(neigh_seq_start);
2466
2467void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2468{
2469 struct neigh_seq_state *state;
2470 void *rc;
2471
2472 if (v == SEQ_START_TOKEN) {
Chris Larsonbff69732008-08-03 01:02:41 -07002473 rc = neigh_get_first(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 goto out;
2475 }
2476
2477 state = seq->private;
2478 if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
2479 rc = neigh_get_next(seq, v, NULL);
2480 if (rc)
2481 goto out;
2482 if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
2483 rc = pneigh_get_first(seq);
2484 } else {
2485 BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
2486 rc = pneigh_get_next(seq, v, NULL);
2487 }
2488out:
2489 ++(*pos);
2490 return rc;
2491}
2492EXPORT_SYMBOL(neigh_seq_next);
2493
2494void neigh_seq_stop(struct seq_file *seq, void *v)
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002495 __releases(rcu_bh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496{
Eric Dumazetd6bf7812010-10-04 06:15:44 +00002497 rcu_read_unlock_bh();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498}
2499EXPORT_SYMBOL(neigh_seq_stop);
2500
2501/* statistics via seq_file */
2502
2503static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
2504{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002505 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 int cpu;
2507
2508 if (*pos == 0)
2509 return SEQ_START_TOKEN;
YOSHIFUJI Hideaki4ec93ed2007-02-09 23:24:36 +09002510
Rusty Russell0f23174a2008-12-29 12:23:42 +00002511 for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 if (!cpu_possible(cpu))
2513 continue;
2514 *pos = cpu+1;
2515 return per_cpu_ptr(tbl->stats, cpu);
2516 }
2517 return NULL;
2518}
2519
2520static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2521{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002522 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 int cpu;
2524
Rusty Russell0f23174a2008-12-29 12:23:42 +00002525 for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 if (!cpu_possible(cpu))
2527 continue;
2528 *pos = cpu+1;
2529 return per_cpu_ptr(tbl->stats, cpu);
2530 }
2531 return NULL;
2532}
2533
2534static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
2535{
2536
2537}
2538
2539static int neigh_stat_seq_show(struct seq_file *seq, void *v)
2540{
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002541 struct neigh_table *tbl = seq->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 struct neigh_statistics *st = v;
2543
2544 if (v == SEQ_START_TOKEN) {
Neil Horman9a6d2762008-07-16 20:50:49 -07002545 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 -07002546 return 0;
2547 }
2548
2549 seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx "
Neil Horman9a6d2762008-07-16 20:50:49 -07002550 "%08lx %08lx %08lx %08lx %08lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 atomic_read(&tbl->entries),
2552
2553 st->allocs,
2554 st->destroys,
2555 st->hash_grows,
2556
2557 st->lookups,
2558 st->hits,
2559
2560 st->res_failed,
2561
2562 st->rcv_probes_mcast,
2563 st->rcv_probes_ucast,
2564
2565 st->periodic_gc_runs,
Neil Horman9a6d2762008-07-16 20:50:49 -07002566 st->forced_gc_runs,
2567 st->unres_discards
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 );
2569
2570 return 0;
2571}
2572
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002573static const struct seq_operations neigh_stat_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 .start = neigh_stat_seq_start,
2575 .next = neigh_stat_seq_next,
2576 .stop = neigh_stat_seq_stop,
2577 .show = neigh_stat_seq_show,
2578};
2579
2580static int neigh_stat_seq_open(struct inode *inode, struct file *file)
2581{
2582 int ret = seq_open(file, &neigh_stat_seq_ops);
2583
2584 if (!ret) {
2585 struct seq_file *sf = file->private_data;
Alexey Dobriyan81c1ebf2010-01-22 10:16:05 +00002586 sf->private = PDE(inode)->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 }
2588 return ret;
2589};
2590
Arjan van de Ven9a321442007-02-12 00:55:35 -08002591static const struct file_operations neigh_stat_seq_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 .owner = THIS_MODULE,
2593 .open = neigh_stat_seq_open,
2594 .read = seq_read,
2595 .llseek = seq_lseek,
2596 .release = seq_release,
2597};
2598
2599#endif /* CONFIG_PROC_FS */
2600
Thomas Graf339bf982006-11-10 14:10:15 -08002601static inline size_t neigh_nlmsg_size(void)
2602{
2603 return NLMSG_ALIGN(sizeof(struct ndmsg))
2604 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2605 + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2606 + nla_total_size(sizeof(struct nda_cacheinfo))
2607 + nla_total_size(4); /* NDA_PROBES */
2608}
2609
Thomas Grafb8673312006-08-15 00:33:14 -07002610static void __neigh_notify(struct neighbour *n, int type, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611{
YOSHIFUJI Hideakic346dca2008-03-25 21:47:49 +09002612 struct net *net = dev_net(n->dev);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002613 struct sk_buff *skb;
Thomas Grafb8673312006-08-15 00:33:14 -07002614 int err = -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615
Thomas Graf339bf982006-11-10 14:10:15 -08002616 skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
Thomas Graf8b8aec52006-08-07 17:56:37 -07002617 if (skb == NULL)
Thomas Grafb8673312006-08-15 00:33:14 -07002618 goto errout;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619
Thomas Grafb8673312006-08-15 00:33:14 -07002620 err = neigh_fill_info(skb, n, 0, 0, type, flags);
Patrick McHardy26932562007-01-31 23:16:40 -08002621 if (err < 0) {
2622 /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
2623 WARN_ON(err == -EMSGSIZE);
2624 kfree_skb(skb);
2625 goto errout;
2626 }
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -08002627 rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
2628 return;
Thomas Grafb8673312006-08-15 00:33:14 -07002629errout:
2630 if (err < 0)
Eric W. Biederman426b5302008-01-24 00:13:18 -08002631 rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
Thomas Grafb8673312006-08-15 00:33:14 -07002632}
2633
Thomas Grafd961db32007-08-08 23:12:56 -07002634#ifdef CONFIG_ARPD
Thomas Grafb8673312006-08-15 00:33:14 -07002635void neigh_app_ns(struct neighbour *n)
2636{
2637 __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09002639EXPORT_SYMBOL(neigh_app_ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640#endif /* CONFIG_ARPD */
2641
2642#ifdef CONFIG_SYSCTL
2643
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002644static int proc_unres_qlen(ctl_table *ctl, int write, void __user *buffer,
2645 size_t *lenp, loff_t *ppos)
2646{
2647 int size, ret;
2648 ctl_table tmp = *ctl;
2649
2650 tmp.data = &size;
2651 size = DIV_ROUND_UP(*(int *)ctl->data, SKB_TRUESIZE(ETH_FRAME_LEN));
2652 ret = proc_dointvec(&tmp, write, buffer, lenp, ppos);
2653 if (write && !ret)
2654 *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
2655 return ret;
2656}
2657
2658enum {
2659 NEIGH_VAR_MCAST_PROBE,
2660 NEIGH_VAR_UCAST_PROBE,
2661 NEIGH_VAR_APP_PROBE,
2662 NEIGH_VAR_RETRANS_TIME,
2663 NEIGH_VAR_BASE_REACHABLE_TIME,
2664 NEIGH_VAR_DELAY_PROBE_TIME,
2665 NEIGH_VAR_GC_STALETIME,
2666 NEIGH_VAR_QUEUE_LEN,
2667 NEIGH_VAR_QUEUE_LEN_BYTES,
2668 NEIGH_VAR_PROXY_QLEN,
2669 NEIGH_VAR_ANYCAST_DELAY,
2670 NEIGH_VAR_PROXY_DELAY,
2671 NEIGH_VAR_LOCKTIME,
2672 NEIGH_VAR_RETRANS_TIME_MS,
2673 NEIGH_VAR_BASE_REACHABLE_TIME_MS,
2674 NEIGH_VAR_GC_INTERVAL,
2675 NEIGH_VAR_GC_THRESH1,
2676 NEIGH_VAR_GC_THRESH2,
2677 NEIGH_VAR_GC_THRESH3,
2678 NEIGH_VAR_MAX
2679};
Eric W. Biederman54716e32010-02-14 03:27:03 +00002680
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681static struct neigh_sysctl_table {
2682 struct ctl_table_header *sysctl_header;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002683 struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002684 char *dev_name;
Brian Haleyab32ea52006-09-22 14:15:41 -07002685} neigh_sysctl_template __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 .neigh_vars = {
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002687 [NEIGH_VAR_MCAST_PROBE] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 .procname = "mcast_solicit",
2689 .maxlen = sizeof(int),
2690 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002691 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002693 [NEIGH_VAR_UCAST_PROBE] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 .procname = "ucast_solicit",
2695 .maxlen = sizeof(int),
2696 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002697 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002699 [NEIGH_VAR_APP_PROBE] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 .procname = "app_solicit",
2701 .maxlen = sizeof(int),
2702 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002703 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002705 [NEIGH_VAR_RETRANS_TIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 .procname = "retrans_time",
2707 .maxlen = sizeof(int),
2708 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002709 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002711 [NEIGH_VAR_BASE_REACHABLE_TIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 .procname = "base_reachable_time",
2713 .maxlen = sizeof(int),
2714 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002715 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002717 [NEIGH_VAR_DELAY_PROBE_TIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 .procname = "delay_first_probe_time",
2719 .maxlen = sizeof(int),
2720 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002721 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002723 [NEIGH_VAR_GC_STALETIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 .procname = "gc_stale_time",
2725 .maxlen = sizeof(int),
2726 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002727 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002729 [NEIGH_VAR_QUEUE_LEN] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 .procname = "unres_qlen",
2731 .maxlen = sizeof(int),
2732 .mode = 0644,
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002733 .proc_handler = proc_unres_qlen,
2734 },
2735 [NEIGH_VAR_QUEUE_LEN_BYTES] = {
2736 .procname = "unres_qlen_bytes",
2737 .maxlen = sizeof(int),
2738 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002739 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002741 [NEIGH_VAR_PROXY_QLEN] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 .procname = "proxy_qlen",
2743 .maxlen = sizeof(int),
2744 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002745 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002747 [NEIGH_VAR_ANYCAST_DELAY] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 .procname = "anycast_delay",
2749 .maxlen = sizeof(int),
2750 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002751 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002753 [NEIGH_VAR_PROXY_DELAY] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 .procname = "proxy_delay",
2755 .maxlen = sizeof(int),
2756 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002757 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002759 [NEIGH_VAR_LOCKTIME] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 .procname = "locktime",
2761 .maxlen = sizeof(int),
2762 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002763 .proc_handler = proc_dointvec_userhz_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002765 [NEIGH_VAR_RETRANS_TIME_MS] = {
Eric W. Biedermand12af672007-10-18 03:05:25 -07002766 .procname = "retrans_time_ms",
2767 .maxlen = sizeof(int),
2768 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002769 .proc_handler = proc_dointvec_ms_jiffies,
Eric W. Biedermand12af672007-10-18 03:05:25 -07002770 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002771 [NEIGH_VAR_BASE_REACHABLE_TIME_MS] = {
Eric W. Biedermand12af672007-10-18 03:05:25 -07002772 .procname = "base_reachable_time_ms",
2773 .maxlen = sizeof(int),
2774 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002775 .proc_handler = proc_dointvec_ms_jiffies,
Eric W. Biedermand12af672007-10-18 03:05:25 -07002776 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002777 [NEIGH_VAR_GC_INTERVAL] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 .procname = "gc_interval",
2779 .maxlen = sizeof(int),
2780 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002781 .proc_handler = proc_dointvec_jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002783 [NEIGH_VAR_GC_THRESH1] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 .procname = "gc_thresh1",
2785 .maxlen = sizeof(int),
2786 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002787 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002789 [NEIGH_VAR_GC_THRESH2] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 .procname = "gc_thresh2",
2791 .maxlen = sizeof(int),
2792 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002793 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 },
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002795 [NEIGH_VAR_GC_THRESH3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 .procname = "gc_thresh3",
2797 .maxlen = sizeof(int),
2798 .mode = 0644,
Alexey Dobriyan6d9f2392008-11-03 18:21:05 -08002799 .proc_handler = proc_dointvec,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002801 {},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 },
2803};
2804
2805int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
Eric W. Biederman54716e32010-02-14 03:27:03 +00002806 char *p_name, proc_handler *handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807{
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002808 struct neigh_sysctl_table *t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 const char *dev_name_source = NULL;
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002810
2811#define NEIGH_CTL_PATH_ROOT 0
2812#define NEIGH_CTL_PATH_PROTO 1
2813#define NEIGH_CTL_PATH_NEIGH 2
2814#define NEIGH_CTL_PATH_DEV 3
2815
2816 struct ctl_path neigh_path[] = {
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002817 { .procname = "net", },
2818 { .procname = "proto", },
2819 { .procname = "neigh", },
2820 { .procname = "default", },
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002821 { },
2822 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002824 t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 if (!t)
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002826 goto err;
2827
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002828 t->neigh_vars[NEIGH_VAR_MCAST_PROBE].data = &p->mcast_probes;
2829 t->neigh_vars[NEIGH_VAR_UCAST_PROBE].data = &p->ucast_probes;
2830 t->neigh_vars[NEIGH_VAR_APP_PROBE].data = &p->app_probes;
2831 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].data = &p->retrans_time;
2832 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].data = &p->base_reachable_time;
2833 t->neigh_vars[NEIGH_VAR_DELAY_PROBE_TIME].data = &p->delay_probe_time;
2834 t->neigh_vars[NEIGH_VAR_GC_STALETIME].data = &p->gc_staletime;
2835 t->neigh_vars[NEIGH_VAR_QUEUE_LEN].data = &p->queue_len_bytes;
2836 t->neigh_vars[NEIGH_VAR_QUEUE_LEN_BYTES].data = &p->queue_len_bytes;
2837 t->neigh_vars[NEIGH_VAR_PROXY_QLEN].data = &p->proxy_qlen;
2838 t->neigh_vars[NEIGH_VAR_ANYCAST_DELAY].data = &p->anycast_delay;
2839 t->neigh_vars[NEIGH_VAR_PROXY_DELAY].data = &p->proxy_delay;
2840 t->neigh_vars[NEIGH_VAR_LOCKTIME].data = &p->locktime;
2841 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].data = &p->retrans_time;
2842 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].data = &p->base_reachable_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843
2844 if (dev) {
2845 dev_name_source = dev->name;
Eric W. Biedermand12af672007-10-18 03:05:25 -07002846 /* Terminate the table early */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002847 memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
2848 sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 } else {
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002850 dev_name_source = neigh_path[NEIGH_CTL_PATH_DEV].procname;
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002851 t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = (int *)(p + 1);
2852 t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = (int *)(p + 1) + 1;
2853 t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = (int *)(p + 1) + 2;
2854 t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = (int *)(p + 1) + 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 }
2856
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857
Eric W. Biedermanf8572d82009-11-05 13:32:03 -08002858 if (handler) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 /* RetransTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002860 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
2861 t->neigh_vars[NEIGH_VAR_RETRANS_TIME].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 /* ReachableTime */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002863 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
2864 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 /* RetransTime (in milliseconds)*/
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002866 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
2867 t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 /* ReachableTime (in milliseconds) */
Eric Dumazet8b5c1712011-11-09 12:07:14 +00002869 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
2870 t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].extra1 = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 }
2872
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002873 t->dev_name = kstrdup(dev_name_source, GFP_KERNEL);
2874 if (!t->dev_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 goto free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002877 neigh_path[NEIGH_CTL_PATH_DEV].procname = t->dev_name;
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002878 neigh_path[NEIGH_CTL_PATH_PROTO].procname = p_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879
Denis V. Lunev4ab438f2008-02-28 20:48:01 -08002880 t->sysctl_header =
YOSHIFUJI Hideaki57da52c2008-03-26 03:49:59 +09002881 register_net_sysctl_table(neigh_parms_net(p), neigh_path, t->neigh_vars);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002882 if (!t->sysctl_header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 goto free_procname;
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002884
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 p->sysctl_table = t;
2886 return 0;
2887
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002888free_procname:
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002889 kfree(t->dev_name);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002890free:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 kfree(t);
Pavel Emelyanov3c607bb2007-12-02 00:06:34 +11002892err:
2893 return -ENOBUFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09002895EXPORT_SYMBOL(neigh_sysctl_register);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
2897void neigh_sysctl_unregister(struct neigh_parms *p)
2898{
2899 if (p->sysctl_table) {
2900 struct neigh_sysctl_table *t = p->sysctl_table;
2901 p->sysctl_table = NULL;
2902 unregister_sysctl_table(t->sysctl_header);
Pavel Emelyanovc3bac5a2007-12-02 00:08:16 +11002903 kfree(t->dev_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 kfree(t);
2905 }
2906}
YOSHIFUJI Hideaki0a204502008-03-24 18:39:10 +09002907EXPORT_SYMBOL(neigh_sysctl_unregister);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908
2909#endif /* CONFIG_SYSCTL */
2910
Thomas Grafc8822a42007-03-22 11:50:06 -07002911static int __init neigh_init(void)
2912{
Greg Rosec7ac8672011-06-10 01:27:09 +00002913 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, NULL);
2914 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, NULL);
2915 rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, NULL);
Thomas Grafc8822a42007-03-22 11:50:06 -07002916
Greg Rosec7ac8672011-06-10 01:27:09 +00002917 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
2918 NULL);
2919 rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, NULL);
Thomas Grafc8822a42007-03-22 11:50:06 -07002920
2921 return 0;
2922}
2923
2924subsys_initcall(neigh_init);
2925