Blame view

net/core/neighbour.c 70.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  /*
   *	Generic address resolution entity
   *
   *	Authors:
   *	Pedro Roque		<roque@di.fc.ul.pt>
   *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
   *
   *	This program is free software; you can redistribute it and/or
   *      modify it under the terms of the GNU General Public License
   *      as published by the Free Software Foundation; either version
   *      2 of the License, or (at your option) any later version.
   *
   *	Fixes:
   *	Vitaly E. Lavrov	releasing NULL neighbor in neigh_add.
   *	Harald Welte		Add neighbour cache statistics like rtstat
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
17
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/socket.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
  #include <linux/netdevice.h>
  #include <linux/proc_fs.h>
  #ifdef CONFIG_SYSCTL
  #include <linux/sysctl.h>
  #endif
  #include <linux/times.h>
457c4cbc5   Eric W. Biederman   [NET]: Make /proc...
28
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
  #include <net/neighbour.h>
  #include <net/dst.h>
  #include <net/sock.h>
8d71740c5   Tom Tucker   [NET]: Core net c...
32
  #include <net/netevent.h>
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
33
  #include <net/netlink.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
  #include <linux/rtnetlink.h>
  #include <linux/random.h>
543537bd9   Paulo Marques   [PATCH] create a ...
36
  #include <linux/string.h>
c3609d510   vignesh babu   [NET]: is_power_o...
37
  #include <linux/log2.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
  
  #define NEIGH_DEBUG 1
  
  #define NEIGH_PRINTK(x...) printk(x)
  #define NEIGH_NOPRINTK(x...) do { ; } while(0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  #define NEIGH_PRINTK1 NEIGH_NOPRINTK
  #define NEIGH_PRINTK2 NEIGH_NOPRINTK
  
  #if NEIGH_DEBUG >= 1
  #undef NEIGH_PRINTK1
  #define NEIGH_PRINTK1 NEIGH_PRINTK
  #endif
  #if NEIGH_DEBUG >= 2
  #undef NEIGH_PRINTK2
  #define NEIGH_PRINTK2 NEIGH_PRINTK
  #endif
  
  #define PNEIGH_HASHMASK		0xF
  
  static void neigh_timer_handler(unsigned long arg);
d961db358   Thomas Graf   [NEIGH]: Netlink ...
58
59
  static void __neigh_notify(struct neighbour *n, int type, int flags);
  static void neigh_update_notify(struct neighbour *neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
  static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
  
  static struct neigh_table *neigh_tables;
45fc3b11f   Amos Waterland   [NET]: Protect ne...
63
  #ifdef CONFIG_PROC_FS
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
64
  static const struct file_operations neigh_stat_seq_fops;
45fc3b11f   Amos Waterland   [NET]: Protect ne...
65
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  
  /*
     Neighbour hash table buckets are protected with rwlock tbl->lock.
  
     - All the scans/updates to hash buckets MUST be made under this lock.
     - NOTHING clever should be made under this lock: no callbacks
       to protocol backends, no attempts to send something to network.
       It will result in deadlocks, if backend/driver wants to use neighbour
       cache.
     - If the entry requires some non-trivial actions, increase
       its reference count and release table lock.
  
     Neighbour entries are protected:
     - with reference count.
     - with rwlock neigh->lock
  
     Reference count prevents destruction.
  
     neigh->lock mainly serializes ll address data and its validity state.
     However, the same lock is used to protect another entry fields:
      - timer
      - resolution queue
  
     Again, nothing clever shall be made under neigh->lock,
     the most complicated procedure, which we allow is dev->hard_header.
     It is supposed, that dev->hard_header is simplistic and does
     not make callbacks to neighbour tables.
  
     The last lock is neigh_tbl_lock. It is pure SMP lock, protecting
     list of neighbour tables. This list is used only in process context,
   */
  
  static DEFINE_RWLOCK(neigh_tbl_lock);
8f40b161d   David S. Miller   neigh: Pass neigh...
99
  static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
103
  {
  	kfree_skb(skb);
  	return -ENETDOWN;
  }
4f494554f   Thomas Graf   [NEIGH]: Combine ...
104
105
106
107
  static void neigh_cleanup_and_release(struct neighbour *neigh)
  {
  	if (neigh->parms->neigh_cleanup)
  		neigh->parms->neigh_cleanup(neigh);
d961db358   Thomas Graf   [NEIGH]: Netlink ...
108
  	__neigh_notify(neigh, RTM_DELNEIGH, 0);
4f494554f   Thomas Graf   [NEIGH]: Combine ...
109
110
  	neigh_release(neigh);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
113
114
115
116
117
118
  /*
   * It is random distribution in the interval (1/2)*base...(3/2)*base.
   * It corresponds to default IPv6 settings and is not overridable,
   * because it is really reasonable choice.
   */
  
  unsigned long neigh_rand_reach_time(unsigned long base)
  {
a02cec215   Eric Dumazet   net: return opera...
119
  	return base ? (net_random() % base) + (base >> 1) : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
121
  EXPORT_SYMBOL(neigh_rand_reach_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
126
127
  
  
  static int neigh_forced_gc(struct neigh_table *tbl)
  {
  	int shrunk = 0;
  	int i;
d6bf78171   Eric Dumazet   net neigh: RCU co...
128
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
131
132
  
  	NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
  
  	write_lock_bh(&tbl->lock);
d6bf78171   Eric Dumazet   net neigh: RCU co...
133
134
  	nht = rcu_dereference_protected(tbl->nht,
  					lockdep_is_held(&tbl->lock));
cd0893369   David S. Miller   neigh: Store hash...
135
  	for (i = 0; i < (1 << nht->hash_shift); i++) {
767e97e1e   Eric Dumazet   neigh: RCU conver...
136
137
  		struct neighbour *n;
  		struct neighbour __rcu **np;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138

d6bf78171   Eric Dumazet   net neigh: RCU co...
139
  		np = &nht->hash_buckets[i];
767e97e1e   Eric Dumazet   neigh: RCU conver...
140
141
  		while ((n = rcu_dereference_protected(*np,
  					lockdep_is_held(&tbl->lock))) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
146
147
148
  			/* Neighbour record may be discarded if:
  			 * - nobody refers to it.
  			 * - it is not permanent
  			 */
  			write_lock(&n->lock);
  			if (atomic_read(&n->refcnt) == 1 &&
  			    !(n->nud_state & NUD_PERMANENT)) {
767e97e1e   Eric Dumazet   neigh: RCU conver...
149
150
151
  				rcu_assign_pointer(*np,
  					rcu_dereference_protected(n->next,
  						  lockdep_is_held(&tbl->lock)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
  				n->dead = 1;
  				shrunk	= 1;
  				write_unlock(&n->lock);
4f494554f   Thomas Graf   [NEIGH]: Combine ...
155
  				neigh_cleanup_and_release(n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
159
160
161
162
163
164
165
166
167
168
  				continue;
  			}
  			write_unlock(&n->lock);
  			np = &n->next;
  		}
  	}
  
  	tbl->last_flush = jiffies;
  
  	write_unlock_bh(&tbl->lock);
  
  	return shrunk;
  }
a43d8994b   Pavel Emelyanov   [NEIGH]: Make nei...
169
170
171
172
173
174
175
176
177
178
  static void neigh_add_timer(struct neighbour *n, unsigned long when)
  {
  	neigh_hold(n);
  	if (unlikely(mod_timer(&n->timer, when))) {
  		printk("NEIGH: BUG, double timer add, state is %x
  ",
  		       n->nud_state);
  		dump_stack();
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
  static int neigh_del_timer(struct neighbour *n)
  {
  	if ((n->nud_state & NUD_IN_TIMER) &&
  	    del_timer(&n->timer)) {
  		neigh_release(n);
  		return 1;
  	}
  	return 0;
  }
  
  static void pneigh_queue_purge(struct sk_buff_head *list)
  {
  	struct sk_buff *skb;
  
  	while ((skb = skb_dequeue(list)) != NULL) {
  		dev_put(skb->dev);
  		kfree_skb(skb);
  	}
  }
49636bb12   Herbert Xu   [NEIGH] Fix timer...
198
  static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
  {
  	int i;
d6bf78171   Eric Dumazet   net neigh: RCU co...
201
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202

d6bf78171   Eric Dumazet   net neigh: RCU co...
203
204
  	nht = rcu_dereference_protected(tbl->nht,
  					lockdep_is_held(&tbl->lock));
cd0893369   David S. Miller   neigh: Store hash...
205
  	for (i = 0; i < (1 << nht->hash_shift); i++) {
767e97e1e   Eric Dumazet   neigh: RCU conver...
206
207
  		struct neighbour *n;
  		struct neighbour __rcu **np = &nht->hash_buckets[i];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208

767e97e1e   Eric Dumazet   neigh: RCU conver...
209
210
  		while ((n = rcu_dereference_protected(*np,
  					lockdep_is_held(&tbl->lock))) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
214
  			if (dev && n->dev != dev) {
  				np = &n->next;
  				continue;
  			}
767e97e1e   Eric Dumazet   neigh: RCU conver...
215
216
217
  			rcu_assign_pointer(*np,
  				   rcu_dereference_protected(n->next,
  						lockdep_is_held(&tbl->lock)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  			write_lock(&n->lock);
  			neigh_del_timer(n);
  			n->dead = 1;
  
  			if (atomic_read(&n->refcnt) != 1) {
  				/* The most unpleasant situation.
  				   We must destroy neighbour entry,
  				   but someone still uses it.
  
  				   The destroy will be delayed until
  				   the last user releases us, but
  				   we must kill timers etc. and move
  				   it to safe state.
  				 */
  				skb_queue_purge(&n->arp_queue);
8b5c171bb   Eric Dumazet   neigh: new unreso...
233
  				n->arp_queue_len_bytes = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
236
237
238
239
240
241
242
  				n->output = neigh_blackhole;
  				if (n->nud_state & NUD_VALID)
  					n->nud_state = NUD_NOARP;
  				else
  					n->nud_state = NUD_NONE;
  				NEIGH_PRINTK2("neigh %p is stray.
  ", n);
  			}
  			write_unlock(&n->lock);
4f494554f   Thomas Graf   [NEIGH]: Combine ...
243
  			neigh_cleanup_and_release(n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
  		}
  	}
49636bb12   Herbert Xu   [NEIGH] Fix timer...
246
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247

49636bb12   Herbert Xu   [NEIGH] Fix timer...
248
249
250
251
252
253
  void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
  {
  	write_lock_bh(&tbl->lock);
  	neigh_flush_dev(tbl, dev);
  	write_unlock_bh(&tbl->lock);
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
254
  EXPORT_SYMBOL(neigh_changeaddr);
49636bb12   Herbert Xu   [NEIGH] Fix timer...
255
256
257
258
259
  
  int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
  {
  	write_lock_bh(&tbl->lock);
  	neigh_flush_dev(tbl, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
263
264
265
266
  	pneigh_ifdown(tbl, dev);
  	write_unlock_bh(&tbl->lock);
  
  	del_timer_sync(&tbl->proxy_timer);
  	pneigh_queue_purge(&tbl->proxy_queue);
  	return 0;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
267
  EXPORT_SYMBOL(neigh_ifdown);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268

596b9b68e   David Miller   neigh: Add infras...
269
  static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
273
274
275
276
277
278
279
280
281
282
  {
  	struct neighbour *n = NULL;
  	unsigned long now = jiffies;
  	int entries;
  
  	entries = atomic_inc_return(&tbl->entries) - 1;
  	if (entries >= tbl->gc_thresh3 ||
  	    (entries >= tbl->gc_thresh2 &&
  	     time_after(now, tbl->last_flush + 5 * HZ))) {
  		if (!neigh_forced_gc(tbl) &&
  		    entries >= tbl->gc_thresh3)
  			goto out_entries;
  	}
596b9b68e   David Miller   neigh: Add infras...
283
284
285
286
287
288
289
290
291
  	if (tbl->entry_size)
  		n = kzalloc(tbl->entry_size, GFP_ATOMIC);
  	else {
  		int sz = sizeof(*n) + tbl->key_len;
  
  		sz = ALIGN(sz, NEIGH_PRIV_ALIGN);
  		sz += dev->neigh_priv_len;
  		n = kzalloc(sz, GFP_ATOMIC);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
  	if (!n)
  		goto out_entries;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
  	skb_queue_head_init(&n->arp_queue);
  	rwlock_init(&n->lock);
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
296
  	seqlock_init(&n->ha_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
  	n->updated	  = n->used = now;
  	n->nud_state	  = NUD_NONE;
  	n->output	  = neigh_blackhole;
f6b72b621   David S. Miller   net: Embed hh_cac...
300
  	seqlock_init(&n->hh.hh_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  	n->parms	  = neigh_parms_clone(&tbl->parms);
b24b8a247   Pavel Emelyanov   [NET]: Convert in...
302
  	setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
305
306
307
308
309
310
311
312
313
314
  
  	NEIGH_CACHE_STAT_INC(tbl, allocs);
  	n->tbl		  = tbl;
  	atomic_set(&n->refcnt, 1);
  	n->dead		  = 1;
  out:
  	return n;
  
  out_entries:
  	atomic_dec(&tbl->entries);
  	goto out;
  }
2c2aba6c5   David S. Miller   ipv6: Use univers...
315
316
317
318
319
  static void neigh_get_hash_rnd(u32 *x)
  {
  	get_random_bytes(x, sizeof(*x));
  	*x |= 1;
  }
cd0893369   David S. Miller   neigh: Store hash...
320
  static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
  {
cd0893369   David S. Miller   neigh: Store hash...
322
  	size_t size = (1 << shift) * sizeof(struct neighbour *);
d6bf78171   Eric Dumazet   net neigh: RCU co...
323
  	struct neigh_hash_table *ret;
6193d2be2   Eric Dumazet   neigh: __rcu anno...
324
  	struct neighbour __rcu **buckets;
2c2aba6c5   David S. Miller   ipv6: Use univers...
325
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326

d6bf78171   Eric Dumazet   net neigh: RCU co...
327
328
329
330
331
332
  	ret = kmalloc(sizeof(*ret), GFP_ATOMIC);
  	if (!ret)
  		return NULL;
  	if (size <= PAGE_SIZE)
  		buckets = kzalloc(size, GFP_ATOMIC);
  	else
6193d2be2   Eric Dumazet   neigh: __rcu anno...
333
  		buckets = (struct neighbour __rcu **)
d6bf78171   Eric Dumazet   net neigh: RCU co...
334
335
336
337
338
  			  __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
  					   get_order(size));
  	if (!buckets) {
  		kfree(ret);
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  	}
6193d2be2   Eric Dumazet   neigh: __rcu anno...
340
  	ret->hash_buckets = buckets;
cd0893369   David S. Miller   neigh: Store hash...
341
  	ret->hash_shift = shift;
2c2aba6c5   David S. Miller   ipv6: Use univers...
342
343
  	for (i = 0; i < NEIGH_NUM_HASH_RND; i++)
  		neigh_get_hash_rnd(&ret->hash_rnd[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
  	return ret;
  }
d6bf78171   Eric Dumazet   net neigh: RCU co...
346
  static void neigh_hash_free_rcu(struct rcu_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  {
d6bf78171   Eric Dumazet   net neigh: RCU co...
348
349
350
  	struct neigh_hash_table *nht = container_of(head,
  						    struct neigh_hash_table,
  						    rcu);
cd0893369   David S. Miller   neigh: Store hash...
351
  	size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
6193d2be2   Eric Dumazet   neigh: __rcu anno...
352
  	struct neighbour __rcu **buckets = nht->hash_buckets;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
  
  	if (size <= PAGE_SIZE)
d6bf78171   Eric Dumazet   net neigh: RCU co...
355
  		kfree(buckets);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  	else
d6bf78171   Eric Dumazet   net neigh: RCU co...
357
358
  		free_pages((unsigned long)buckets, get_order(size));
  	kfree(nht);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
  }
d6bf78171   Eric Dumazet   net neigh: RCU co...
360
  static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
cd0893369   David S. Miller   neigh: Store hash...
361
  						unsigned long new_shift)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
  {
d6bf78171   Eric Dumazet   net neigh: RCU co...
363
364
  	unsigned int i, hash;
  	struct neigh_hash_table *new_nht, *old_nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
  
  	NEIGH_CACHE_STAT_INC(tbl, hash_grows);
d6bf78171   Eric Dumazet   net neigh: RCU co...
367
368
  	old_nht = rcu_dereference_protected(tbl->nht,
  					    lockdep_is_held(&tbl->lock));
cd0893369   David S. Miller   neigh: Store hash...
369
  	new_nht = neigh_hash_alloc(new_shift);
d6bf78171   Eric Dumazet   net neigh: RCU co...
370
371
  	if (!new_nht)
  		return old_nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372

cd0893369   David S. Miller   neigh: Store hash...
373
  	for (i = 0; i < (1 << old_nht->hash_shift); i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  		struct neighbour *n, *next;
767e97e1e   Eric Dumazet   neigh: RCU conver...
375
376
  		for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
  						   lockdep_is_held(&tbl->lock));
d6bf78171   Eric Dumazet   net neigh: RCU co...
377
378
379
380
  		     n != NULL;
  		     n = next) {
  			hash = tbl->hash(n->primary_key, n->dev,
  					 new_nht->hash_rnd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381

cd0893369   David S. Miller   neigh: Store hash...
382
  			hash >>= (32 - new_nht->hash_shift);
767e97e1e   Eric Dumazet   neigh: RCU conver...
383
384
385
386
387
388
389
390
  			next = rcu_dereference_protected(n->next,
  						lockdep_is_held(&tbl->lock));
  
  			rcu_assign_pointer(n->next,
  					   rcu_dereference_protected(
  						new_nht->hash_buckets[hash],
  						lockdep_is_held(&tbl->lock)));
  			rcu_assign_pointer(new_nht->hash_buckets[hash], n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393

d6bf78171   Eric Dumazet   net neigh: RCU co...
394
395
396
  	rcu_assign_pointer(tbl->nht, new_nht);
  	call_rcu(&old_nht->rcu, neigh_hash_free_rcu);
  	return new_nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
400
401
402
403
  }
  
  struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
  			       struct net_device *dev)
  {
  	struct neighbour *n;
  	int key_len = tbl->key_len;
bc4bf5f38   Pavel Emelyanov   [NEIGH]: Fix race...
404
  	u32 hash_val;
d6bf78171   Eric Dumazet   net neigh: RCU co...
405
  	struct neigh_hash_table *nht;
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
406

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
  	NEIGH_CACHE_STAT_INC(tbl, lookups);
d6bf78171   Eric Dumazet   net neigh: RCU co...
408
409
  	rcu_read_lock_bh();
  	nht = rcu_dereference_bh(tbl->nht);
cd0893369   David S. Miller   neigh: Store hash...
410
  	hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
767e97e1e   Eric Dumazet   neigh: RCU conver...
411
412
413
414
  
  	for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
  	     n != NULL;
  	     n = rcu_dereference_bh(n->next)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
  		if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
767e97e1e   Eric Dumazet   neigh: RCU conver...
416
417
  			if (!atomic_inc_not_zero(&n->refcnt))
  				n = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
419
420
421
  			NEIGH_CACHE_STAT_INC(tbl, hits);
  			break;
  		}
  	}
767e97e1e   Eric Dumazet   neigh: RCU conver...
422

d6bf78171   Eric Dumazet   net neigh: RCU co...
423
  	rcu_read_unlock_bh();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
  	return n;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
426
  EXPORT_SYMBOL(neigh_lookup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427

426b5303e   Eric W. Biederman   [NETNS]: Modify t...
428
429
  struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
  				     const void *pkey)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
432
  {
  	struct neighbour *n;
  	int key_len = tbl->key_len;
bc4bf5f38   Pavel Emelyanov   [NEIGH]: Fix race...
433
  	u32 hash_val;
d6bf78171   Eric Dumazet   net neigh: RCU co...
434
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
  
  	NEIGH_CACHE_STAT_INC(tbl, lookups);
d6bf78171   Eric Dumazet   net neigh: RCU co...
437
438
  	rcu_read_lock_bh();
  	nht = rcu_dereference_bh(tbl->nht);
cd0893369   David S. Miller   neigh: Store hash...
439
  	hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
767e97e1e   Eric Dumazet   neigh: RCU conver...
440
441
442
443
  
  	for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]);
  	     n != NULL;
  	     n = rcu_dereference_bh(n->next)) {
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
444
  		if (!memcmp(n->primary_key, pkey, key_len) &&
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
445
  		    net_eq(dev_net(n->dev), net)) {
767e97e1e   Eric Dumazet   neigh: RCU conver...
446
447
  			if (!atomic_inc_not_zero(&n->refcnt))
  				n = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
451
  			NEIGH_CACHE_STAT_INC(tbl, hits);
  			break;
  		}
  	}
767e97e1e   Eric Dumazet   neigh: RCU conver...
452

d6bf78171   Eric Dumazet   net neigh: RCU co...
453
  	rcu_read_unlock_bh();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
455
  	return n;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
456
  EXPORT_SYMBOL(neigh_lookup_nodev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
459
460
461
462
463
  
  struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
  			       struct net_device *dev)
  {
  	u32 hash_val;
  	int key_len = tbl->key_len;
  	int error;
596b9b68e   David Miller   neigh: Add infras...
464
  	struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev);
d6bf78171   Eric Dumazet   net neigh: RCU co...
465
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  
  	if (!n) {
  		rc = ERR_PTR(-ENOBUFS);
  		goto out;
  	}
  
  	memcpy(n->primary_key, pkey, key_len);
  	n->dev = dev;
  	dev_hold(dev);
  
  	/* Protocol specific setup. */
  	if (tbl->constructor &&	(error = tbl->constructor(n)) < 0) {
  		rc = ERR_PTR(error);
  		goto out_neigh_release;
  	}
da6a8fa02   David Miller   neigh: Add device...
481
482
483
484
485
486
487
  	if (dev->netdev_ops->ndo_neigh_construct) {
  		error = dev->netdev_ops->ndo_neigh_construct(n);
  		if (error < 0) {
  			rc = ERR_PTR(error);
  			goto out_neigh_release;
  		}
  	}
447f21919   David S. Miller   Revert "net: Remo...
488
489
490
491
492
493
  	/* Device specific setup. */
  	if (n->parms->neigh_setup &&
  	    (error = n->parms->neigh_setup(n)) < 0) {
  		rc = ERR_PTR(error);
  		goto out_neigh_release;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
  	n->confirmed = jiffies - (n->parms->base_reachable_time << 1);
  
  	write_lock_bh(&tbl->lock);
d6bf78171   Eric Dumazet   net neigh: RCU co...
497
498
  	nht = rcu_dereference_protected(tbl->nht,
  					lockdep_is_held(&tbl->lock));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499

cd0893369   David S. Miller   neigh: Store hash...
500
501
  	if (atomic_read(&tbl->entries) > (1 << nht->hash_shift))
  		nht = neigh_hash_grow(tbl, nht->hash_shift + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502

cd0893369   David S. Miller   neigh: Store hash...
503
  	hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
506
507
508
  
  	if (n->parms->dead) {
  		rc = ERR_PTR(-EINVAL);
  		goto out_tbl_unlock;
  	}
767e97e1e   Eric Dumazet   neigh: RCU conver...
509
510
511
512
513
  	for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val],
  					    lockdep_is_held(&tbl->lock));
  	     n1 != NULL;
  	     n1 = rcu_dereference_protected(n1->next,
  			lockdep_is_held(&tbl->lock))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
517
518
519
  		if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) {
  			neigh_hold(n1);
  			rc = n1;
  			goto out_tbl_unlock;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
  	n->dead = 0;
  	neigh_hold(n);
767e97e1e   Eric Dumazet   neigh: RCU conver...
522
523
524
525
  	rcu_assign_pointer(n->next,
  			   rcu_dereference_protected(nht->hash_buckets[hash_val],
  						     lockdep_is_held(&tbl->lock)));
  	rcu_assign_pointer(nht->hash_buckets[hash_val], n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
529
530
531
532
533
534
535
536
537
  	write_unlock_bh(&tbl->lock);
  	NEIGH_PRINTK2("neigh %p is created.
  ", n);
  	rc = n;
  out:
  	return rc;
  out_tbl_unlock:
  	write_unlock_bh(&tbl->lock);
  out_neigh_release:
  	neigh_release(n);
  	goto out;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
538
  EXPORT_SYMBOL(neigh_create);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539

be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
540
  static u32 pneigh_hash(const void *pkey, int key_len)
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
541
  {
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
542
  	u32 hash_val = *(u32 *)(pkey + key_len - 4);
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
543
544
545
546
  	hash_val ^= (hash_val >> 16);
  	hash_val ^= hash_val >> 8;
  	hash_val ^= hash_val >> 4;
  	hash_val &= PNEIGH_HASHMASK;
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
547
548
  	return hash_val;
  }
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
549

be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
550
551
552
553
554
555
556
  static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
  					      struct net *net,
  					      const void *pkey,
  					      int key_len,
  					      struct net_device *dev)
  {
  	while (n) {
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
557
  		if (!memcmp(n->key, pkey, key_len) &&
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
558
  		    net_eq(pneigh_net(n), net) &&
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
559
  		    (n->dev == dev || !n->dev))
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
560
561
  			return n;
  		n = n->next;
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
562
  	}
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
563
564
  	return NULL;
  }
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
565

be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
566
567
568
569
570
571
572
573
  struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
  		struct net *net, const void *pkey, struct net_device *dev)
  {
  	int key_len = tbl->key_len;
  	u32 hash_val = pneigh_hash(pkey, key_len);
  
  	return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
  				 net, pkey, key_len, dev);
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
574
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
575
  EXPORT_SYMBOL_GPL(__pneigh_lookup);
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
576

426b5303e   Eric W. Biederman   [NETNS]: Modify t...
577
578
  struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
  				    struct net *net, const void *pkey,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
580
581
582
  				    struct net_device *dev, int creat)
  {
  	struct pneigh_entry *n;
  	int key_len = tbl->key_len;
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
583
  	u32 hash_val = pneigh_hash(pkey, key_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
585
  
  	read_lock_bh(&tbl->lock);
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
586
587
  	n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
  			      net, pkey, key_len, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
  	read_unlock_bh(&tbl->lock);
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
589
590
  
  	if (n || !creat)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591
  		goto out;
4ae289444   Pavel Emelyanov   [NEIGH]: Ensure t...
592
  	ASSERT_RTNL();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
  	n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
  	if (!n)
  		goto out;
e42ea986e   Eric Dumazet   net: Cleanup of n...
596
  	write_pnet(&n->net, hold_net(net));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
599
600
601
602
603
604
  	memcpy(n->key, pkey, key_len);
  	n->dev = dev;
  	if (dev)
  		dev_hold(dev);
  
  	if (tbl->pconstructor && tbl->pconstructor(n)) {
  		if (dev)
  			dev_put(dev);
da12f7356   Denis V. Lunev   [NETNS]: Namespac...
605
  		release_net(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
608
609
610
611
612
613
614
615
616
617
  		kfree(n);
  		n = NULL;
  		goto out;
  	}
  
  	write_lock_bh(&tbl->lock);
  	n->next = tbl->phash_buckets[hash_val];
  	tbl->phash_buckets[hash_val] = n;
  	write_unlock_bh(&tbl->lock);
  out:
  	return n;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
618
  EXPORT_SYMBOL(pneigh_lookup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619

426b5303e   Eric W. Biederman   [NETNS]: Modify t...
620
  int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
624
  		  struct net_device *dev)
  {
  	struct pneigh_entry *n, **np;
  	int key_len = tbl->key_len;
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
625
  	u32 hash_val = pneigh_hash(pkey, key_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
627
628
629
  
  	write_lock_bh(&tbl->lock);
  	for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
  	     np = &n->next) {
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
630
  		if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
631
  		    net_eq(pneigh_net(n), net)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
633
634
635
636
637
  			*np = n->next;
  			write_unlock_bh(&tbl->lock);
  			if (tbl->pdestructor)
  				tbl->pdestructor(n);
  			if (n->dev)
  				dev_put(n->dev);
57da52c1e   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
638
  			release_net(pneigh_net(n));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
  			kfree(n);
  			return 0;
  		}
  	}
  	write_unlock_bh(&tbl->lock);
  	return -ENOENT;
  }
  
  static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
  {
  	struct pneigh_entry *n, **np;
  	u32 h;
  
  	for (h = 0; h <= PNEIGH_HASHMASK; h++) {
  		np = &tbl->phash_buckets[h];
  		while ((n = *np) != NULL) {
  			if (!dev || n->dev == dev) {
  				*np = n->next;
  				if (tbl->pdestructor)
  					tbl->pdestructor(n);
  				if (n->dev)
  					dev_put(n->dev);
57da52c1e   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
661
  				release_net(pneigh_net(n));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
664
665
666
667
668
669
  				kfree(n);
  				continue;
  			}
  			np = &n->next;
  		}
  	}
  	return -ENOENT;
  }
06f0511df   Denis V. Lunev   [ARP]: neigh_parm...
670
671
672
673
674
675
676
  static void neigh_parms_destroy(struct neigh_parms *parms);
  
  static inline void neigh_parms_put(struct neigh_parms *parms)
  {
  	if (atomic_dec_and_test(&parms->refcnt))
  		neigh_parms_destroy(parms);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
679
680
681
682
683
  
  /*
   *	neighbour must already be out of the table;
   *
   */
  void neigh_destroy(struct neighbour *neigh)
  {
da6a8fa02   David Miller   neigh: Add device...
684
  	struct net_device *dev = neigh->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
688
689
690
691
692
693
694
695
696
697
  	NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
  
  	if (!neigh->dead) {
  		printk(KERN_WARNING
  		       "Destroying alive neighbour %p
  ", neigh);
  		dump_stack();
  		return;
  	}
  
  	if (neigh_del_timer(neigh))
  		printk(KERN_WARNING "Impossible event.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
  	skb_queue_purge(&neigh->arp_queue);
8b5c171bb   Eric Dumazet   neigh: new unreso...
699
  	neigh->arp_queue_len_bytes = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700

447f21919   David S. Miller   Revert "net: Remo...
701
702
  	if (dev->netdev_ops->ndo_neigh_destroy)
  		dev->netdev_ops->ndo_neigh_destroy(neigh);
da6a8fa02   David Miller   neigh: Add device...
703
  	dev_put(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
705
706
707
708
709
  	neigh_parms_put(neigh->parms);
  
  	NEIGH_PRINTK2("neigh %p is destroyed.
  ", neigh);
  
  	atomic_dec(&neigh->tbl->entries);
5b8b0060c   David Miller   neigh: Get rid of...
710
  	kfree_rcu(neigh, rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
712
  EXPORT_SYMBOL(neigh_destroy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
714
715
716
717
718
719
720
  
  /* Neighbour state is suspicious;
     disable fast path.
  
     Called with write_locked neigh.
   */
  static void neigh_suspect(struct neighbour *neigh)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
723
724
  	NEIGH_PRINTK2("neigh %p is suspected.
  ", neigh);
  
  	neigh->output = neigh->ops->output;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
726
727
728
729
730
731
732
733
  }
  
  /* Neighbour state is OK;
     enable fast path.
  
     Called with write_locked neigh.
   */
  static void neigh_connect(struct neighbour *neigh)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
736
737
  	NEIGH_PRINTK2("neigh %p is connected.
  ", neigh);
  
  	neigh->output = neigh->ops->connected_output;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
  }
e4c4e448c   Eric Dumazet   neigh: Convert ga...
739
  static void neigh_periodic_work(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
  {
e4c4e448c   Eric Dumazet   neigh: Convert ga...
741
  	struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
767e97e1e   Eric Dumazet   neigh: RCU conver...
742
743
  	struct neighbour *n;
  	struct neighbour __rcu **np;
e4c4e448c   Eric Dumazet   neigh: Convert ga...
744
  	unsigned int i;
d6bf78171   Eric Dumazet   net neigh: RCU co...
745
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
  
  	NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
e4c4e448c   Eric Dumazet   neigh: Convert ga...
748
  	write_lock_bh(&tbl->lock);
d6bf78171   Eric Dumazet   net neigh: RCU co...
749
750
  	nht = rcu_dereference_protected(tbl->nht,
  					lockdep_is_held(&tbl->lock));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
752
753
754
  
  	/*
  	 *	periodically recompute ReachableTime from random function
  	 */
e4c4e448c   Eric Dumazet   neigh: Convert ga...
755
  	if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756
  		struct neigh_parms *p;
e4c4e448c   Eric Dumazet   neigh: Convert ga...
757
  		tbl->last_rand = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
760
761
  		for (p = &tbl->parms; p; p = p->next)
  			p->reachable_time =
  				neigh_rand_reach_time(p->base_reachable_time);
  	}
cd0893369   David S. Miller   neigh: Store hash...
762
  	for (i = 0 ; i < (1 << nht->hash_shift); i++) {
d6bf78171   Eric Dumazet   net neigh: RCU co...
763
  		np = &nht->hash_buckets[i];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764

767e97e1e   Eric Dumazet   neigh: RCU conver...
765
766
  		while ((n = rcu_dereference_protected(*np,
  				lockdep_is_held(&tbl->lock))) != NULL) {
e4c4e448c   Eric Dumazet   neigh: Convert ga...
767
  			unsigned int state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768

e4c4e448c   Eric Dumazet   neigh: Convert ga...
769
  			write_lock(&n->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770

e4c4e448c   Eric Dumazet   neigh: Convert ga...
771
772
773
774
775
  			state = n->nud_state;
  			if (state & (NUD_PERMANENT | NUD_IN_TIMER)) {
  				write_unlock(&n->lock);
  				goto next_elt;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776

e4c4e448c   Eric Dumazet   neigh: Convert ga...
777
778
  			if (time_before(n->used, n->confirmed))
  				n->used = n->confirmed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779

e4c4e448c   Eric Dumazet   neigh: Convert ga...
780
781
782
783
784
785
786
787
788
  			if (atomic_read(&n->refcnt) == 1 &&
  			    (state == NUD_FAILED ||
  			     time_after(jiffies, n->used + n->parms->gc_staletime))) {
  				*np = n->next;
  				n->dead = 1;
  				write_unlock(&n->lock);
  				neigh_cleanup_and_release(n);
  				continue;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
  			write_unlock(&n->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
791
  
  next_elt:
e4c4e448c   Eric Dumazet   neigh: Convert ga...
792
793
794
795
796
797
798
799
800
  			np = &n->next;
  		}
  		/*
  		 * It's fine to release lock here, even if hash table
  		 * grows while we are preempted.
  		 */
  		write_unlock_bh(&tbl->lock);
  		cond_resched();
  		write_lock_bh(&tbl->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
  	}
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
802
803
804
  	/* Cycle through all hash buckets every base_reachable_time/2 ticks.
  	 * ARP entry timeouts range from 1/2 base_reachable_time to 3/2
  	 * base_reachable_time.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
  	 */
e4c4e448c   Eric Dumazet   neigh: Convert ga...
806
807
808
  	schedule_delayed_work(&tbl->gc_work,
  			      tbl->parms.base_reachable_time >> 1);
  	write_unlock_bh(&tbl->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
810
811
812
813
  }
  
  static __inline__ int neigh_max_probes(struct neighbour *n)
  {
  	struct neigh_parms *p = n->parms;
a02cec215   Eric Dumazet   net: return opera...
814
  	return (n->nud_state & NUD_PROBE) ?
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
  		p->ucast_probes :
a02cec215   Eric Dumazet   net: return opera...
816
  		p->ucast_probes + p->app_probes + p->mcast_probes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
  }
5ef12d98a   Timo Teras   neigh: fix state ...
818
  static void neigh_invalidate(struct neighbour *neigh)
0a141509e   Eric Dumazet   net: Annotates ne...
819
820
  	__releases(neigh->lock)
  	__acquires(neigh->lock)
5ef12d98a   Timo Teras   neigh: fix state ...
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
  {
  	struct sk_buff *skb;
  
  	NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
  	NEIGH_PRINTK2("neigh %p is failed.
  ", neigh);
  	neigh->updated = jiffies;
  
  	/* It is very thin place. report_unreachable is very complicated
  	   routine. Particularly, it can hit the same neighbour entry!
  
  	   So that, we try to be accurate and avoid dead loop. --ANK
  	 */
  	while (neigh->nud_state == NUD_FAILED &&
  	       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
  		write_unlock(&neigh->lock);
  		neigh->ops->error_report(neigh, skb);
  		write_lock(&neigh->lock);
  	}
  	skb_queue_purge(&neigh->arp_queue);
8b5c171bb   Eric Dumazet   neigh: new unreso...
841
  	neigh->arp_queue_len_bytes = 0;
5ef12d98a   Timo Teras   neigh: fix state ...
842
  }
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
843
844
845
846
847
848
849
850
851
852
853
854
  static void neigh_probe(struct neighbour *neigh)
  	__releases(neigh->lock)
  {
  	struct sk_buff *skb = skb_peek(&neigh->arp_queue);
  	/* keep skb alive even if arp_queue overflows */
  	if (skb)
  		skb = skb_copy(skb, GFP_ATOMIC);
  	write_unlock(&neigh->lock);
  	neigh->ops->solicit(neigh, skb);
  	atomic_inc(&neigh->probes);
  	kfree_skb(skb);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
856
857
858
859
860
861
862
863
864
865
866
867
868
  /* Called when a timer expires for a neighbour entry. */
  
  static void neigh_timer_handler(unsigned long arg)
  {
  	unsigned long now, next;
  	struct neighbour *neigh = (struct neighbour *)arg;
  	unsigned state;
  	int notify = 0;
  
  	write_lock(&neigh->lock);
  
  	state = neigh->nud_state;
  	now = jiffies;
  	next = now + HZ;
045f7b3b0   David S. Miller   neigh: Kill bogus...
869
  	if (!(state & NUD_IN_TIMER))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
872
  
  	if (state & NUD_REACHABLE) {
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
873
  		if (time_before_eq(now,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
875
876
877
878
879
880
881
882
  				   neigh->confirmed + neigh->parms->reachable_time)) {
  			NEIGH_PRINTK2("neigh %p is still alive.
  ", neigh);
  			next = neigh->confirmed + neigh->parms->reachable_time;
  		} else if (time_before_eq(now,
  					  neigh->used + neigh->parms->delay_probe_time)) {
  			NEIGH_PRINTK2("neigh %p is delayed.
  ", neigh);
  			neigh->nud_state = NUD_DELAY;
955aaa2fe   YOSHIFUJI Hideaki   [NET]: NEIGHBOUR:...
883
  			neigh->updated = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
885
886
887
888
889
  			neigh_suspect(neigh);
  			next = now + neigh->parms->delay_probe_time;
  		} else {
  			NEIGH_PRINTK2("neigh %p is suspected.
  ", neigh);
  			neigh->nud_state = NUD_STALE;
955aaa2fe   YOSHIFUJI Hideaki   [NET]: NEIGHBOUR:...
890
  			neigh->updated = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
  			neigh_suspect(neigh);
8d71740c5   Tom Tucker   [NET]: Core net c...
892
  			notify = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
894
  		}
  	} else if (state & NUD_DELAY) {
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
895
  		if (time_before_eq(now,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
897
898
899
  				   neigh->confirmed + neigh->parms->delay_probe_time)) {
  			NEIGH_PRINTK2("neigh %p is now reachable.
  ", neigh);
  			neigh->nud_state = NUD_REACHABLE;
955aaa2fe   YOSHIFUJI Hideaki   [NET]: NEIGHBOUR:...
900
  			neigh->updated = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
901
  			neigh_connect(neigh);
8d71740c5   Tom Tucker   [NET]: Core net c...
902
  			notify = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
904
905
906
907
  			next = neigh->confirmed + neigh->parms->reachable_time;
  		} else {
  			NEIGH_PRINTK2("neigh %p is probed.
  ", neigh);
  			neigh->nud_state = NUD_PROBE;
955aaa2fe   YOSHIFUJI Hideaki   [NET]: NEIGHBOUR:...
908
  			neigh->updated = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
910
911
912
913
914
915
916
917
918
  			atomic_set(&neigh->probes, 0);
  			next = now + neigh->parms->retrans_time;
  		}
  	} else {
  		/* NUD_PROBE|NUD_INCOMPLETE */
  		next = now + neigh->parms->retrans_time;
  	}
  
  	if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
  	    atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
919
920
  		neigh->nud_state = NUD_FAILED;
  		notify = 1;
5ef12d98a   Timo Teras   neigh: fix state ...
921
  		neigh_invalidate(neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
923
924
  	}
  
  	if (neigh->nud_state & NUD_IN_TIMER) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
926
  		if (time_before(next, jiffies + HZ/2))
  			next = jiffies + HZ/2;
6fb9974f4   Herbert Xu   [NEIGH] Fix add_t...
927
928
  		if (!mod_timer(&neigh->timer, next))
  			neigh_hold(neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
  	}
  	if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
931
  		neigh_probe(neigh);
9ff566074   David S. Miller   Revert "[NDISC]: ...
932
  	} else {
69cc64d8d   David S. Miller   [NDISC]: Fix race...
933
  out:
9ff566074   David S. Miller   Revert "[NDISC]: ...
934
935
  		write_unlock(&neigh->lock);
  	}
d961db358   Thomas Graf   [NEIGH]: Netlink ...
936

8d71740c5   Tom Tucker   [NET]: Core net c...
937
  	if (notify)
d961db358   Thomas Graf   [NEIGH]: Netlink ...
938
  		neigh_update_notify(neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
941
942
943
944
945
  	neigh_release(neigh);
  }
  
  int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
  {
  	int rc;
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
946
  	bool immediate_probe = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
948
949
950
951
952
  
  	write_lock_bh(&neigh->lock);
  
  	rc = 0;
  	if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
  		goto out_unlock_bh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
954
  	if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
  		if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
955
  			unsigned long next, now = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
957
  			atomic_set(&neigh->probes, neigh->parms->ucast_probes);
  			neigh->nud_state     = NUD_INCOMPLETE;
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
958
959
960
961
  			neigh->updated = now;
  			next = now + max(neigh->parms->retrans_time, HZ/2);
  			neigh_add_timer(neigh, next);
  			immediate_probe = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
963
  		} else {
  			neigh->nud_state = NUD_FAILED;
955aaa2fe   YOSHIFUJI Hideaki   [NET]: NEIGHBOUR:...
964
  			neigh->updated = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
  			write_unlock_bh(&neigh->lock);
f3fbbe0f6   Wei Yongjun   core: remove some...
966
  			kfree_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
968
969
970
971
  			return 1;
  		}
  	} else if (neigh->nud_state & NUD_STALE) {
  		NEIGH_PRINTK2("neigh %p is delayed.
  ", neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
  		neigh->nud_state = NUD_DELAY;
955aaa2fe   YOSHIFUJI Hideaki   [NET]: NEIGHBOUR:...
973
  		neigh->updated = jiffies;
667347f1c   David S. Miller   [NEIGH]: Add debu...
974
975
  		neigh_add_timer(neigh,
  				jiffies + neigh->parms->delay_probe_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
978
979
  	}
  
  	if (neigh->nud_state == NUD_INCOMPLETE) {
  		if (skb) {
8b5c171bb   Eric Dumazet   neigh: new unreso...
980
981
  			while (neigh->arp_queue_len_bytes + skb->truesize >
  			       neigh->parms->queue_len_bytes) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982
  				struct sk_buff *buff;
8b5c171bb   Eric Dumazet   neigh: new unreso...
983

f72051b06   David S. Miller   neigh: Remove by-...
984
  				buff = __skb_dequeue(&neigh->arp_queue);
8b5c171bb   Eric Dumazet   neigh: new unreso...
985
986
987
  				if (!buff)
  					break;
  				neigh->arp_queue_len_bytes -= buff->truesize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
  				kfree_skb(buff);
9a6d276e8   Neil Horman   core: add stat to...
989
  				NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
  			}
a47311380   Eric Dumazet   net: fix __neigh_...
991
  			skb_dst_force(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992
  			__skb_queue_tail(&neigh->arp_queue, skb);
8b5c171bb   Eric Dumazet   neigh: new unreso...
993
  			neigh->arp_queue_len_bytes += skb->truesize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994
995
996
997
  		}
  		rc = 1;
  	}
  out_unlock_bh:
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
998
999
1000
1001
1002
  	if (immediate_probe)
  		neigh_probe(neigh);
  	else
  		write_unlock(&neigh->lock);
  	local_bh_enable();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1003
1004
  	return rc;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1005
  EXPORT_SYMBOL(__neigh_event_send);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006

f6b72b621   David S. Miller   net: Embed hh_cac...
1007
  static void neigh_update_hhs(struct neighbour *neigh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
  {
  	struct hh_cache *hh;
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
1010
  	void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
91a72a705   Doug Kehn   net/core: neighbo...
1011
1012
1013
1014
  		= NULL;
  
  	if (neigh->dev->header_ops)
  		update = neigh->dev->header_ops->cache_update;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
1016
  
  	if (update) {
f6b72b621   David S. Miller   net: Embed hh_cac...
1017
1018
  		hh = &neigh->hh;
  		if (hh->hh_len) {
3644f0cee   Stephen Hemminger   [NET]: Convert hh...
1019
  			write_seqlock_bh(&hh->hh_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
  			update(hh, neigh->dev, neigh->ha);
3644f0cee   Stephen Hemminger   [NET]: Convert hh...
1021
  			write_sequnlock_bh(&hh->hh_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
  		}
  	}
  }
  
  
  
  /* Generic update routine.
     -- lladdr is new lladdr or NULL, if it is not supplied.
     -- new    is new state.
     -- flags
  	NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr,
  				if it is different.
  	NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected"
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1035
  				lladdr instead of overriding it
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1036
1037
1038
1039
  				if it is different.
  				It also allows to retain current state
  				if lladdr is unchanged.
  	NEIGH_UPDATE_F_ADMIN	means that the change is administrative.
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1040
  	NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
  				NTF_ROUTER flag.
  	NEIGH_UPDATE_F_ISROUTER	indicates if the neighbour is known as
  				a router.
  
     Caller MUST hold reference count on the entry.
   */
  
  int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
  		 u32 flags)
  {
  	u8 old;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1053
  	int notify = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1054
1055
1056
1057
1058
1059
1060
1061
  	struct net_device *dev;
  	int update_isrouter = 0;
  
  	write_lock_bh(&neigh->lock);
  
  	dev    = neigh->dev;
  	old    = neigh->nud_state;
  	err    = -EPERM;
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1062
  	if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
1064
1065
1066
1067
1068
1069
1070
1071
  	    (old & (NUD_NOARP | NUD_PERMANENT)))
  		goto out;
  
  	if (!(new & NUD_VALID)) {
  		neigh_del_timer(neigh);
  		if (old & NUD_CONNECTED)
  			neigh_suspect(neigh);
  		neigh->nud_state = new;
  		err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1072
  		notify = old & NUD_VALID;
5ef12d98a   Timo Teras   neigh: fix state ...
1073
1074
1075
1076
1077
  		if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
  		    (new & NUD_FAILED)) {
  			neigh_invalidate(neigh);
  			notify = 1;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
  		goto out;
  	}
  
  	/* Compare new lladdr with cached one */
  	if (!dev->addr_len) {
  		/* First case: device needs no address. */
  		lladdr = neigh->ha;
  	} else if (lladdr) {
  		/* The second case: if something is already cached
  		   and a new address is proposed:
  		   - compare new & old
  		   - if they are different, check override flag
  		 */
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1091
  		if ((old & NUD_VALID) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
  		    !memcmp(lladdr, neigh->ha, dev->addr_len))
  			lladdr = neigh->ha;
  	} else {
  		/* No address is supplied; if we know something,
  		   use it, otherwise discard the request.
  		 */
  		err = -EINVAL;
  		if (!(old & NUD_VALID))
  			goto out;
  		lladdr = neigh->ha;
  	}
  
  	if (new & NUD_CONNECTED)
  		neigh->confirmed = jiffies;
  	neigh->updated = jiffies;
  
  	/* If entry was valid and address is not changed,
  	   do not change entry state, if new one is STALE.
  	 */
  	err = 0;
  	update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
  	if (old & NUD_VALID) {
  		if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {
  			update_isrouter = 0;
  			if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&
  			    (old & NUD_CONNECTED)) {
  				lladdr = neigh->ha;
  				new = NUD_STALE;
  			} else
  				goto out;
  		} else {
  			if (lladdr == neigh->ha && new == NUD_STALE &&
  			    ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) ||
  			     (old & NUD_CONNECTED))
  			    )
  				new = old;
  		}
  	}
  
  	if (new != old) {
  		neigh_del_timer(neigh);
a43d8994b   Pavel Emelyanov   [NEIGH]: Make nei...
1133
  		if (new & NUD_IN_TIMER)
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1134
1135
  			neigh_add_timer(neigh, (jiffies +
  						((new & NUD_REACHABLE) ?
667347f1c   David S. Miller   [NEIGH]: Add debu...
1136
1137
  						 neigh->parms->reachable_time :
  						 0)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138
1139
1140
1141
  		neigh->nud_state = new;
  	}
  
  	if (lladdr != neigh->ha) {
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1142
  		write_seqlock(&neigh->ha_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
  		memcpy(&neigh->ha, lladdr, dev->addr_len);
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1144
  		write_sequnlock(&neigh->ha_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145
1146
1147
1148
  		neigh_update_hhs(neigh);
  		if (!(new & NUD_CONNECTED))
  			neigh->confirmed = jiffies -
  				      (neigh->parms->base_reachable_time << 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1149
  		notify = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
  	}
  	if (new == old)
  		goto out;
  	if (new & NUD_CONNECTED)
  		neigh_connect(neigh);
  	else
  		neigh_suspect(neigh);
  	if (!(old & NUD_VALID)) {
  		struct sk_buff *skb;
  
  		/* Again: avoid dead loop if something went wrong */
  
  		while (neigh->nud_state & NUD_VALID &&
  		       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
69cce1d14   David S. Miller   net: Abstract dst...
1164
1165
  			struct dst_entry *dst = skb_dst(skb);
  			struct neighbour *n2, *n1 = neigh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
  			write_unlock_bh(&neigh->lock);
e049f2888   roy.qing.li@gmail.com   neigh: fix rcu sp...
1167
1168
  
  			rcu_read_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1169
  			/* On shaper/eql skb->dst->neighbour != neigh :( */
272174550   David Miller   net: Rename dst_g...
1170
  			if (dst && (n2 = dst_get_neighbour_noref(dst)) != NULL)
69cce1d14   David S. Miller   net: Abstract dst...
1171
  				n1 = n2;
8f40b161d   David S. Miller   neigh: Pass neigh...
1172
  			n1->output(n1, skb);
e049f2888   roy.qing.li@gmail.com   neigh: fix rcu sp...
1173
  			rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174
1175
1176
  			write_lock_bh(&neigh->lock);
  		}
  		skb_queue_purge(&neigh->arp_queue);
8b5c171bb   Eric Dumazet   neigh: new unreso...
1177
  		neigh->arp_queue_len_bytes = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
1179
1180
1181
1182
1183
1184
1185
  	}
  out:
  	if (update_isrouter) {
  		neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?
  			(neigh->flags | NTF_ROUTER) :
  			(neigh->flags & ~NTF_ROUTER);
  	}
  	write_unlock_bh(&neigh->lock);
8d71740c5   Tom Tucker   [NET]: Core net c...
1186
1187
  
  	if (notify)
d961db358   Thomas Graf   [NEIGH]: Netlink ...
1188
  		neigh_update_notify(neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189
1190
  	return err;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1191
  EXPORT_SYMBOL(neigh_update);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
1193
1194
1195
1196
1197
1198
1199
  
  struct neighbour *neigh_event_ns(struct neigh_table *tbl,
  				 u8 *lladdr, void *saddr,
  				 struct net_device *dev)
  {
  	struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev,
  						 lladdr || !dev->addr_len);
  	if (neigh)
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1200
  		neigh_update(neigh, lladdr, NUD_STALE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201
1202
1203
  			     NEIGH_UPDATE_F_OVERRIDE);
  	return neigh;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1204
  EXPORT_SYMBOL(neigh_event_ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1205

34d101dd6   Eric Dumazet   neigh: speedup ne...
1206
  /* called with read_lock_bh(&n->lock); */
f6b72b621   David S. Miller   net: Embed hh_cac...
1207
  static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1209
  	struct net_device *dev = dst->dev;
f6b72b621   David S. Miller   net: Embed hh_cac...
1210
1211
  	__be16 prot = dst->ops->protocol;
  	struct hh_cache	*hh = &n->hh;
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1212
1213
  
  	write_lock_bh(&n->lock);
34d101dd6   Eric Dumazet   neigh: speedup ne...
1214

f6b72b621   David S. Miller   net: Embed hh_cac...
1215
1216
1217
  	/* Only one thread can come in here and initialize the
  	 * hh_cache entry.
  	 */
b23b5455b   David S. Miller   neigh: Kill hh_ca...
1218
1219
  	if (!hh->hh_len)
  		dev->header_ops->cache(n, hh, prot);
34d101dd6   Eric Dumazet   neigh: speedup ne...
1220

0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1221
  	write_unlock_bh(&n->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
1223
1224
  }
  
  /* This function can be used in contexts, where only old dev_queue_xmit
767e97e1e   Eric Dumazet   neigh: RCU conver...
1225
1226
   * worked, f.e. if you want to override normal output path (eql, shaper),
   * but resolution is not made yet.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1227
   */
8f40b161d   David S. Miller   neigh: Pass neigh...
1228
  int neigh_compat_output(struct neighbour *neigh, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229
1230
  {
  	struct net_device *dev = skb->dev;
bbe735e42   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1231
  	__skb_pull(skb, skb_network_offset(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232

0c4e85813   Stephen Hemminger   [NET]: Wrap netde...
1233
1234
  	if (dev_hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL,
  			    skb->len) < 0 &&
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
1235
  	    dev->header_ops->rebuild(skb))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1236
1237
1238
1239
  		return 0;
  
  	return dev_queue_xmit(skb);
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1240
  EXPORT_SYMBOL(neigh_compat_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1241
1242
  
  /* Slow and careful. */
8f40b161d   David S. Miller   neigh: Pass neigh...
1243
  int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244
  {
adf30907d   Eric Dumazet   net: skb->dst acc...
1245
  	struct dst_entry *dst = skb_dst(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1246
  	int rc = 0;
8f40b161d   David S. Miller   neigh: Pass neigh...
1247
  	if (!dst)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1248
  		goto discard;
bbe735e42   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1249
  	__skb_pull(skb, skb_network_offset(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250
1251
1252
1253
  
  	if (!neigh_event_send(neigh, skb)) {
  		int err;
  		struct net_device *dev = neigh->dev;
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1254
  		unsigned int seq;
34d101dd6   Eric Dumazet   neigh: speedup ne...
1255

f6b72b621   David S. Miller   net: Embed hh_cac...
1256
1257
  		if (dev->header_ops->cache && !neigh->hh.hh_len)
  			neigh_hh_init(neigh, dst);
34d101dd6   Eric Dumazet   neigh: speedup ne...
1258

0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1259
1260
1261
1262
1263
  		do {
  			seq = read_seqbegin(&neigh->ha_lock);
  			err = dev_hard_header(skb, dev, ntohs(skb->protocol),
  					      neigh->ha, NULL, skb->len);
  		} while (read_seqretry(&neigh->ha_lock, seq));
34d101dd6   Eric Dumazet   neigh: speedup ne...
1264

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1265
  		if (err >= 0)
542d4d685   David S. Miller   neigh: Kill ndisc...
1266
  			rc = dev_queue_xmit(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
1268
1269
1270
1271
1272
1273
1274
  		else
  			goto out_kfree_skb;
  	}
  out:
  	return rc;
  discard:
  	NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p
  ",
8f40b161d   David S. Miller   neigh: Pass neigh...
1275
  		      dst, neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
1277
1278
1279
1280
  out_kfree_skb:
  	rc = -EINVAL;
  	kfree_skb(skb);
  	goto out;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1281
  EXPORT_SYMBOL(neigh_resolve_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1282
1283
  
  /* As fast as possible without hh cache */
8f40b161d   David S. Miller   neigh: Pass neigh...
1284
  int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1286
  	struct net_device *dev = neigh->dev;
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1287
  	unsigned int seq;
8f40b161d   David S. Miller   neigh: Pass neigh...
1288
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1289

bbe735e42   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
1290
  	__skb_pull(skb, skb_network_offset(skb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1291

0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1292
1293
1294
1295
1296
  	do {
  		seq = read_seqbegin(&neigh->ha_lock);
  		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
  				      neigh->ha, NULL, skb->len);
  	} while (read_seqretry(&neigh->ha_lock, seq));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1297
  	if (err >= 0)
542d4d685   David S. Miller   neigh: Kill ndisc...
1298
  		err = dev_queue_xmit(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1299
1300
1301
1302
1303
1304
  	else {
  		err = -EINVAL;
  		kfree_skb(skb);
  	}
  	return err;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1305
  EXPORT_SYMBOL(neigh_connected_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1306

8f40b161d   David S. Miller   neigh: Pass neigh...
1307
1308
1309
1310
1311
  int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
  {
  	return dev_queue_xmit(skb);
  }
  EXPORT_SYMBOL(neigh_direct_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1312
1313
1314
1315
1316
  static void neigh_proxy_process(unsigned long arg)
  {
  	struct neigh_table *tbl = (struct neigh_table *)arg;
  	long sched_next = 0;
  	unsigned long now = jiffies;
f72051b06   David S. Miller   neigh: Remove by-...
1317
  	struct sk_buff *skb, *n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1318
1319
  
  	spin_lock(&tbl->proxy_queue.lock);
f72051b06   David S. Miller   neigh: Remove by-...
1320
1321
  	skb_queue_walk_safe(&tbl->proxy_queue, skb, n) {
  		long tdif = NEIGH_CB(skb)->sched_next - now;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1322

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
  		if (tdif <= 0) {
f72051b06   David S. Miller   neigh: Remove by-...
1324
  			struct net_device *dev = skb->dev;
20e6074eb   Eric Dumazet   arp: fix rcu lock...
1325

f72051b06   David S. Miller   neigh: Remove by-...
1326
  			__skb_unlink(skb, &tbl->proxy_queue);
20e6074eb   Eric Dumazet   arp: fix rcu lock...
1327
1328
  			if (tbl->proxy_redo && netif_running(dev)) {
  				rcu_read_lock();
f72051b06   David S. Miller   neigh: Remove by-...
1329
  				tbl->proxy_redo(skb);
20e6074eb   Eric Dumazet   arp: fix rcu lock...
1330
1331
  				rcu_read_unlock();
  			} else {
f72051b06   David S. Miller   neigh: Remove by-...
1332
  				kfree_skb(skb);
20e6074eb   Eric Dumazet   arp: fix rcu lock...
1333
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
  
  			dev_put(dev);
  		} else if (!sched_next || tdif < sched_next)
  			sched_next = tdif;
  	}
  	del_timer(&tbl->proxy_timer);
  	if (sched_next)
  		mod_timer(&tbl->proxy_timer, jiffies + sched_next);
  	spin_unlock(&tbl->proxy_queue.lock);
  }
  
  void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
  		    struct sk_buff *skb)
  {
  	unsigned long now = jiffies;
  	unsigned long sched_next = now + (net_random() % p->proxy_delay);
  
  	if (tbl->proxy_queue.qlen > p->proxy_qlen) {
  		kfree_skb(skb);
  		return;
  	}
a61bbcf28   Patrick McHardy   [NET]: Store skb-...
1355
1356
1357
  
  	NEIGH_CB(skb)->sched_next = sched_next;
  	NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1358
1359
1360
1361
1362
1363
  
  	spin_lock(&tbl->proxy_queue.lock);
  	if (del_timer(&tbl->proxy_timer)) {
  		if (time_before(tbl->proxy_timer.expires, sched_next))
  			sched_next = tbl->proxy_timer.expires;
  	}
adf30907d   Eric Dumazet   net: skb->dst acc...
1364
  	skb_dst_drop(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1365
1366
1367
1368
1369
  	dev_hold(skb->dev);
  	__skb_queue_tail(&tbl->proxy_queue, skb);
  	mod_timer(&tbl->proxy_timer, sched_next);
  	spin_unlock(&tbl->proxy_queue.lock);
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1370
  EXPORT_SYMBOL(pneigh_enqueue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1371

97fd5bc7f   Tobias Klauser   net: Rename looku...
1372
  static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
1373
1374
1375
1376
1377
  						      struct net *net, int ifindex)
  {
  	struct neigh_parms *p;
  
  	for (p = &tbl->parms; p; p = p->next) {
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1378
  		if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
1379
1380
1381
1382
1383
1384
  		    (!p->dev && !ifindex))
  			return p;
  	}
  
  	return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1385
1386
1387
1388
  
  struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
  				      struct neigh_table *tbl)
  {
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
1389
  	struct neigh_parms *p, *ref;
008298231   Stephen Hemminger   netdev: add more ...
1390
1391
  	struct net *net = dev_net(dev);
  	const struct net_device_ops *ops = dev->netdev_ops;
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
1392

97fd5bc7f   Tobias Klauser   net: Rename looku...
1393
  	ref = lookup_neigh_parms(tbl, net, 0);
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
1394
1395
  	if (!ref)
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1396

426b5303e   Eric W. Biederman   [NETNS]: Modify t...
1397
  	p = kmemdup(ref, sizeof(*p), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1398
  	if (p) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1399
1400
  		p->tbl		  = tbl;
  		atomic_set(&p->refcnt, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1401
1402
  		p->reachable_time =
  				neigh_rand_reach_time(p->base_reachable_time);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1403

008298231   Stephen Hemminger   netdev: add more ...
1404
  		if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
486b51d37   Denis V. Lunev   [ARP]: Remove ove...
1405
1406
  			kfree(p);
  			return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1407
  		}
486b51d37   Denis V. Lunev   [ARP]: Remove ove...
1408
1409
1410
  
  		dev_hold(dev);
  		p->dev = dev;
e42ea986e   Eric Dumazet   net: Cleanup of n...
1411
  		write_pnet(&p->net, hold_net(net));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
1413
1414
1415
1416
1417
1418
1419
  		p->sysctl_table = NULL;
  		write_lock_bh(&tbl->lock);
  		p->next		= tbl->parms.next;
  		tbl->parms.next = p;
  		write_unlock_bh(&tbl->lock);
  	}
  	return p;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1420
  EXPORT_SYMBOL(neigh_parms_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
  
  static void neigh_rcu_free_parms(struct rcu_head *head)
  {
  	struct neigh_parms *parms =
  		container_of(head, struct neigh_parms, rcu_head);
  
  	neigh_parms_put(parms);
  }
  
  void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
  {
  	struct neigh_parms **p;
  
  	if (!parms || parms == &tbl->parms)
  		return;
  	write_lock_bh(&tbl->lock);
  	for (p = &tbl->parms.next; *p; p = &(*p)->next) {
  		if (*p == parms) {
  			*p = parms->next;
  			parms->dead = 1;
  			write_unlock_bh(&tbl->lock);
cecbb6396   David S. Miller   [NEIGH]: Revert '...
1442
1443
  			if (parms->dev)
  				dev_put(parms->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1444
1445
1446
1447
1448
1449
1450
1451
  			call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
  			return;
  		}
  	}
  	write_unlock_bh(&tbl->lock);
  	NEIGH_PRINTK1("neigh_parms_release: not found
  ");
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1452
  EXPORT_SYMBOL(neigh_parms_release);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1453

06f0511df   Denis V. Lunev   [ARP]: neigh_parm...
1454
  static void neigh_parms_destroy(struct neigh_parms *parms)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1455
  {
57da52c1e   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1456
  	release_net(neigh_parms_net(parms));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1457
1458
  	kfree(parms);
  }
c2ecba717   Pavel Emelianov   [NET]: Set a sepa...
1459
  static struct lock_class_key neigh_table_proxy_queue_class;
bd89efc53   Simon Kelley   [NEIGH]: Fix IP-o...
1460
  void neigh_table_init_no_netlink(struct neigh_table *tbl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1461
1462
1463
  {
  	unsigned long now = jiffies;
  	unsigned long phsize;
e42ea986e   Eric Dumazet   net: Cleanup of n...
1464
  	write_pnet(&tbl->parms.net, &init_net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1465
  	atomic_set(&tbl->parms.refcnt, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1466
1467
  	tbl->parms.reachable_time =
  			  neigh_rand_reach_time(tbl->parms.base_reachable_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1468
1469
1470
  	tbl->stats = alloc_percpu(struct neigh_statistics);
  	if (!tbl->stats)
  		panic("cannot create neighbour cache statistics");
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1471

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1472
  #ifdef CONFIG_PROC_FS
9b739ba5e   Alexey Dobriyan   net: remove struc...
1473
1474
  	if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat,
  			      &neigh_stat_seq_fops, tbl))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1475
  		panic("cannot create neighbour proc dir entry");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1476
  #endif
cd0893369   David S. Miller   neigh: Store hash...
1477
  	RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1478
1479
  
  	phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
77d04bd95   Andrew Morton   [NET]: More kzall...
1480
  	tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1481

d6bf78171   Eric Dumazet   net neigh: RCU co...
1482
  	if (!tbl->nht || !tbl->phash_buckets)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1483
  		panic("cannot allocate neighbour cache hashes");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1484
  	rwlock_init(&tbl->lock);
e4c4e448c   Eric Dumazet   neigh: Convert ga...
1485
1486
  	INIT_DELAYED_WORK_DEFERRABLE(&tbl->gc_work, neigh_periodic_work);
  	schedule_delayed_work(&tbl->gc_work, tbl->parms.reachable_time);
b24b8a247   Pavel Emelyanov   [NET]: Convert in...
1487
  	setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl);
c2ecba717   Pavel Emelianov   [NET]: Set a sepa...
1488
1489
  	skb_queue_head_init_class(&tbl->proxy_queue,
  			&neigh_table_proxy_queue_class);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1490
1491
1492
  
  	tbl->last_flush = now;
  	tbl->last_rand	= now + tbl->parms.reachable_time * 20;
bd89efc53   Simon Kelley   [NEIGH]: Fix IP-o...
1493
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1494
  EXPORT_SYMBOL(neigh_table_init_no_netlink);
bd89efc53   Simon Kelley   [NEIGH]: Fix IP-o...
1495
1496
1497
1498
1499
1500
  
  void neigh_table_init(struct neigh_table *tbl)
  {
  	struct neigh_table *tmp;
  
  	neigh_table_init_no_netlink(tbl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501
  	write_lock(&neigh_tbl_lock);
bd89efc53   Simon Kelley   [NEIGH]: Fix IP-o...
1502
1503
1504
1505
  	for (tmp = neigh_tables; tmp; tmp = tmp->next) {
  		if (tmp->family == tbl->family)
  			break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1506
1507
1508
  	tbl->next	= neigh_tables;
  	neigh_tables	= tbl;
  	write_unlock(&neigh_tbl_lock);
bd89efc53   Simon Kelley   [NEIGH]: Fix IP-o...
1509
1510
1511
1512
1513
1514
1515
  
  	if (unlikely(tmp)) {
  		printk(KERN_ERR "NEIGH: Registering multiple tables for "
  		       "family %d
  ", tbl->family);
  		dump_stack();
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1516
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1517
  EXPORT_SYMBOL(neigh_table_init);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1518
1519
1520
1521
1522
1523
  
  int neigh_table_clear(struct neigh_table *tbl)
  {
  	struct neigh_table **tp;
  
  	/* It is not clean... Fix it to unload IPv6 module safely */
a5c30b349   Tejun Heo   net/neighbour: ca...
1524
  	cancel_delayed_work_sync(&tbl->gc_work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
  	del_timer_sync(&tbl->proxy_timer);
  	pneigh_queue_purge(&tbl->proxy_queue);
  	neigh_ifdown(tbl, NULL);
  	if (atomic_read(&tbl->entries))
  		printk(KERN_CRIT "neighbour leakage
  ");
  	write_lock(&neigh_tbl_lock);
  	for (tp = &neigh_tables; *tp; tp = &(*tp)->next) {
  		if (*tp == tbl) {
  			*tp = tbl->next;
  			break;
  		}
  	}
  	write_unlock(&neigh_tbl_lock);
6193d2be2   Eric Dumazet   neigh: __rcu anno...
1539
1540
  	call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
  		 neigh_hash_free_rcu);
d6bf78171   Eric Dumazet   net neigh: RCU co...
1541
  	tbl->nht = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1542
1543
1544
  
  	kfree(tbl->phash_buckets);
  	tbl->phash_buckets = NULL;
3f192b5c5   Alexey Dobriyan   [NET]: Remove /pr...
1545
  	remove_proc_entry(tbl->id, init_net.proc_net_stat);
3fcde74b3   Kirill Korotaev   [NEIGH]: neigh_ta...
1546
1547
  	free_percpu(tbl->stats);
  	tbl->stats = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1548
1549
  	return 0;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1550
  EXPORT_SYMBOL(neigh_table_clear);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1551

c8822a4e0   Thomas Graf   [NEIGH]: Use rtnl...
1552
  static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1553
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1554
  	struct net *net = sock_net(skb->sk);
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1555
1556
  	struct ndmsg *ndm;
  	struct nlattr *dst_attr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1557
1558
  	struct neigh_table *tbl;
  	struct net_device *dev = NULL;
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1559
  	int err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1560

110b24993   Eric Dumazet   net neigh: neigh_...
1561
  	ASSERT_RTNL();
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1562
  	if (nlmsg_len(nlh) < sizeof(*ndm))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1563
  		goto out;
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1564
1565
1566
1567
1568
1569
  	dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
  	if (dst_attr == NULL)
  		goto out;
  
  	ndm = nlmsg_data(nlh);
  	if (ndm->ndm_ifindex) {
110b24993   Eric Dumazet   net neigh: neigh_...
1570
  		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1571
1572
1573
1574
1575
  		if (dev == NULL) {
  			err = -ENODEV;
  			goto out;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1576
1577
  	read_lock(&neigh_tbl_lock);
  	for (tbl = neigh_tables; tbl; tbl = tbl->next) {
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1578
  		struct neighbour *neigh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1579
1580
1581
1582
  
  		if (tbl->family != ndm->ndm_family)
  			continue;
  		read_unlock(&neigh_tbl_lock);
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1583
  		if (nla_len(dst_attr) < tbl->key_len)
110b24993   Eric Dumazet   net neigh: neigh_...
1584
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1585
1586
  
  		if (ndm->ndm_flags & NTF_PROXY) {
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
1587
  			err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
110b24993   Eric Dumazet   net neigh: neigh_...
1588
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1589
  		}
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1590
  		if (dev == NULL)
110b24993   Eric Dumazet   net neigh: neigh_...
1591
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1592

a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1593
1594
1595
  		neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
  		if (neigh == NULL) {
  			err = -ENOENT;
110b24993   Eric Dumazet   net neigh: neigh_...
1596
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
  		}
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1598
1599
1600
1601
1602
  
  		err = neigh_update(neigh, NULL, NUD_FAILED,
  				   NEIGH_UPDATE_F_OVERRIDE |
  				   NEIGH_UPDATE_F_ADMIN);
  		neigh_release(neigh);
110b24993   Eric Dumazet   net neigh: neigh_...
1603
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1604
1605
  	}
  	read_unlock(&neigh_tbl_lock);
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1606
  	err = -EAFNOSUPPORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1607
1608
1609
  out:
  	return err;
  }
c8822a4e0   Thomas Graf   [NEIGH]: Use rtnl...
1610
  static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1611
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1612
  	struct net *net = sock_net(skb->sk);
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1613
1614
  	struct ndmsg *ndm;
  	struct nlattr *tb[NDA_MAX+1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1615
1616
  	struct neigh_table *tbl;
  	struct net_device *dev = NULL;
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1617
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1618

110b24993   Eric Dumazet   net neigh: neigh_...
1619
  	ASSERT_RTNL();
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1620
1621
  	err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1622
  		goto out;
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1623
1624
1625
1626
1627
1628
  	err = -EINVAL;
  	if (tb[NDA_DST] == NULL)
  		goto out;
  
  	ndm = nlmsg_data(nlh);
  	if (ndm->ndm_ifindex) {
110b24993   Eric Dumazet   net neigh: neigh_...
1629
  		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1630
1631
1632
1633
1634
1635
  		if (dev == NULL) {
  			err = -ENODEV;
  			goto out;
  		}
  
  		if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
110b24993   Eric Dumazet   net neigh: neigh_...
1636
  			goto out;
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1637
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1638
1639
  	read_lock(&neigh_tbl_lock);
  	for (tbl = neigh_tables; tbl; tbl = tbl->next) {
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1640
1641
1642
  		int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
  		struct neighbour *neigh;
  		void *dst, *lladdr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1643
1644
1645
1646
  
  		if (tbl->family != ndm->ndm_family)
  			continue;
  		read_unlock(&neigh_tbl_lock);
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1647
  		if (nla_len(tb[NDA_DST]) < tbl->key_len)
110b24993   Eric Dumazet   net neigh: neigh_...
1648
  			goto out;
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1649
1650
  		dst = nla_data(tb[NDA_DST]);
  		lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1651
1652
  
  		if (ndm->ndm_flags & NTF_PROXY) {
62dd93181   Ville Nuorvala   [IPV6] NDISC: Set...
1653
1654
1655
  			struct pneigh_entry *pn;
  
  			err = -ENOBUFS;
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
1656
  			pn = pneigh_lookup(tbl, net, dst, dev, 1);
62dd93181   Ville Nuorvala   [IPV6] NDISC: Set...
1657
1658
1659
1660
  			if (pn) {
  				pn->flags = ndm->ndm_flags;
  				err = 0;
  			}
110b24993   Eric Dumazet   net neigh: neigh_...
1661
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1662
  		}
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1663
  		if (dev == NULL)
110b24993   Eric Dumazet   net neigh: neigh_...
1664
  			goto out;
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1665
1666
1667
1668
1669
  
  		neigh = neigh_lookup(tbl, dst, dev);
  		if (neigh == NULL) {
  			if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
  				err = -ENOENT;
110b24993   Eric Dumazet   net neigh: neigh_...
1670
  				goto out;
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1671
  			}
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1672

5208debd0   Thomas Graf   [NEIGH]: Convert ...
1673
1674
1675
  			neigh = __neigh_lookup_errno(tbl, dst, dev);
  			if (IS_ERR(neigh)) {
  				err = PTR_ERR(neigh);
110b24993   Eric Dumazet   net neigh: neigh_...
1676
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1677
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1678
  		} else {
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1679
1680
1681
  			if (nlh->nlmsg_flags & NLM_F_EXCL) {
  				err = -EEXIST;
  				neigh_release(neigh);
110b24993   Eric Dumazet   net neigh: neigh_...
1682
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1683
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1684

5208debd0   Thomas Graf   [NEIGH]: Convert ...
1685
1686
1687
  			if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
  				flags &= ~NEIGH_UPDATE_F_OVERRIDE;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1688

0c5c2d308   Eric Biederman   neigh: Allow for ...
1689
1690
1691
1692
1693
  		if (ndm->ndm_flags & NTF_USE) {
  			neigh_event_send(neigh, NULL);
  			err = 0;
  		} else
  			err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1694
  		neigh_release(neigh);
110b24993   Eric Dumazet   net neigh: neigh_...
1695
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1696
1697
1698
  	}
  
  	read_unlock(&neigh_tbl_lock);
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1699
  	err = -EAFNOSUPPORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1700
1701
1702
  out:
  	return err;
  }
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1703
1704
  static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
  {
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1705
1706
1707
1708
1709
  	struct nlattr *nest;
  
  	nest = nla_nest_start(skb, NDTA_PARMS);
  	if (nest == NULL)
  		return -ENOBUFS;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1710
1711
  
  	if (parms->dev)
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1712
1713
1714
  		NLA_PUT_U32(skb, NDTPA_IFINDEX, parms->dev->ifindex);
  
  	NLA_PUT_U32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt));
8b5c171bb   Eric Dumazet   neigh: new unreso...
1715
1716
1717
1718
1719
  	NLA_PUT_U32(skb, NDTPA_QUEUE_LENBYTES, parms->queue_len_bytes);
  	/* approximative value for deprecated QUEUE_LEN (in packets) */
  	NLA_PUT_U32(skb, NDTPA_QUEUE_LEN,
  		    DIV_ROUND_UP(parms->queue_len_bytes,
  				 SKB_TRUESIZE(ETH_FRAME_LEN)));
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1720
1721
1722
1723
1724
1725
  	NLA_PUT_U32(skb, NDTPA_PROXY_QLEN, parms->proxy_qlen);
  	NLA_PUT_U32(skb, NDTPA_APP_PROBES, parms->app_probes);
  	NLA_PUT_U32(skb, NDTPA_UCAST_PROBES, parms->ucast_probes);
  	NLA_PUT_U32(skb, NDTPA_MCAST_PROBES, parms->mcast_probes);
  	NLA_PUT_MSECS(skb, NDTPA_REACHABLE_TIME, parms->reachable_time);
  	NLA_PUT_MSECS(skb, NDTPA_BASE_REACHABLE_TIME,
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1726
  		      parms->base_reachable_time);
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1727
1728
1729
1730
1731
1732
  	NLA_PUT_MSECS(skb, NDTPA_GC_STALETIME, parms->gc_staletime);
  	NLA_PUT_MSECS(skb, NDTPA_DELAY_PROBE_TIME, parms->delay_probe_time);
  	NLA_PUT_MSECS(skb, NDTPA_RETRANS_TIME, parms->retrans_time);
  	NLA_PUT_MSECS(skb, NDTPA_ANYCAST_DELAY, parms->anycast_delay);
  	NLA_PUT_MSECS(skb, NDTPA_PROXY_DELAY, parms->proxy_delay);
  	NLA_PUT_MSECS(skb, NDTPA_LOCKTIME, parms->locktime);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1733

ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1734
  	return nla_nest_end(skb, nest);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1735

ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1736
  nla_put_failure:
bc3ed28ca   Thomas Graf   netlink: Improve ...
1737
1738
  	nla_nest_cancel(skb, nest);
  	return -EMSGSIZE;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1739
  }
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1740
1741
  static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl,
  			      u32 pid, u32 seq, int type, int flags)
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1742
1743
1744
  {
  	struct nlmsghdr *nlh;
  	struct ndtmsg *ndtmsg;
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1745
1746
  	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
  	if (nlh == NULL)
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1747
  		return -EMSGSIZE;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1748

ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1749
  	ndtmsg = nlmsg_data(nlh);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1750
1751
1752
  
  	read_lock_bh(&tbl->lock);
  	ndtmsg->ndtm_family = tbl->family;
9ef1d4c7c   Patrick McHardy   [NETLINK]: Missin...
1753
1754
  	ndtmsg->ndtm_pad1   = 0;
  	ndtmsg->ndtm_pad2   = 0;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1755

ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1756
1757
1758
1759
1760
  	NLA_PUT_STRING(skb, NDTA_NAME, tbl->id);
  	NLA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval);
  	NLA_PUT_U32(skb, NDTA_THRESH1, tbl->gc_thresh1);
  	NLA_PUT_U32(skb, NDTA_THRESH2, tbl->gc_thresh2);
  	NLA_PUT_U32(skb, NDTA_THRESH3, tbl->gc_thresh3);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1761
1762
1763
1764
1765
  
  	{
  		unsigned long now = jiffies;
  		unsigned int flush_delta = now - tbl->last_flush;
  		unsigned int rand_delta = now - tbl->last_rand;
d6bf78171   Eric Dumazet   net neigh: RCU co...
1766
  		struct neigh_hash_table *nht;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1767
1768
1769
1770
1771
1772
  		struct ndt_config ndc = {
  			.ndtc_key_len		= tbl->key_len,
  			.ndtc_entry_size	= tbl->entry_size,
  			.ndtc_entries		= atomic_read(&tbl->entries),
  			.ndtc_last_flush	= jiffies_to_msecs(flush_delta),
  			.ndtc_last_rand		= jiffies_to_msecs(rand_delta),
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1773
1774
  			.ndtc_proxy_qlen	= tbl->proxy_queue.qlen,
  		};
d6bf78171   Eric Dumazet   net neigh: RCU co...
1775
1776
  		rcu_read_lock_bh();
  		nht = rcu_dereference_bh(tbl->nht);
2c2aba6c5   David S. Miller   ipv6: Use univers...
1777
  		ndc.ndtc_hash_rnd = nht->hash_rnd[0];
cd0893369   David S. Miller   neigh: Store hash...
1778
  		ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
d6bf78171   Eric Dumazet   net neigh: RCU co...
1779
  		rcu_read_unlock_bh();
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1780
  		NLA_PUT(skb, NDTA_CONFIG, sizeof(ndc), &ndc);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1781
1782
1783
1784
1785
1786
1787
  	}
  
  	{
  		int cpu;
  		struct ndt_stats ndst;
  
  		memset(&ndst, 0, sizeof(ndst));
6f9120422   KAMEZAWA Hiroyuki   [PATCH] for_each_...
1788
  		for_each_possible_cpu(cpu) {
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1789
  			struct neigh_statistics	*st;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
  			st = per_cpu_ptr(tbl->stats, cpu);
  			ndst.ndts_allocs		+= st->allocs;
  			ndst.ndts_destroys		+= st->destroys;
  			ndst.ndts_hash_grows		+= st->hash_grows;
  			ndst.ndts_res_failed		+= st->res_failed;
  			ndst.ndts_lookups		+= st->lookups;
  			ndst.ndts_hits			+= st->hits;
  			ndst.ndts_rcv_probes_mcast	+= st->rcv_probes_mcast;
  			ndst.ndts_rcv_probes_ucast	+= st->rcv_probes_ucast;
  			ndst.ndts_periodic_gc_runs	+= st->periodic_gc_runs;
  			ndst.ndts_forced_gc_runs	+= st->forced_gc_runs;
  		}
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1802
  		NLA_PUT(skb, NDTA_STATS, sizeof(ndst), &ndst);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1803
1804
1805
1806
  	}
  
  	BUG_ON(tbl->parms.dev);
  	if (neightbl_fill_parms(skb, &tbl->parms) < 0)
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1807
  		goto nla_put_failure;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1808
1809
  
  	read_unlock_bh(&tbl->lock);
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1810
  	return nlmsg_end(skb, nlh);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1811

ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1812
  nla_put_failure:
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1813
  	read_unlock_bh(&tbl->lock);
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1814
1815
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1816
  }
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1817
1818
  static int neightbl_fill_param_info(struct sk_buff *skb,
  				    struct neigh_table *tbl,
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1819
  				    struct neigh_parms *parms,
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1820
1821
  				    u32 pid, u32 seq, int type,
  				    unsigned int flags)
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1822
1823
1824
  {
  	struct ndtmsg *ndtmsg;
  	struct nlmsghdr *nlh;
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1825
1826
  	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
  	if (nlh == NULL)
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1827
  		return -EMSGSIZE;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1828

ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1829
  	ndtmsg = nlmsg_data(nlh);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1830
1831
1832
  
  	read_lock_bh(&tbl->lock);
  	ndtmsg->ndtm_family = tbl->family;
9ef1d4c7c   Patrick McHardy   [NETLINK]: Missin...
1833
1834
  	ndtmsg->ndtm_pad1   = 0;
  	ndtmsg->ndtm_pad2   = 0;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1835

ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1836
1837
1838
  	if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
  	    neightbl_fill_parms(skb, parms) < 0)
  		goto errout;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1839
1840
  
  	read_unlock_bh(&tbl->lock);
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1841
1842
  	return nlmsg_end(skb, nlh);
  errout:
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1843
  	read_unlock_bh(&tbl->lock);
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1844
1845
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1846
  }
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1847

ef7c79ed6   Patrick McHardy   [NETLINK]: Mark n...
1848
  static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1849
1850
1851
1852
1853
1854
1855
  	[NDTA_NAME]		= { .type = NLA_STRING },
  	[NDTA_THRESH1]		= { .type = NLA_U32 },
  	[NDTA_THRESH2]		= { .type = NLA_U32 },
  	[NDTA_THRESH3]		= { .type = NLA_U32 },
  	[NDTA_GC_INTERVAL]	= { .type = NLA_U64 },
  	[NDTA_PARMS]		= { .type = NLA_NESTED },
  };
ef7c79ed6   Patrick McHardy   [NETLINK]: Mark n...
1856
  static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
  	[NDTPA_IFINDEX]			= { .type = NLA_U32 },
  	[NDTPA_QUEUE_LEN]		= { .type = NLA_U32 },
  	[NDTPA_PROXY_QLEN]		= { .type = NLA_U32 },
  	[NDTPA_APP_PROBES]		= { .type = NLA_U32 },
  	[NDTPA_UCAST_PROBES]		= { .type = NLA_U32 },
  	[NDTPA_MCAST_PROBES]		= { .type = NLA_U32 },
  	[NDTPA_BASE_REACHABLE_TIME]	= { .type = NLA_U64 },
  	[NDTPA_GC_STALETIME]		= { .type = NLA_U64 },
  	[NDTPA_DELAY_PROBE_TIME]	= { .type = NLA_U64 },
  	[NDTPA_RETRANS_TIME]		= { .type = NLA_U64 },
  	[NDTPA_ANYCAST_DELAY]		= { .type = NLA_U64 },
  	[NDTPA_PROXY_DELAY]		= { .type = NLA_U64 },
  	[NDTPA_LOCKTIME]		= { .type = NLA_U64 },
  };
c8822a4e0   Thomas Graf   [NEIGH]: Use rtnl...
1871
  static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1872
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1873
  	struct net *net = sock_net(skb->sk);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1874
  	struct neigh_table *tbl;
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1875
1876
1877
  	struct ndtmsg *ndtmsg;
  	struct nlattr *tb[NDTA_MAX+1];
  	int err;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1878

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1879
1880
1881
1882
  	err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
  			  nl_neightbl_policy);
  	if (err < 0)
  		goto errout;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1883

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1884
1885
1886
1887
1888
1889
  	if (tb[NDTA_NAME] == NULL) {
  		err = -EINVAL;
  		goto errout;
  	}
  
  	ndtmsg = nlmsg_data(nlh);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1890
1891
1892
1893
  	read_lock(&neigh_tbl_lock);
  	for (tbl = neigh_tables; tbl; tbl = tbl->next) {
  		if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
  			continue;
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1894
  		if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0)
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1895
1896
1897
1898
1899
  			break;
  	}
  
  	if (tbl == NULL) {
  		err = -ENOENT;
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1900
  		goto errout_locked;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1901
  	}
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1902
  	/*
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1903
1904
1905
1906
  	 * We acquire tbl->lock to be nice to the periodic timers and
  	 * make sure they always see a consistent set of values.
  	 */
  	write_lock_bh(&tbl->lock);
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1907
1908
  	if (tb[NDTA_PARMS]) {
  		struct nlattr *tbp[NDTPA_MAX+1];
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1909
  		struct neigh_parms *p;
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1910
  		int i, ifindex = 0;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1911

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1912
1913
1914
1915
  		err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
  				       nl_ntbl_parm_policy);
  		if (err < 0)
  			goto errout_tbl_lock;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1916

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1917
1918
  		if (tbp[NDTPA_IFINDEX])
  			ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1919

97fd5bc7f   Tobias Klauser   net: Rename looku...
1920
  		p = lookup_neigh_parms(tbl, net, ifindex);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1921
1922
  		if (p == NULL) {
  			err = -ENOENT;
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1923
  			goto errout_tbl_lock;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1924
  		}
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1925

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1926
1927
1928
  		for (i = 1; i <= NDTPA_MAX; i++) {
  			if (tbp[i] == NULL)
  				continue;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1929

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1930
1931
  			switch (i) {
  			case NDTPA_QUEUE_LEN:
8b5c171bb   Eric Dumazet   neigh: new unreso...
1932
1933
1934
1935
1936
  				p->queue_len_bytes = nla_get_u32(tbp[i]) *
  						     SKB_TRUESIZE(ETH_FRAME_LEN);
  				break;
  			case NDTPA_QUEUE_LENBYTES:
  				p->queue_len_bytes = nla_get_u32(tbp[i]);
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
  				break;
  			case NDTPA_PROXY_QLEN:
  				p->proxy_qlen = nla_get_u32(tbp[i]);
  				break;
  			case NDTPA_APP_PROBES:
  				p->app_probes = nla_get_u32(tbp[i]);
  				break;
  			case NDTPA_UCAST_PROBES:
  				p->ucast_probes = nla_get_u32(tbp[i]);
  				break;
  			case NDTPA_MCAST_PROBES:
  				p->mcast_probes = nla_get_u32(tbp[i]);
  				break;
  			case NDTPA_BASE_REACHABLE_TIME:
  				p->base_reachable_time = nla_get_msecs(tbp[i]);
  				break;
  			case NDTPA_GC_STALETIME:
  				p->gc_staletime = nla_get_msecs(tbp[i]);
  				break;
  			case NDTPA_DELAY_PROBE_TIME:
  				p->delay_probe_time = nla_get_msecs(tbp[i]);
  				break;
  			case NDTPA_RETRANS_TIME:
  				p->retrans_time = nla_get_msecs(tbp[i]);
  				break;
  			case NDTPA_ANYCAST_DELAY:
  				p->anycast_delay = nla_get_msecs(tbp[i]);
  				break;
  			case NDTPA_PROXY_DELAY:
  				p->proxy_delay = nla_get_msecs(tbp[i]);
  				break;
  			case NDTPA_LOCKTIME:
  				p->locktime = nla_get_msecs(tbp[i]);
  				break;
  			}
  		}
  	}
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1974

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1975
1976
  	if (tb[NDTA_THRESH1])
  		tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1977

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1978
1979
  	if (tb[NDTA_THRESH2])
  		tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1980

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1981
1982
  	if (tb[NDTA_THRESH3])
  		tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1983

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1984
1985
  	if (tb[NDTA_GC_INTERVAL])
  		tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1986
1987
  
  	err = 0;
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1988
  errout_tbl_lock:
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1989
  	write_unlock_bh(&tbl->lock);
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1990
  errout_locked:
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1991
  	read_unlock(&neigh_tbl_lock);
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1992
  errout:
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1993
1994
  	return err;
  }
c8822a4e0   Thomas Graf   [NEIGH]: Use rtnl...
1995
  static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1996
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1997
  	struct net *net = sock_net(skb->sk);
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1998
1999
2000
  	int family, tidx, nidx = 0;
  	int tbl_skip = cb->args[0];
  	int neigh_skip = cb->args[1];
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2001
  	struct neigh_table *tbl;
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2002
  	family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2003
2004
  
  	read_lock(&neigh_tbl_lock);
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2005
  	for (tbl = neigh_tables, tidx = 0; tbl; tbl = tbl->next, tidx++) {
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2006
  		struct neigh_parms *p;
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2007
  		if (tidx < tbl_skip || (family && tbl->family != family))
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2008
  			continue;
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2009
2010
2011
  		if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).pid,
  				       cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
  				       NLM_F_MULTI) <= 0)
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2012
  			break;
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
2013
  		for (nidx = 0, p = tbl->parms.next; p; p = p->next) {
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2014
  			if (!net_eq(neigh_parms_net(p), net))
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
2015
  				continue;
efc683fc2   Gautam Kachroo   neigh: some entri...
2016
2017
  			if (nidx < neigh_skip)
  				goto next;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2018

ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2019
2020
2021
2022
2023
  			if (neightbl_fill_param_info(skb, tbl, p,
  						     NETLINK_CB(cb->skb).pid,
  						     cb->nlh->nlmsg_seq,
  						     RTM_NEWNEIGHTBL,
  						     NLM_F_MULTI) <= 0)
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2024
  				goto out;
efc683fc2   Gautam Kachroo   neigh: some entri...
2025
2026
  		next:
  			nidx++;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2027
  		}
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2028
  		neigh_skip = 0;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2029
2030
2031
  	}
  out:
  	read_unlock(&neigh_tbl_lock);
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2032
2033
  	cb->args[0] = tidx;
  	cb->args[1] = nidx;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2034
2035
2036
  
  	return skb->len;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2037

8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2038
2039
  static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
  			   u32 pid, u32 seq, int type, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2040
2041
  {
  	unsigned long now = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2042
  	struct nda_cacheinfo ci;
8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2043
2044
2045
2046
2047
  	struct nlmsghdr *nlh;
  	struct ndmsg *ndm;
  
  	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
  	if (nlh == NULL)
26932566a   Patrick McHardy   [NETLINK]: Don't ...
2048
  		return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2049

8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2050
2051
  	ndm = nlmsg_data(nlh);
  	ndm->ndm_family	 = neigh->ops->family;
9ef1d4c7c   Patrick McHardy   [NETLINK]: Missin...
2052
2053
  	ndm->ndm_pad1    = 0;
  	ndm->ndm_pad2    = 0;
8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2054
2055
2056
  	ndm->ndm_flags	 = neigh->flags;
  	ndm->ndm_type	 = neigh->type;
  	ndm->ndm_ifindex = neigh->dev->ifindex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2057

8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2058
2059
2060
2061
  	NLA_PUT(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key);
  
  	read_lock_bh(&neigh->lock);
  	ndm->ndm_state	 = neigh->nud_state;
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
2062
2063
2064
2065
2066
2067
2068
2069
  	if (neigh->nud_state & NUD_VALID) {
  		char haddr[MAX_ADDR_LEN];
  
  		neigh_ha_snapshot(haddr, neigh, neigh->dev);
  		if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) {
  			read_unlock_bh(&neigh->lock);
  			goto nla_put_failure;
  		}
8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2070
  	}
b9f5f52cc   Stephen Hemminger   net: neighbour ta...
2071
2072
2073
  	ci.ndm_used	 = jiffies_to_clock_t(now - neigh->used);
  	ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
  	ci.ndm_updated	 = jiffies_to_clock_t(now - neigh->updated);
8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2074
2075
2076
2077
2078
2079
2080
2081
2082
  	ci.ndm_refcnt	 = atomic_read(&neigh->refcnt) - 1;
  	read_unlock_bh(&neigh->lock);
  
  	NLA_PUT_U32(skb, NDA_PROBES, atomic_read(&neigh->probes));
  	NLA_PUT(skb, NDA_CACHEINFO, sizeof(ci), &ci);
  
  	return nlmsg_end(skb, nlh);
  
  nla_put_failure:
26932566a   Patrick McHardy   [NETLINK]: Don't ...
2083
2084
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2085
  }
d961db358   Thomas Graf   [NEIGH]: Netlink ...
2086
2087
2088
2089
2090
  static void neigh_update_notify(struct neighbour *neigh)
  {
  	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
  	__neigh_notify(neigh, RTM_NEWNEIGH, 0);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091
2092
2093
2094
  
  static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
  			    struct netlink_callback *cb)
  {
767e97e1e   Eric Dumazet   neigh: RCU conver...
2095
  	struct net *net = sock_net(skb->sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2096
2097
2098
  	struct neighbour *n;
  	int rc, h, s_h = cb->args[1];
  	int idx, s_idx = idx = cb->args[2];
d6bf78171   Eric Dumazet   net neigh: RCU co...
2099
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2100

d6bf78171   Eric Dumazet   net neigh: RCU co...
2101
2102
  	rcu_read_lock_bh();
  	nht = rcu_dereference_bh(tbl->nht);
cd0893369   David S. Miller   neigh: Store hash...
2103
  	for (h = 0; h < (1 << nht->hash_shift); h++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2104
2105
2106
2107
  		if (h < s_h)
  			continue;
  		if (h > s_h)
  			s_idx = 0;
767e97e1e   Eric Dumazet   neigh: RCU conver...
2108
2109
2110
  		for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
  		     n != NULL;
  		     n = rcu_dereference_bh(n->next)) {
09ad9bc75   Octavian Purdila   net: use net_eq t...
2111
  			if (!net_eq(dev_net(n->dev), net))
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
2112
  				continue;
efc683fc2   Gautam Kachroo   neigh: some entri...
2113
2114
  			if (idx < s_idx)
  				goto next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2115
2116
  			if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid,
  					    cb->nlh->nlmsg_seq,
b6544c0b4   Jamal Hadi Salim   [NETLINK]: Correc...
2117
2118
  					    RTM_NEWNEIGH,
  					    NLM_F_MULTI) <= 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2119
2120
2121
  				rc = -1;
  				goto out;
  			}
767e97e1e   Eric Dumazet   neigh: RCU conver...
2122
  next:
efc683fc2   Gautam Kachroo   neigh: some entri...
2123
  			idx++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2124
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2125
2126
2127
  	}
  	rc = skb->len;
  out:
d6bf78171   Eric Dumazet   net neigh: RCU co...
2128
  	rcu_read_unlock_bh();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2129
2130
2131
2132
  	cb->args[1] = h;
  	cb->args[2] = idx;
  	return rc;
  }
c8822a4e0   Thomas Graf   [NEIGH]: Use rtnl...
2133
  static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2134
2135
2136
2137
2138
  {
  	struct neigh_table *tbl;
  	int t, family, s_t;
  
  	read_lock(&neigh_tbl_lock);
8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2139
  	family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
  	s_t = cb->args[0];
  
  	for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) {
  		if (t < s_t || (family && tbl->family != family))
  			continue;
  		if (t > s_t)
  			memset(&cb->args[1], 0, sizeof(cb->args) -
  						sizeof(cb->args[0]));
  		if (neigh_dump_table(tbl, skb, cb) < 0)
  			break;
  	}
  	read_unlock(&neigh_tbl_lock);
  
  	cb->args[0] = t;
  	return skb->len;
  }
  
  void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
  {
  	int chain;
d6bf78171   Eric Dumazet   net neigh: RCU co...
2160
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2161

d6bf78171   Eric Dumazet   net neigh: RCU co...
2162
2163
  	rcu_read_lock_bh();
  	nht = rcu_dereference_bh(tbl->nht);
767e97e1e   Eric Dumazet   neigh: RCU conver...
2164
  	read_lock(&tbl->lock); /* avoid resizes */
cd0893369   David S. Miller   neigh: Store hash...
2165
  	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2166
  		struct neighbour *n;
767e97e1e   Eric Dumazet   neigh: RCU conver...
2167
2168
2169
  		for (n = rcu_dereference_bh(nht->hash_buckets[chain]);
  		     n != NULL;
  		     n = rcu_dereference_bh(n->next))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2170
2171
  			cb(n, cookie);
  	}
d6bf78171   Eric Dumazet   net neigh: RCU co...
2172
2173
  	read_unlock(&tbl->lock);
  	rcu_read_unlock_bh();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2174
2175
2176
2177
2178
2179
2180
2181
  }
  EXPORT_SYMBOL(neigh_for_each);
  
  /* The tbl->lock must be held as a writer and BH disabled. */
  void __neigh_for_each_release(struct neigh_table *tbl,
  			      int (*cb)(struct neighbour *))
  {
  	int chain;
d6bf78171   Eric Dumazet   net neigh: RCU co...
2182
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2183

d6bf78171   Eric Dumazet   net neigh: RCU co...
2184
2185
  	nht = rcu_dereference_protected(tbl->nht,
  					lockdep_is_held(&tbl->lock));
cd0893369   David S. Miller   neigh: Store hash...
2186
  	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
767e97e1e   Eric Dumazet   neigh: RCU conver...
2187
2188
  		struct neighbour *n;
  		struct neighbour __rcu **np;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2189

d6bf78171   Eric Dumazet   net neigh: RCU co...
2190
  		np = &nht->hash_buckets[chain];
767e97e1e   Eric Dumazet   neigh: RCU conver...
2191
2192
  		while ((n = rcu_dereference_protected(*np,
  					lockdep_is_held(&tbl->lock))) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2193
2194
2195
2196
2197
  			int release;
  
  			write_lock(&n->lock);
  			release = cb(n);
  			if (release) {
767e97e1e   Eric Dumazet   neigh: RCU conver...
2198
2199
2200
  				rcu_assign_pointer(*np,
  					rcu_dereference_protected(n->next,
  						lockdep_is_held(&tbl->lock)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2201
2202
2203
2204
  				n->dead = 1;
  			} else
  				np = &n->next;
  			write_unlock(&n->lock);
4f494554f   Thomas Graf   [NEIGH]: Combine ...
2205
2206
  			if (release)
  				neigh_cleanup_and_release(n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
  		}
  	}
  }
  EXPORT_SYMBOL(__neigh_for_each_release);
  
  #ifdef CONFIG_PROC_FS
  
  static struct neighbour *neigh_get_first(struct seq_file *seq)
  {
  	struct neigh_seq_state *state = seq->private;
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2217
  	struct net *net = seq_file_net(seq);
d6bf78171   Eric Dumazet   net neigh: RCU co...
2218
  	struct neigh_hash_table *nht = state->nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2219
2220
2221
2222
  	struct neighbour *n = NULL;
  	int bucket = state->bucket;
  
  	state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
cd0893369   David S. Miller   neigh: Store hash...
2223
  	for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
767e97e1e   Eric Dumazet   neigh: RCU conver...
2224
  		n = rcu_dereference_bh(nht->hash_buckets[bucket]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2225
2226
  
  		while (n) {
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2227
  			if (!net_eq(dev_net(n->dev), net))
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
2228
  				goto next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
  			if (state->neigh_sub_iter) {
  				loff_t fakep = 0;
  				void *v;
  
  				v = state->neigh_sub_iter(state, n, &fakep);
  				if (!v)
  					goto next;
  			}
  			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
  				break;
  			if (n->nud_state & ~NUD_NOARP)
  				break;
767e97e1e   Eric Dumazet   neigh: RCU conver...
2241
2242
  next:
  			n = rcu_dereference_bh(n->next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
  		}
  
  		if (n)
  			break;
  	}
  	state->bucket = bucket;
  
  	return n;
  }
  
  static struct neighbour *neigh_get_next(struct seq_file *seq,
  					struct neighbour *n,
  					loff_t *pos)
  {
  	struct neigh_seq_state *state = seq->private;
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2258
  	struct net *net = seq_file_net(seq);
d6bf78171   Eric Dumazet   net neigh: RCU co...
2259
  	struct neigh_hash_table *nht = state->nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2260
2261
2262
2263
2264
2265
  
  	if (state->neigh_sub_iter) {
  		void *v = state->neigh_sub_iter(state, n, pos);
  		if (v)
  			return n;
  	}
767e97e1e   Eric Dumazet   neigh: RCU conver...
2266
  	n = rcu_dereference_bh(n->next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2267
2268
2269
  
  	while (1) {
  		while (n) {
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2270
  			if (!net_eq(dev_net(n->dev), net))
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
2271
  				goto next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
  			if (state->neigh_sub_iter) {
  				void *v = state->neigh_sub_iter(state, n, pos);
  				if (v)
  					return n;
  				goto next;
  			}
  			if (!(state->flags & NEIGH_SEQ_SKIP_NOARP))
  				break;
  
  			if (n->nud_state & ~NUD_NOARP)
  				break;
767e97e1e   Eric Dumazet   neigh: RCU conver...
2283
2284
  next:
  			n = rcu_dereference_bh(n->next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2285
2286
2287
2288
  		}
  
  		if (n)
  			break;
cd0893369   David S. Miller   neigh: Store hash...
2289
  		if (++state->bucket >= (1 << nht->hash_shift))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2290
  			break;
767e97e1e   Eric Dumazet   neigh: RCU conver...
2291
  		n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
  	}
  
  	if (n && pos)
  		--(*pos);
  	return n;
  }
  
  static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
  {
  	struct neighbour *n = neigh_get_first(seq);
  
  	if (n) {
745e20316   Chris Larson   net: fix missing ...
2304
  		--(*pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
  		while (*pos) {
  			n = neigh_get_next(seq, n, pos);
  			if (!n)
  				break;
  		}
  	}
  	return *pos ? NULL : n;
  }
  
  static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
  {
  	struct neigh_seq_state *state = seq->private;
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2317
  	struct net *net = seq_file_net(seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2318
2319
2320
2321
2322
2323
2324
  	struct neigh_table *tbl = state->tbl;
  	struct pneigh_entry *pn = NULL;
  	int bucket = state->bucket;
  
  	state->flags |= NEIGH_SEQ_IS_PNEIGH;
  	for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
  		pn = tbl->phash_buckets[bucket];
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2325
  		while (pn && !net_eq(pneigh_net(pn), net))
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
2326
  			pn = pn->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
  		if (pn)
  			break;
  	}
  	state->bucket = bucket;
  
  	return pn;
  }
  
  static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
  					    struct pneigh_entry *pn,
  					    loff_t *pos)
  {
  	struct neigh_seq_state *state = seq->private;
1218854af   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2340
  	struct net *net = seq_file_net(seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2341
  	struct neigh_table *tbl = state->tbl;
df07a94cf   Jorge Boncompte [DTI2]   netns: fix proxy ...
2342
2343
2344
  	do {
  		pn = pn->next;
  	} while (pn && !net_eq(pneigh_net(pn), net));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2345
2346
2347
2348
  	while (!pn) {
  		if (++state->bucket > PNEIGH_HASHMASK)
  			break;
  		pn = tbl->phash_buckets[state->bucket];
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2349
  		while (pn && !net_eq(pneigh_net(pn), net))
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
2350
  			pn = pn->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
  		if (pn)
  			break;
  	}
  
  	if (pn && pos)
  		--(*pos);
  
  	return pn;
  }
  
  static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos)
  {
  	struct pneigh_entry *pn = pneigh_get_first(seq);
  
  	if (pn) {
745e20316   Chris Larson   net: fix missing ...
2366
  		--(*pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
  		while (*pos) {
  			pn = pneigh_get_next(seq, pn, pos);
  			if (!pn)
  				break;
  		}
  	}
  	return *pos ? NULL : pn;
  }
  
  static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos)
  {
  	struct neigh_seq_state *state = seq->private;
  	void *rc;
745e20316   Chris Larson   net: fix missing ...
2380
  	loff_t idxpos = *pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2381

745e20316   Chris Larson   net: fix missing ...
2382
  	rc = neigh_get_idx(seq, &idxpos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2383
  	if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
745e20316   Chris Larson   net: fix missing ...
2384
  		rc = pneigh_get_idx(seq, &idxpos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2385
2386
2387
2388
2389
  
  	return rc;
  }
  
  void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags)
d6bf78171   Eric Dumazet   net neigh: RCU co...
2390
  	__acquires(rcu_bh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2391
2392
  {
  	struct neigh_seq_state *state = seq->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2393
2394
2395
2396
  
  	state->tbl = tbl;
  	state->bucket = 0;
  	state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
d6bf78171   Eric Dumazet   net neigh: RCU co...
2397
2398
  	rcu_read_lock_bh();
  	state->nht = rcu_dereference_bh(tbl->nht);
767e97e1e   Eric Dumazet   neigh: RCU conver...
2399

745e20316   Chris Larson   net: fix missing ...
2400
  	return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2401
2402
2403
2404
2405
2406
2407
2408
2409
  }
  EXPORT_SYMBOL(neigh_seq_start);
  
  void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
  	struct neigh_seq_state *state;
  	void *rc;
  
  	if (v == SEQ_START_TOKEN) {
bff69732c   Chris Larson   net: in the first...
2410
  		rc = neigh_get_first(seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
  		goto out;
  	}
  
  	state = seq->private;
  	if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) {
  		rc = neigh_get_next(seq, v, NULL);
  		if (rc)
  			goto out;
  		if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY))
  			rc = pneigh_get_first(seq);
  	} else {
  		BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY);
  		rc = pneigh_get_next(seq, v, NULL);
  	}
  out:
  	++(*pos);
  	return rc;
  }
  EXPORT_SYMBOL(neigh_seq_next);
  
  void neigh_seq_stop(struct seq_file *seq, void *v)
d6bf78171   Eric Dumazet   net neigh: RCU co...
2432
  	__releases(rcu_bh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2433
  {
d6bf78171   Eric Dumazet   net neigh: RCU co...
2434
  	rcu_read_unlock_bh();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2435
2436
2437
2438
2439
2440
2441
  }
  EXPORT_SYMBOL(neigh_seq_stop);
  
  /* statistics via seq_file */
  
  static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
  {
81c1ebfc4   Alexey Dobriyan   neigh: simplify s...
2442
  	struct neigh_table *tbl = seq->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2443
2444
2445
2446
  	int cpu;
  
  	if (*pos == 0)
  		return SEQ_START_TOKEN;
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
2447

0f23174aa   Rusty Russell   cpumask: prepare ...
2448
  	for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
  		if (!cpu_possible(cpu))
  			continue;
  		*pos = cpu+1;
  		return per_cpu_ptr(tbl->stats, cpu);
  	}
  	return NULL;
  }
  
  static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  {
81c1ebfc4   Alexey Dobriyan   neigh: simplify s...
2459
  	struct neigh_table *tbl = seq->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2460
  	int cpu;
0f23174aa   Rusty Russell   cpumask: prepare ...
2461
  	for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
  		if (!cpu_possible(cpu))
  			continue;
  		*pos = cpu+1;
  		return per_cpu_ptr(tbl->stats, cpu);
  	}
  	return NULL;
  }
  
  static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
  {
  
  }
  
  static int neigh_stat_seq_show(struct seq_file *seq, void *v)
  {
81c1ebfc4   Alexey Dobriyan   neigh: simplify s...
2477
  	struct neigh_table *tbl = seq->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2478
2479
2480
  	struct neigh_statistics *st = v;
  
  	if (v == SEQ_START_TOKEN) {
9a6d276e8   Neil Horman   core: add stat to...
2481
2482
  		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
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2483
2484
2485
2486
  		return 0;
  	}
  
  	seq_printf(seq, "%08x  %08lx %08lx %08lx  %08lx %08lx  %08lx  "
9a6d276e8   Neil Horman   core: add stat to...
2487
2488
  			"%08lx %08lx  %08lx %08lx %08lx
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
  		   atomic_read(&tbl->entries),
  
  		   st->allocs,
  		   st->destroys,
  		   st->hash_grows,
  
  		   st->lookups,
  		   st->hits,
  
  		   st->res_failed,
  
  		   st->rcv_probes_mcast,
  		   st->rcv_probes_ucast,
  
  		   st->periodic_gc_runs,
9a6d276e8   Neil Horman   core: add stat to...
2504
2505
  		   st->forced_gc_runs,
  		   st->unres_discards
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2506
2507
2508
2509
  		   );
  
  	return 0;
  }
f690808e1   Stephen Hemminger   [NET]: make seq_o...
2510
  static const struct seq_operations neigh_stat_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
  	.start	= neigh_stat_seq_start,
  	.next	= neigh_stat_seq_next,
  	.stop	= neigh_stat_seq_stop,
  	.show	= neigh_stat_seq_show,
  };
  
  static int neigh_stat_seq_open(struct inode *inode, struct file *file)
  {
  	int ret = seq_open(file, &neigh_stat_seq_ops);
  
  	if (!ret) {
  		struct seq_file *sf = file->private_data;
81c1ebfc4   Alexey Dobriyan   neigh: simplify s...
2523
  		sf->private = PDE(inode)->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2524
2525
2526
  	}
  	return ret;
  };
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
2527
  static const struct file_operations neigh_stat_seq_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2528
2529
2530
2531
2532
2533
2534
2535
  	.owner	 = THIS_MODULE,
  	.open 	 = neigh_stat_seq_open,
  	.read	 = seq_read,
  	.llseek	 = seq_lseek,
  	.release = seq_release,
  };
  
  #endif /* CONFIG_PROC_FS */
339bf98ff   Thomas Graf   [NETLINK]: Do pre...
2536
2537
2538
2539
2540
2541
2542
2543
  static inline size_t neigh_nlmsg_size(void)
  {
  	return NLMSG_ALIGN(sizeof(struct ndmsg))
  	       + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
  	       + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
  	       + nla_total_size(sizeof(struct nda_cacheinfo))
  	       + nla_total_size(4); /* NDA_PROBES */
  }
b86733118   Thomas Graf   [NEIGH]: Convert ...
2544
  static void __neigh_notify(struct neighbour *n, int type, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2545
  {
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2546
  	struct net *net = dev_net(n->dev);
8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2547
  	struct sk_buff *skb;
b86733118   Thomas Graf   [NEIGH]: Convert ...
2548
  	int err = -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2549

339bf98ff   Thomas Graf   [NETLINK]: Do pre...
2550
  	skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC);
8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2551
  	if (skb == NULL)
b86733118   Thomas Graf   [NEIGH]: Convert ...
2552
  		goto errout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2553

b86733118   Thomas Graf   [NEIGH]: Convert ...
2554
  	err = neigh_fill_info(skb, n, 0, 0, type, flags);
26932566a   Patrick McHardy   [NETLINK]: Don't ...
2555
2556
2557
2558
2559
2560
  	if (err < 0) {
  		/* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
  		WARN_ON(err == -EMSGSIZE);
  		kfree_skb(skb);
  		goto errout;
  	}
1ce85fe40   Pablo Neira Ayuso   netlink: change n...
2561
2562
  	rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
  	return;
b86733118   Thomas Graf   [NEIGH]: Convert ...
2563
2564
  errout:
  	if (err < 0)
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
2565
  		rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2566
  }
d961db358   Thomas Graf   [NEIGH]: Netlink ...
2567
  #ifdef CONFIG_ARPD
b86733118   Thomas Graf   [NEIGH]: Convert ...
2568
  void neigh_app_ns(struct neighbour *n)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2569
  {
b86733118   Thomas Graf   [NEIGH]: Convert ...
2570
2571
  	__neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
2572
  EXPORT_SYMBOL(neigh_app_ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2573
2574
2575
  #endif /* CONFIG_ARPD */
  
  #ifdef CONFIG_SYSCTL
8b5c171bb   Eric Dumazet   neigh: new unreso...
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
  static int proc_unres_qlen(ctl_table *ctl, int write, void __user *buffer,
  			   size_t *lenp, loff_t *ppos)
  {
  	int size, ret;
  	ctl_table tmp = *ctl;
  
  	tmp.data = &size;
  	size = DIV_ROUND_UP(*(int *)ctl->data, SKB_TRUESIZE(ETH_FRAME_LEN));
  	ret = proc_dointvec(&tmp, write, buffer, lenp, ppos);
  	if (write && !ret)
  		*(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
  	return ret;
  }
  
  enum {
  	NEIGH_VAR_MCAST_PROBE,
  	NEIGH_VAR_UCAST_PROBE,
  	NEIGH_VAR_APP_PROBE,
  	NEIGH_VAR_RETRANS_TIME,
  	NEIGH_VAR_BASE_REACHABLE_TIME,
  	NEIGH_VAR_DELAY_PROBE_TIME,
  	NEIGH_VAR_GC_STALETIME,
  	NEIGH_VAR_QUEUE_LEN,
  	NEIGH_VAR_QUEUE_LEN_BYTES,
  	NEIGH_VAR_PROXY_QLEN,
  	NEIGH_VAR_ANYCAST_DELAY,
  	NEIGH_VAR_PROXY_DELAY,
  	NEIGH_VAR_LOCKTIME,
  	NEIGH_VAR_RETRANS_TIME_MS,
  	NEIGH_VAR_BASE_REACHABLE_TIME_MS,
  	NEIGH_VAR_GC_INTERVAL,
  	NEIGH_VAR_GC_THRESH1,
  	NEIGH_VAR_GC_THRESH2,
  	NEIGH_VAR_GC_THRESH3,
  	NEIGH_VAR_MAX
  };
54716e3be   Eric W. Biederman   net neigh: Decoup...
2612

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2613
2614
  static struct neigh_sysctl_table {
  	struct ctl_table_header *sysctl_header;
8b5c171bb   Eric Dumazet   neigh: new unreso...
2615
  	struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
c3bac5a71   Pavel Emelyanov   [NEIGH]: Use the ...
2616
  	char *dev_name;
ab32ea5d8   Brian Haley   [NET/IPV4/IPV6]: ...
2617
  } neigh_sysctl_template __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2618
  	.neigh_vars = {
8b5c171bb   Eric Dumazet   neigh: new unreso...
2619
  		[NEIGH_VAR_MCAST_PROBE] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2620
2621
2622
  			.procname	= "mcast_solicit",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2623
  			.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2624
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2625
  		[NEIGH_VAR_UCAST_PROBE] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2626
2627
2628
  			.procname	= "ucast_solicit",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2629
  			.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2630
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2631
  		[NEIGH_VAR_APP_PROBE] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2632
2633
2634
  			.procname	= "app_solicit",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2635
  			.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2636
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2637
  		[NEIGH_VAR_RETRANS_TIME] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2638
2639
2640
  			.procname	= "retrans_time",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2641
  			.proc_handler	= proc_dointvec_userhz_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2642
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2643
  		[NEIGH_VAR_BASE_REACHABLE_TIME] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2644
2645
2646
  			.procname	= "base_reachable_time",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2647
  			.proc_handler	= proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2648
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2649
  		[NEIGH_VAR_DELAY_PROBE_TIME] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2650
2651
2652
  			.procname	= "delay_first_probe_time",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2653
  			.proc_handler	= proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2654
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2655
  		[NEIGH_VAR_GC_STALETIME] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2656
2657
2658
  			.procname	= "gc_stale_time",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2659
  			.proc_handler	= proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2660
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2661
  		[NEIGH_VAR_QUEUE_LEN] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2662
2663
2664
  			.procname	= "unres_qlen",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
8b5c171bb   Eric Dumazet   neigh: new unreso...
2665
2666
2667
2668
2669
2670
  			.proc_handler	= proc_unres_qlen,
  		},
  		[NEIGH_VAR_QUEUE_LEN_BYTES] = {
  			.procname	= "unres_qlen_bytes",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2671
  			.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2672
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2673
  		[NEIGH_VAR_PROXY_QLEN] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2674
2675
2676
  			.procname	= "proxy_qlen",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2677
  			.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2678
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2679
  		[NEIGH_VAR_ANYCAST_DELAY] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2680
2681
2682
  			.procname	= "anycast_delay",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2683
  			.proc_handler	= proc_dointvec_userhz_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2684
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2685
  		[NEIGH_VAR_PROXY_DELAY] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2686
2687
2688
  			.procname	= "proxy_delay",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2689
  			.proc_handler	= proc_dointvec_userhz_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2690
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2691
  		[NEIGH_VAR_LOCKTIME] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2692
2693
2694
  			.procname	= "locktime",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2695
  			.proc_handler	= proc_dointvec_userhz_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2696
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2697
  		[NEIGH_VAR_RETRANS_TIME_MS] = {
d12af679b   Eric W. Biederman   sysctl: fix neigh...
2698
2699
2700
  			.procname	= "retrans_time_ms",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2701
  			.proc_handler	= proc_dointvec_ms_jiffies,
d12af679b   Eric W. Biederman   sysctl: fix neigh...
2702
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2703
  		[NEIGH_VAR_BASE_REACHABLE_TIME_MS] = {
d12af679b   Eric W. Biederman   sysctl: fix neigh...
2704
2705
2706
  			.procname	= "base_reachable_time_ms",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2707
  			.proc_handler	= proc_dointvec_ms_jiffies,
d12af679b   Eric W. Biederman   sysctl: fix neigh...
2708
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2709
  		[NEIGH_VAR_GC_INTERVAL] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2710
2711
2712
  			.procname	= "gc_interval",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2713
  			.proc_handler	= proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2714
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2715
  		[NEIGH_VAR_GC_THRESH1] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2716
2717
2718
  			.procname	= "gc_thresh1",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2719
  			.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2720
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2721
  		[NEIGH_VAR_GC_THRESH2] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2722
2723
2724
  			.procname	= "gc_thresh2",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2725
  			.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2726
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
2727
  		[NEIGH_VAR_GC_THRESH3] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2728
2729
2730
  			.procname	= "gc_thresh3",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
2731
  			.proc_handler	= proc_dointvec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2732
  		},
c3bac5a71   Pavel Emelyanov   [NEIGH]: Use the ...
2733
  		{},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2734
2735
2736
2737
  	},
  };
  
  int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
54716e3be   Eric W. Biederman   net neigh: Decoup...
2738
  			  char *p_name, proc_handler *handler)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2739
  {
3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
2740
  	struct neigh_sysctl_table *t;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2741
  	const char *dev_name_source = NULL;
c3bac5a71   Pavel Emelyanov   [NEIGH]: Use the ...
2742
2743
2744
2745
2746
2747
2748
  
  #define NEIGH_CTL_PATH_ROOT	0
  #define NEIGH_CTL_PATH_PROTO	1
  #define NEIGH_CTL_PATH_NEIGH	2
  #define NEIGH_CTL_PATH_DEV	3
  
  	struct ctl_path neigh_path[] = {
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2749
2750
2751
2752
  		{ .procname = "net",	 },
  		{ .procname = "proto",	 },
  		{ .procname = "neigh",	 },
  		{ .procname = "default", },
c3bac5a71   Pavel Emelyanov   [NEIGH]: Use the ...
2753
2754
  		{ },
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2755

3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
2756
  	t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2757
  	if (!t)
3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
2758
  		goto err;
8b5c171bb   Eric Dumazet   neigh: new unreso...
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
  	t->neigh_vars[NEIGH_VAR_MCAST_PROBE].data  = &p->mcast_probes;
  	t->neigh_vars[NEIGH_VAR_UCAST_PROBE].data  = &p->ucast_probes;
  	t->neigh_vars[NEIGH_VAR_APP_PROBE].data  = &p->app_probes;
  	t->neigh_vars[NEIGH_VAR_RETRANS_TIME].data  = &p->retrans_time;
  	t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].data  = &p->base_reachable_time;
  	t->neigh_vars[NEIGH_VAR_DELAY_PROBE_TIME].data  = &p->delay_probe_time;
  	t->neigh_vars[NEIGH_VAR_GC_STALETIME].data  = &p->gc_staletime;
  	t->neigh_vars[NEIGH_VAR_QUEUE_LEN].data  = &p->queue_len_bytes;
  	t->neigh_vars[NEIGH_VAR_QUEUE_LEN_BYTES].data  = &p->queue_len_bytes;
  	t->neigh_vars[NEIGH_VAR_PROXY_QLEN].data  = &p->proxy_qlen;
  	t->neigh_vars[NEIGH_VAR_ANYCAST_DELAY].data  = &p->anycast_delay;
  	t->neigh_vars[NEIGH_VAR_PROXY_DELAY].data = &p->proxy_delay;
  	t->neigh_vars[NEIGH_VAR_LOCKTIME].data = &p->locktime;
  	t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].data  = &p->retrans_time;
  	t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].data  = &p->base_reachable_time;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2774
2775
2776
  
  	if (dev) {
  		dev_name_source = dev->name;
d12af679b   Eric W. Biederman   sysctl: fix neigh...
2777
  		/* Terminate the table early */
8b5c171bb   Eric Dumazet   neigh: new unreso...
2778
2779
  		memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0,
  		       sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2780
  	} else {
c3bac5a71   Pavel Emelyanov   [NEIGH]: Use the ...
2781
  		dev_name_source = neigh_path[NEIGH_CTL_PATH_DEV].procname;
8b5c171bb   Eric Dumazet   neigh: new unreso...
2782
2783
2784
2785
  		t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = (int *)(p + 1);
  		t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = (int *)(p + 1) + 1;
  		t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = (int *)(p + 1) + 2;
  		t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = (int *)(p + 1) + 3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2786
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2787

f8572d8f2   Eric W. Biederman   sysctl net: Remov...
2788
  	if (handler) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2789
  		/* RetransTime */
8b5c171bb   Eric Dumazet   neigh: new unreso...
2790
2791
  		t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
  		t->neigh_vars[NEIGH_VAR_RETRANS_TIME].extra1 = dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2792
  		/* ReachableTime */
8b5c171bb   Eric Dumazet   neigh: new unreso...
2793
2794
  		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
  		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].extra1 = dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2795
  		/* RetransTime (in milliseconds)*/
8b5c171bb   Eric Dumazet   neigh: new unreso...
2796
2797
  		t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
  		t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].extra1 = dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2798
  		/* ReachableTime (in milliseconds) */
8b5c171bb   Eric Dumazet   neigh: new unreso...
2799
2800
  		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
  		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].extra1 = dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2801
  	}
c3bac5a71   Pavel Emelyanov   [NEIGH]: Use the ...
2802
2803
  	t->dev_name = kstrdup(dev_name_source, GFP_KERNEL);
  	if (!t->dev_name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2804
  		goto free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2805

c3bac5a71   Pavel Emelyanov   [NEIGH]: Use the ...
2806
  	neigh_path[NEIGH_CTL_PATH_DEV].procname = t->dev_name;
c3bac5a71   Pavel Emelyanov   [NEIGH]: Use the ...
2807
  	neigh_path[NEIGH_CTL_PATH_PROTO].procname = p_name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2808

4ab438fcd   Denis V. Lunev   [NETNS]: Register...
2809
  	t->sysctl_header =
57da52c1e   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2810
  		register_net_sysctl_table(neigh_parms_net(p), neigh_path, t->neigh_vars);
3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
2811
  	if (!t->sysctl_header)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2812
  		goto free_procname;
3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
2813

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2814
2815
  	p->sysctl_table = t;
  	return 0;
3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
2816
  free_procname:
c3bac5a71   Pavel Emelyanov   [NEIGH]: Use the ...
2817
  	kfree(t->dev_name);
3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
2818
  free:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2819
  	kfree(t);
3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
2820
2821
  err:
  	return -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2822
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
2823
  EXPORT_SYMBOL(neigh_sysctl_register);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2824
2825
2826
2827
2828
2829
2830
  
  void neigh_sysctl_unregister(struct neigh_parms *p)
  {
  	if (p->sysctl_table) {
  		struct neigh_sysctl_table *t = p->sysctl_table;
  		p->sysctl_table = NULL;
  		unregister_sysctl_table(t->sysctl_header);
c3bac5a71   Pavel Emelyanov   [NEIGH]: Use the ...
2831
  		kfree(t->dev_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2832
2833
2834
  		kfree(t);
  	}
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
2835
  EXPORT_SYMBOL(neigh_sysctl_unregister);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2836
2837
  
  #endif	/* CONFIG_SYSCTL */
c8822a4e0   Thomas Graf   [NEIGH]: Use rtnl...
2838
2839
  static int __init neigh_init(void)
  {
c7ac8679b   Greg Rose   rtnetlink: Comput...
2840
2841
2842
  	rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, NULL);
  	rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, NULL);
  	rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, NULL);
c8822a4e0   Thomas Graf   [NEIGH]: Use rtnl...
2843

c7ac8679b   Greg Rose   rtnetlink: Comput...
2844
2845
2846
  	rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
  		      NULL);
  	rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, NULL);
c8822a4e0   Thomas Graf   [NEIGH]: Use rtnl...
2847
2848
2849
2850
2851
  
  	return 0;
  }
  
  subsys_initcall(neigh_init);