Blame view

net/core/neighbour.c 80.5 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
   */
e005d193d   Joe Perches   net: core: Use pr...
17
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5a0e3ad6a   Tejun Heo   include cleanup: ...
18
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/socket.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
  #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...
29
  #include <net/net_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
  #include <net/neighbour.h>
  #include <net/dst.h>
  #include <net/sock.h>
8d71740c5   Tom Tucker   [NET]: Core net c...
33
  #include <net/netevent.h>
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
34
  #include <net/netlink.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  #include <linux/rtnetlink.h>
  #include <linux/random.h>
543537bd9   Paulo Marques   [PATCH] create a ...
37
  #include <linux/string.h>
c3609d510   vignesh babu   [NET]: is_power_o...
38
  #include <linux/log2.h>
1d4c8c298   Jiri Pirko   neigh: restore ol...
39
  #include <linux/inetdevice.h>
bba24896f   Jiri Pirko   neigh: ipv6: resp...
40
  #include <net/addrconf.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41

d5d427cda   Joe Perches   neighbour: Conver...
42
  #define DEBUG
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
  #define NEIGH_DEBUG 1
d5d427cda   Joe Perches   neighbour: Conver...
44
45
46
47
48
  #define neigh_dbg(level, fmt, ...)		\
  do {						\
  	if (level <= NEIGH_DEBUG)		\
  		pr_debug(fmt, ##__VA_ARGS__);	\
  } while (0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
  
  #define PNEIGH_HASHMASK		0xF
  
  static void neigh_timer_handler(unsigned long arg);
7b8f7a402   Roopa Prabhu   neighbour: fix nl...
53
54
55
  static void __neigh_notify(struct neighbour *n, int type, int flags,
  			   u32 pid);
  static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid);
012e5e5b6   Wolfgang Bumiller   net: fix deadlock...
56
57
  static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
  				    struct net_device *dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58

45fc3b11f   Amos Waterland   [NET]: Protect ne...
59
  #ifdef CONFIG_PROC_FS
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
60
  static const struct file_operations neigh_stat_seq_fops;
45fc3b11f   Amos Waterland   [NET]: Protect ne...
61
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  
  /*
     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.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
   */
8f40b161d   David S. Miller   neigh: Pass neigh...
90
  static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
94
  {
  	kfree_skb(skb);
  	return -ENETDOWN;
  }
4f494554f   Thomas Graf   [NEIGH]: Combine ...
95
96
97
98
  static void neigh_cleanup_and_release(struct neighbour *neigh)
  {
  	if (neigh->parms->neigh_cleanup)
  		neigh->parms->neigh_cleanup(neigh);
7b8f7a402   Roopa Prabhu   neighbour: fix nl...
99
  	__neigh_notify(neigh, RTM_DELNEIGH, 0, 0);
53f800e3b   Ido Schimmel   neigh: Send netev...
100
  	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
4f494554f   Thomas Graf   [NEIGH]: Combine ...
101
102
  	neigh_release(neigh);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
106
107
108
109
110
  /*
   * 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)
  {
63862b5be   Aruna-Hewapathirane   net: replace macr...
111
  	return base ? (prandom_u32() % base) + (base >> 1) : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
113
  EXPORT_SYMBOL(neigh_rand_reach_time);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114

5071034e4   Sowmini Varadhan   neigh: Really del...
115
116
117
118
119
120
  static bool neigh_del(struct neighbour *n, __u8 state,
  		      struct neighbour __rcu **np, struct neigh_table *tbl)
  {
  	bool retval = false;
  
  	write_lock(&n->lock);
9f2374301   Reshetova, Elena   net: convert neig...
121
  	if (refcount_read(&n->refcnt) == 1 && !(n->nud_state & state)) {
5071034e4   Sowmini Varadhan   neigh: Really del...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  		struct neighbour *neigh;
  
  		neigh = rcu_dereference_protected(n->next,
  						  lockdep_is_held(&tbl->lock));
  		rcu_assign_pointer(*np, neigh);
  		n->dead = 1;
  		retval = true;
  	}
  	write_unlock(&n->lock);
  	if (retval)
  		neigh_cleanup_and_release(n);
  	return retval;
  }
  
  bool neigh_remove_one(struct neighbour *ndel, struct neigh_table *tbl)
  {
  	struct neigh_hash_table *nht;
  	void *pkey = ndel->primary_key;
  	u32 hash_val;
  	struct neighbour *n;
  	struct neighbour __rcu **np;
  
  	nht = rcu_dereference_protected(tbl->nht,
  					lockdep_is_held(&tbl->lock));
  	hash_val = tbl->hash(pkey, ndel->dev, nht->hash_rnd);
  	hash_val = hash_val >> (32 - nht->hash_shift);
  
  	np = &nht->hash_buckets[hash_val];
  	while ((n = rcu_dereference_protected(*np,
  					      lockdep_is_held(&tbl->lock)))) {
  		if (n == ndel)
  			return neigh_del(n, 0, np, tbl);
  		np = &n->next;
  	}
  	return false;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
160
161
  static int neigh_forced_gc(struct neigh_table *tbl)
  {
  	int shrunk = 0;
  	int i;
d6bf78171   Eric Dumazet   net neigh: RCU co...
162
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
  
  	NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
  
  	write_lock_bh(&tbl->lock);
d6bf78171   Eric Dumazet   net neigh: RCU co...
167
168
  	nht = rcu_dereference_protected(tbl->nht,
  					lockdep_is_held(&tbl->lock));
cd0893369   David S. Miller   neigh: Store hash...
169
  	for (i = 0; i < (1 << nht->hash_shift); i++) {
767e97e1e   Eric Dumazet   neigh: RCU conver...
170
171
  		struct neighbour *n;
  		struct neighbour __rcu **np;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172

d6bf78171   Eric Dumazet   net neigh: RCU co...
173
  		np = &nht->hash_buckets[i];
767e97e1e   Eric Dumazet   neigh: RCU conver...
174
175
  		while ((n = rcu_dereference_protected(*np,
  					lockdep_is_held(&tbl->lock))) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
179
  			/* Neighbour record may be discarded if:
  			 * - nobody refers to it.
  			 * - it is not permanent
  			 */
5071034e4   Sowmini Varadhan   neigh: Really del...
180
181
  			if (neigh_del(n, NUD_PERMANENT, np, tbl)) {
  				shrunk = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
  				continue;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
190
191
192
193
  			np = &n->next;
  		}
  	}
  
  	tbl->last_flush = jiffies;
  
  	write_unlock_bh(&tbl->lock);
  
  	return shrunk;
  }
a43d8994b   Pavel Emelyanov   [NEIGH]: Make nei...
194
195
196
197
198
199
200
201
202
203
  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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  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...
223
  static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
  {
  	int i;
d6bf78171   Eric Dumazet   net neigh: RCU co...
226
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227

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

767e97e1e   Eric Dumazet   neigh: RCU conver...
234
235
  		while ((n = rcu_dereference_protected(*np,
  					lockdep_is_held(&tbl->lock))) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
238
239
  			if (dev && n->dev != dev) {
  				np = &n->next;
  				continue;
  			}
767e97e1e   Eric Dumazet   neigh: RCU conver...
240
241
242
  			rcu_assign_pointer(*np,
  				   rcu_dereference_protected(n->next,
  						lockdep_is_held(&tbl->lock)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
  			write_lock(&n->lock);
  			neigh_del_timer(n);
  			n->dead = 1;
9f2374301   Reshetova, Elena   net: convert neig...
246
  			if (refcount_read(&n->refcnt) != 1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
250
251
252
253
254
255
  				/* 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.
  				 */
c9ab4d85d   Eric Dumazet   neighbour: fix a ...
256
  				__skb_queue_purge(&n->arp_queue);
8b5c171bb   Eric Dumazet   neigh: new unreso...
257
  				n->arp_queue_len_bytes = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
260
261
262
  				n->output = neigh_blackhole;
  				if (n->nud_state & NUD_VALID)
  					n->nud_state = NUD_NOARP;
  				else
  					n->nud_state = NUD_NONE;
d5d427cda   Joe Perches   neighbour: Conver...
263
264
  				neigh_dbg(2, "neigh %p is stray
  ", n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
  			}
  			write_unlock(&n->lock);
4f494554f   Thomas Graf   [NEIGH]: Combine ...
267
  			neigh_cleanup_and_release(n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
  		}
  	}
49636bb12   Herbert Xu   [NEIGH] Fix timer...
270
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271

49636bb12   Herbert Xu   [NEIGH] Fix timer...
272
273
274
275
276
277
  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: ...
278
  EXPORT_SYMBOL(neigh_changeaddr);
49636bb12   Herbert Xu   [NEIGH] Fix timer...
279
280
281
282
283
  
  int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
  {
  	write_lock_bh(&tbl->lock);
  	neigh_flush_dev(tbl, dev);
012e5e5b6   Wolfgang Bumiller   net: fix deadlock...
284
  	pneigh_ifdown_and_unlock(tbl, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
288
289
  
  	del_timer_sync(&tbl->proxy_timer);
  	pneigh_queue_purge(&tbl->proxy_queue);
  	return 0;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
290
  EXPORT_SYMBOL(neigh_ifdown);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291

596b9b68e   David Miller   neigh: Add infras...
292
  static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
295
296
297
298
299
300
301
302
  {
  	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) &&
fb811395c   Rick Jones   net: add explicit...
303
304
305
306
307
  		    entries >= tbl->gc_thresh3) {
  			net_info_ratelimited("%s: neighbor table overflow!
  ",
  					     tbl->id);
  			NEIGH_CACHE_STAT_INC(tbl, table_fulls);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  			goto out_entries;
fb811395c   Rick Jones   net: add explicit...
309
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
  	}
08433eff2   YOSHIFUJI Hideaki / 吉藤英明   net neigh: Optimi...
311
  	n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
  	if (!n)
  		goto out_entries;
c9ab4d85d   Eric Dumazet   neighbour: fix a ...
314
  	__skb_queue_head_init(&n->arp_queue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
  	rwlock_init(&n->lock);
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
316
  	seqlock_init(&n->ha_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
319
  	n->updated	  = n->used = now;
  	n->nud_state	  = NUD_NONE;
  	n->output	  = neigh_blackhole;
f6b72b621   David S. Miller   net: Embed hh_cac...
320
  	seqlock_init(&n->hh.hh_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
  	n->parms	  = neigh_parms_clone(&tbl->parms);
b24b8a247   Pavel Emelyanov   [NET]: Convert in...
322
  	setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
  
  	NEIGH_CACHE_STAT_INC(tbl, allocs);
  	n->tbl		  = tbl;
9f2374301   Reshetova, Elena   net: convert neig...
326
  	refcount_set(&n->refcnt, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
330
331
332
333
334
  	n->dead		  = 1;
  out:
  	return n;
  
  out_entries:
  	atomic_dec(&tbl->entries);
  	goto out;
  }
2c2aba6c5   David S. Miller   ipv6: Use univers...
335
336
  static void neigh_get_hash_rnd(u32 *x)
  {
b3d0f7895   Jason A. Donenfeld   net/neighbor: use...
337
  	*x = get_random_u32() | 1;
2c2aba6c5   David S. Miller   ipv6: Use univers...
338
  }
cd0893369   David S. Miller   neigh: Store hash...
339
  static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  {
cd0893369   David S. Miller   neigh: Store hash...
341
  	size_t size = (1 << shift) * sizeof(struct neighbour *);
d6bf78171   Eric Dumazet   net neigh: RCU co...
342
  	struct neigh_hash_table *ret;
6193d2be2   Eric Dumazet   neigh: __rcu anno...
343
  	struct neighbour __rcu **buckets;
2c2aba6c5   David S. Miller   ipv6: Use univers...
344
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345

d6bf78171   Eric Dumazet   net neigh: RCU co...
346
347
348
349
350
351
  	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...
352
  		buckets = (struct neighbour __rcu **)
d6bf78171   Eric Dumazet   net neigh: RCU co...
353
354
355
356
357
  			  __get_free_pages(GFP_ATOMIC | __GFP_ZERO,
  					   get_order(size));
  	if (!buckets) {
  		kfree(ret);
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  	}
6193d2be2   Eric Dumazet   neigh: __rcu anno...
359
  	ret->hash_buckets = buckets;
cd0893369   David S. Miller   neigh: Store hash...
360
  	ret->hash_shift = shift;
2c2aba6c5   David S. Miller   ipv6: Use univers...
361
362
  	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
363
364
  	return ret;
  }
d6bf78171   Eric Dumazet   net neigh: RCU co...
365
  static void neigh_hash_free_rcu(struct rcu_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  {
d6bf78171   Eric Dumazet   net neigh: RCU co...
367
368
369
  	struct neigh_hash_table *nht = container_of(head,
  						    struct neigh_hash_table,
  						    rcu);
cd0893369   David S. Miller   neigh: Store hash...
370
  	size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *);
6193d2be2   Eric Dumazet   neigh: __rcu anno...
371
  	struct neighbour __rcu **buckets = nht->hash_buckets;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
  
  	if (size <= PAGE_SIZE)
d6bf78171   Eric Dumazet   net neigh: RCU co...
374
  		kfree(buckets);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
  	else
d6bf78171   Eric Dumazet   net neigh: RCU co...
376
377
  		free_pages((unsigned long)buckets, get_order(size));
  	kfree(nht);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
  }
d6bf78171   Eric Dumazet   net neigh: RCU co...
379
  static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl,
cd0893369   David S. Miller   neigh: Store hash...
380
  						unsigned long new_shift)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
  {
d6bf78171   Eric Dumazet   net neigh: RCU co...
382
383
  	unsigned int i, hash;
  	struct neigh_hash_table *new_nht, *old_nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
  
  	NEIGH_CACHE_STAT_INC(tbl, hash_grows);
d6bf78171   Eric Dumazet   net neigh: RCU co...
386
387
  	old_nht = rcu_dereference_protected(tbl->nht,
  					    lockdep_is_held(&tbl->lock));
cd0893369   David S. Miller   neigh: Store hash...
388
  	new_nht = neigh_hash_alloc(new_shift);
d6bf78171   Eric Dumazet   net neigh: RCU co...
389
390
  	if (!new_nht)
  		return old_nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391

cd0893369   David S. Miller   neigh: Store hash...
392
  	for (i = 0; i < (1 << old_nht->hash_shift); i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
  		struct neighbour *n, *next;
767e97e1e   Eric Dumazet   neigh: RCU conver...
394
395
  		for (n = rcu_dereference_protected(old_nht->hash_buckets[i],
  						   lockdep_is_held(&tbl->lock));
d6bf78171   Eric Dumazet   net neigh: RCU co...
396
397
398
399
  		     n != NULL;
  		     n = next) {
  			hash = tbl->hash(n->primary_key, n->dev,
  					 new_nht->hash_rnd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400

cd0893369   David S. Miller   neigh: Store hash...
401
  			hash >>= (32 - new_nht->hash_shift);
767e97e1e   Eric Dumazet   neigh: RCU conver...
402
403
404
405
406
407
408
409
  			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
410
411
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412

d6bf78171   Eric Dumazet   net neigh: RCU co...
413
414
415
  	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
416
417
418
419
420
421
  }
  
  struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
  			       struct net_device *dev)
  {
  	struct neighbour *n;
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
422

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  	NEIGH_CACHE_STAT_INC(tbl, lookups);
d6bf78171   Eric Dumazet   net neigh: RCU co...
424
  	rcu_read_lock_bh();
60395a20f   Eric W. Biederman   neigh: Factor out...
425
426
  	n = __neigh_lookup_noref(tbl, pkey, dev);
  	if (n) {
9f2374301   Reshetova, Elena   net: convert neig...
427
  		if (!refcount_inc_not_zero(&n->refcnt))
60395a20f   Eric W. Biederman   neigh: Factor out...
428
429
  			n = NULL;
  		NEIGH_CACHE_STAT_INC(tbl, hits);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
  	}
767e97e1e   Eric Dumazet   neigh: RCU conver...
431

d6bf78171   Eric Dumazet   net neigh: RCU co...
432
  	rcu_read_unlock_bh();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
  	return n;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
435
  EXPORT_SYMBOL(neigh_lookup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436

426b5303e   Eric W. Biederman   [NETNS]: Modify t...
437
438
  struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
  				     const void *pkey)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
  {
  	struct neighbour *n;
  	int key_len = tbl->key_len;
bc4bf5f38   Pavel Emelyanov   [NEIGH]: Fix race...
442
  	u32 hash_val;
d6bf78171   Eric Dumazet   net neigh: RCU co...
443
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
  
  	NEIGH_CACHE_STAT_INC(tbl, lookups);
d6bf78171   Eric Dumazet   net neigh: RCU co...
446
447
  	rcu_read_lock_bh();
  	nht = rcu_dereference_bh(tbl->nht);
cd0893369   David S. Miller   neigh: Store hash...
448
  	hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift);
767e97e1e   Eric Dumazet   neigh: RCU conver...
449
450
451
452
  
  	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...
453
  		if (!memcmp(n->primary_key, pkey, key_len) &&
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
454
  		    net_eq(dev_net(n->dev), net)) {
9f2374301   Reshetova, Elena   net: convert neig...
455
  			if (!refcount_inc_not_zero(&n->refcnt))
767e97e1e   Eric Dumazet   neigh: RCU conver...
456
  				n = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
459
460
  			NEIGH_CACHE_STAT_INC(tbl, hits);
  			break;
  		}
  	}
767e97e1e   Eric Dumazet   neigh: RCU conver...
461

d6bf78171   Eric Dumazet   net neigh: RCU co...
462
  	rcu_read_unlock_bh();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
464
  	return n;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
465
  EXPORT_SYMBOL(neigh_lookup_nodev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466

a263b3093   David S. Miller   ipv4: Make neigh ...
467
468
  struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
  				 struct net_device *dev, bool want_ref)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
471
472
  {
  	u32 hash_val;
  	int key_len = tbl->key_len;
  	int error;
596b9b68e   David Miller   neigh: Add infras...
473
  	struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev);
d6bf78171   Eric Dumazet   net neigh: RCU co...
474
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
  
  	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...
490
  	if (dev->netdev_ops->ndo_neigh_construct) {
503eebc26   Jiri Pirko   net: add dev arg ...
491
  		error = dev->netdev_ops->ndo_neigh_construct(dev, n);
da6a8fa02   David Miller   neigh: Add device...
492
493
494
495
496
  		if (error < 0) {
  			rc = ERR_PTR(error);
  			goto out_neigh_release;
  		}
  	}
447f21919   David S. Miller   Revert "net: Remo...
497
498
499
500
501
502
  	/* Device specific setup. */
  	if (n->parms->neigh_setup &&
  	    (error = n->parms->neigh_setup(n)) < 0) {
  		rc = ERR_PTR(error);
  		goto out_neigh_release;
  	}
1f9248e56   Jiri Pirko   neigh: convert pa...
503
  	n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
  
  	write_lock_bh(&tbl->lock);
d6bf78171   Eric Dumazet   net neigh: RCU co...
506
507
  	nht = rcu_dereference_protected(tbl->nht,
  					lockdep_is_held(&tbl->lock));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508

cd0893369   David S. Miller   neigh: Store hash...
509
510
  	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
511

f70343709   Jim Westfall   net: Allow neigh ...
512
  	hash_val = tbl->hash(n->primary_key, dev, nht->hash_rnd) >> (32 - nht->hash_shift);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
514
515
516
517
  
  	if (n->parms->dead) {
  		rc = ERR_PTR(-EINVAL);
  		goto out_tbl_unlock;
  	}
767e97e1e   Eric Dumazet   neigh: RCU conver...
518
519
520
521
522
  	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))) {
f70343709   Jim Westfall   net: Allow neigh ...
523
  		if (dev == n1->dev && !memcmp(n1->primary_key, n->primary_key, key_len)) {
a263b3093   David S. Miller   ipv4: Make neigh ...
524
525
  			if (want_ref)
  				neigh_hold(n1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
529
  			rc = n1;
  			goto out_tbl_unlock;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  	n->dead = 0;
a263b3093   David S. Miller   ipv4: Make neigh ...
531
532
  	if (want_ref)
  		neigh_hold(n);
767e97e1e   Eric Dumazet   neigh: RCU conver...
533
534
535
536
  	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
537
  	write_unlock_bh(&tbl->lock);
d5d427cda   Joe Perches   neighbour: Conver...
538
539
  	neigh_dbg(2, "neigh %p is created
  ", n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
542
543
544
545
546
547
548
  	rc = n;
  out:
  	return rc;
  out_tbl_unlock:
  	write_unlock_bh(&tbl->lock);
  out_neigh_release:
  	neigh_release(n);
  	goto out;
  }
a263b3093   David S. Miller   ipv4: Make neigh ...
549
  EXPORT_SYMBOL(__neigh_create);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550

be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
551
  static u32 pneigh_hash(const void *pkey, int key_len)
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
552
  {
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
553
  	u32 hash_val = *(u32 *)(pkey + key_len - 4);
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
554
555
556
557
  	hash_val ^= (hash_val >> 16);
  	hash_val ^= hash_val >> 8;
  	hash_val ^= hash_val >> 4;
  	hash_val &= PNEIGH_HASHMASK;
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
558
559
  	return hash_val;
  }
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
560

be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
561
562
563
564
565
566
567
  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...
568
  		if (!memcmp(n->key, pkey, key_len) &&
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
569
  		    net_eq(pneigh_net(n), net) &&
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
570
  		    (n->dev == dev || !n->dev))
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
571
572
  			return n;
  		n = n->next;
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
573
  	}
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
574
575
  	return NULL;
  }
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
576

be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
577
578
579
580
581
582
583
584
  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...
585
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
586
  EXPORT_SYMBOL_GPL(__pneigh_lookup);
fa86d322d   Pavel Emelyanov   [NEIGH]: Fix race...
587

426b5303e   Eric W. Biederman   [NETNS]: Modify t...
588
589
  struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
  				    struct net *net, const void *pkey,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
591
592
593
  				    struct net_device *dev, int creat)
  {
  	struct pneigh_entry *n;
  	int key_len = tbl->key_len;
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
594
  	u32 hash_val = pneigh_hash(pkey, key_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
  
  	read_lock_bh(&tbl->lock);
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
597
598
  	n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
  			      net, pkey, key_len, dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  	read_unlock_bh(&tbl->lock);
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
600
601
  
  	if (n || !creat)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
  		goto out;
4ae289444   Pavel Emelyanov   [NEIGH]: Ensure t...
603
  	ASSERT_RTNL();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
605
606
  	n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL);
  	if (!n)
  		goto out;
efd7ef1c1   Eric W. Biederman   net: Kill hold_ne...
607
  	write_pnet(&n->net, net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
  	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);
  		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: ...
628
  EXPORT_SYMBOL(pneigh_lookup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629

426b5303e   Eric W. Biederman   [NETNS]: Modify t...
630
  int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
632
633
634
  		  struct net_device *dev)
  {
  	struct pneigh_entry *n, **np;
  	int key_len = tbl->key_len;
be01d655d   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
635
  	u32 hash_val = pneigh_hash(pkey, key_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
638
639
  
  	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...
640
  		if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
641
  		    net_eq(pneigh_net(n), net)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
643
644
645
646
647
648
649
650
651
652
653
654
  			*np = n->next;
  			write_unlock_bh(&tbl->lock);
  			if (tbl->pdestructor)
  				tbl->pdestructor(n);
  			if (n->dev)
  				dev_put(n->dev);
  			kfree(n);
  			return 0;
  		}
  	}
  	write_unlock_bh(&tbl->lock);
  	return -ENOENT;
  }
012e5e5b6   Wolfgang Bumiller   net: fix deadlock...
655
656
  static int pneigh_ifdown_and_unlock(struct neigh_table *tbl,
  				    struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
  {
012e5e5b6   Wolfgang Bumiller   net: fix deadlock...
658
  	struct pneigh_entry *n, **np, *freelist = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
662
663
664
665
  	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;
012e5e5b6   Wolfgang Bumiller   net: fix deadlock...
666
667
  				n->next = freelist;
  				freelist = n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
670
671
672
  				continue;
  			}
  			np = &n->next;
  		}
  	}
012e5e5b6   Wolfgang Bumiller   net: fix deadlock...
673
674
675
676
677
678
679
680
681
682
  	write_unlock_bh(&tbl->lock);
  	while ((n = freelist)) {
  		freelist = n->next;
  		n->next = NULL;
  		if (tbl->pdestructor)
  			tbl->pdestructor(n);
  		if (n->dev)
  			dev_put(n->dev);
  		kfree(n);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
  	return -ENOENT;
  }
06f0511df   Denis V. Lunev   [ARP]: neigh_parm...
685
686
687
688
  static void neigh_parms_destroy(struct neigh_parms *parms);
  
  static inline void neigh_parms_put(struct neigh_parms *parms)
  {
6343944bc   Reshetova, Elena   net: convert neig...
689
  	if (refcount_dec_and_test(&parms->refcnt))
06f0511df   Denis V. Lunev   [ARP]: neigh_parm...
690
691
  		neigh_parms_destroy(parms);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
694
695
696
697
698
  
  /*
   *	neighbour must already be out of the table;
   *
   */
  void neigh_destroy(struct neighbour *neigh)
  {
da6a8fa02   David Miller   neigh: Add device...
699
  	struct net_device *dev = neigh->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
702
  	NEIGH_CACHE_STAT_INC(neigh->tbl, destroys);
  
  	if (!neigh->dead) {
e005d193d   Joe Perches   net: core: Use pr...
703
704
  		pr_warn("Destroying alive neighbour %p
  ", neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
706
707
708
709
  		dump_stack();
  		return;
  	}
  
  	if (neigh_del_timer(neigh))
e005d193d   Joe Perches   net: core: Use pr...
710
711
  		pr_warn("Impossible event
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712

c9ab4d85d   Eric Dumazet   neighbour: fix a ...
713
714
715
  	write_lock_bh(&neigh->lock);
  	__skb_queue_purge(&neigh->arp_queue);
  	write_unlock_bh(&neigh->lock);
8b5c171bb   Eric Dumazet   neigh: new unreso...
716
  	neigh->arp_queue_len_bytes = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717

447f21919   David S. Miller   Revert "net: Remo...
718
  	if (dev->netdev_ops->ndo_neigh_destroy)
503eebc26   Jiri Pirko   net: add dev arg ...
719
  		dev->netdev_ops->ndo_neigh_destroy(dev, neigh);
447f21919   David S. Miller   Revert "net: Remo...
720

da6a8fa02   David Miller   neigh: Add device...
721
  	dev_put(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
  	neigh_parms_put(neigh->parms);
d5d427cda   Joe Perches   neighbour: Conver...
723
724
  	neigh_dbg(2, "neigh %p is destroyed
  ", neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
726
  
  	atomic_dec(&neigh->tbl->entries);
5b8b0060c   David Miller   neigh: Get rid of...
727
  	kfree_rcu(neigh, rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
729
  EXPORT_SYMBOL(neigh_destroy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
731
732
733
734
735
736
737
  
  /* Neighbour state is suspicious;
     disable fast path.
  
     Called with write_locked neigh.
   */
  static void neigh_suspect(struct neighbour *neigh)
  {
d5d427cda   Joe Perches   neighbour: Conver...
738
739
  	neigh_dbg(2, "neigh %p is suspected
  ", neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
  
  	neigh->output = neigh->ops->output;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
744
745
746
747
748
749
750
  }
  
  /* Neighbour state is OK;
     enable fast path.
  
     Called with write_locked neigh.
   */
  static void neigh_connect(struct neighbour *neigh)
  {
d5d427cda   Joe Perches   neighbour: Conver...
751
752
  	neigh_dbg(2, "neigh %p is connected
  ", neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
  
  	neigh->output = neigh->ops->connected_output;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
  }
e4c4e448c   Eric Dumazet   neigh: Convert ga...
756
  static void neigh_periodic_work(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
  {
e4c4e448c   Eric Dumazet   neigh: Convert ga...
758
  	struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work);
767e97e1e   Eric Dumazet   neigh: RCU conver...
759
760
  	struct neighbour *n;
  	struct neighbour __rcu **np;
e4c4e448c   Eric Dumazet   neigh: Convert ga...
761
  	unsigned int i;
d6bf78171   Eric Dumazet   net neigh: RCU co...
762
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
764
  
  	NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs);
e4c4e448c   Eric Dumazet   neigh: Convert ga...
765
  	write_lock_bh(&tbl->lock);
d6bf78171   Eric Dumazet   net neigh: RCU co...
766
767
  	nht = rcu_dereference_protected(tbl->nht,
  					lockdep_is_held(&tbl->lock));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
769
770
771
  
  	/*
  	 *	periodically recompute ReachableTime from random function
  	 */
e4c4e448c   Eric Dumazet   neigh: Convert ga...
772
  	if (time_after(jiffies, tbl->last_rand + 300 * HZ)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  		struct neigh_parms *p;
e4c4e448c   Eric Dumazet   neigh: Convert ga...
774
  		tbl->last_rand = jiffies;
75fbfd332   Nicolas Dichtel   neigh: optimize n...
775
  		list_for_each_entry(p, &tbl->parms_list, list)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
  			p->reachable_time =
1f9248e56   Jiri Pirko   neigh: convert pa...
777
  				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778
  	}
feff9ab2e   Duan Jiong   neigh: recompute ...
779
780
  	if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
  		goto out;
cd0893369   David S. Miller   neigh: Store hash...
781
  	for (i = 0 ; i < (1 << nht->hash_shift); i++) {
d6bf78171   Eric Dumazet   net neigh: RCU co...
782
  		np = &nht->hash_buckets[i];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783

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

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

e4c4e448c   Eric Dumazet   neigh: Convert ga...
790
791
792
793
794
  			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
795

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

9f2374301   Reshetova, Elena   net: convert neig...
799
  			if (refcount_read(&n->refcnt) == 1 &&
e4c4e448c   Eric Dumazet   neigh: Convert ga...
800
  			    (state == NUD_FAILED ||
1f9248e56   Jiri Pirko   neigh: convert pa...
801
  			     time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
e4c4e448c   Eric Dumazet   neigh: Convert ga...
802
803
804
805
806
807
  				*np = n->next;
  				n->dead = 1;
  				write_unlock(&n->lock);
  				neigh_cleanup_and_release(n);
  				continue;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
  			write_unlock(&n->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
810
  
  next_elt:
e4c4e448c   Eric Dumazet   neigh: Convert ga...
811
812
813
814
815
816
817
818
819
  			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);
84338a6c9   Michel Machado   neighbour: Fixed ...
820
821
  		nht = rcu_dereference_protected(tbl->nht,
  						lockdep_is_held(&tbl->lock));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
  	}
2724680bc   YOSHIFUJI Hideaki / 吉藤英明   neigh: Keep neigh...
823
  out:
1f9248e56   Jiri Pirko   neigh: convert pa...
824
825
826
  	/* 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
827
  	 */
f618002b0   viresh kumar   net/neighbour: qu...
828
  	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
1f9248e56   Jiri Pirko   neigh: convert pa...
829
  			      NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1);
e4c4e448c   Eric Dumazet   neigh: Convert ga...
830
  	write_unlock_bh(&tbl->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
833
834
835
  }
  
  static __inline__ int neigh_max_probes(struct neighbour *n)
  {
  	struct neigh_parms *p = n->parms;
8da86466b   YOSHIFUJI Hideaki/吉藤英明   net: neighbour: A...
836
837
838
  	return NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) +
  	       (n->nud_state & NUD_PROBE ? NEIGH_VAR(p, MCAST_REPROBES) :
  	        NEIGH_VAR(p, MCAST_PROBES));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
  }
5ef12d98a   Timo Teras   neigh: fix state ...
840
  static void neigh_invalidate(struct neighbour *neigh)
0a141509e   Eric Dumazet   net: Annotates ne...
841
842
  	__releases(neigh->lock)
  	__acquires(neigh->lock)
5ef12d98a   Timo Teras   neigh: fix state ...
843
844
845
846
  {
  	struct sk_buff *skb;
  
  	NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
d5d427cda   Joe Perches   neighbour: Conver...
847
848
  	neigh_dbg(2, "neigh %p is failed
  ", neigh);
5ef12d98a   Timo Teras   neigh: fix state ...
849
850
851
852
853
854
855
856
857
858
859
860
861
  	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);
  	}
c9ab4d85d   Eric Dumazet   neighbour: fix a ...
862
  	__skb_queue_purge(&neigh->arp_queue);
8b5c171bb   Eric Dumazet   neigh: new unreso...
863
  	neigh->arp_queue_len_bytes = 0;
5ef12d98a   Timo Teras   neigh: fix state ...
864
  }
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
865
866
867
  static void neigh_probe(struct neighbour *neigh)
  	__releases(neigh->lock)
  {
4ed377e36   Hannes Frederic Sowa   net: neighbour: u...
868
  	struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
869
870
  	/* keep skb alive even if arp_queue overflows */
  	if (skb)
19125c1a4   Martin Zhang   net: use skb_clon...
871
  		skb = skb_clone(skb, GFP_ATOMIC);
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
872
  	write_unlock(&neigh->lock);
48481c8fa   Eric Dumazet   net: neigh: guard...
873
874
  	if (neigh->ops->solicit)
  		neigh->ops->solicit(neigh, skb);
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
875
876
877
  	atomic_inc(&neigh->probes);
  	kfree_skb(skb);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
879
880
881
882
883
  /* 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;
95c961747   Eric Dumazet   net: cleanup unsi...
884
  	unsigned int state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885
886
887
888
889
890
891
  	int notify = 0;
  
  	write_lock(&neigh->lock);
  
  	state = neigh->nud_state;
  	now = jiffies;
  	next = now + HZ;
045f7b3b0   David S. Miller   neigh: Kill bogus...
892
  	if (!(state & NUD_IN_TIMER))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
  
  	if (state & NUD_REACHABLE) {
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
896
  		if (time_before_eq(now,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
  				   neigh->confirmed + neigh->parms->reachable_time)) {
d5d427cda   Joe Perches   neighbour: Conver...
898
899
  			neigh_dbg(2, "neigh %p is still alive
  ", neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
900
901
  			next = neigh->confirmed + neigh->parms->reachable_time;
  		} else if (time_before_eq(now,
1f9248e56   Jiri Pirko   neigh: convert pa...
902
903
  					  neigh->used +
  					  NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
d5d427cda   Joe Perches   neighbour: Conver...
904
905
  			neigh_dbg(2, "neigh %p is delayed
  ", neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
  			neigh->nud_state = NUD_DELAY;
955aaa2fe   YOSHIFUJI Hideaki   [NET]: NEIGHBOUR:...
907
  			neigh->updated = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
  			neigh_suspect(neigh);
1f9248e56   Jiri Pirko   neigh: convert pa...
909
  			next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
  		} else {
d5d427cda   Joe Perches   neighbour: Conver...
911
912
  			neigh_dbg(2, "neigh %p is suspected
  ", neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913
  			neigh->nud_state = NUD_STALE;
955aaa2fe   YOSHIFUJI Hideaki   [NET]: NEIGHBOUR:...
914
  			neigh->updated = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
  			neigh_suspect(neigh);
8d71740c5   Tom Tucker   [NET]: Core net c...
916
  			notify = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
  		}
  	} else if (state & NUD_DELAY) {
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
919
  		if (time_before_eq(now,
1f9248e56   Jiri Pirko   neigh: convert pa...
920
921
  				   neigh->confirmed +
  				   NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) {
d5d427cda   Joe Perches   neighbour: Conver...
922
923
  			neigh_dbg(2, "neigh %p is now reachable
  ", neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
  			neigh->nud_state = NUD_REACHABLE;
955aaa2fe   YOSHIFUJI Hideaki   [NET]: NEIGHBOUR:...
925
  			neigh->updated = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
  			neigh_connect(neigh);
8d71740c5   Tom Tucker   [NET]: Core net c...
927
  			notify = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928
929
  			next = neigh->confirmed + neigh->parms->reachable_time;
  		} else {
d5d427cda   Joe Perches   neighbour: Conver...
930
931
  			neigh_dbg(2, "neigh %p is probed
  ", neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
  			neigh->nud_state = NUD_PROBE;
955aaa2fe   YOSHIFUJI Hideaki   [NET]: NEIGHBOUR:...
933
  			neigh->updated = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
  			atomic_set(&neigh->probes, 0);
765c9c639   Erik Kline   neigh: Better han...
935
  			notify = 1;
1f9248e56   Jiri Pirko   neigh: convert pa...
936
  			next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
938
939
  		}
  	} else {
  		/* NUD_PROBE|NUD_INCOMPLETE */
1f9248e56   Jiri Pirko   neigh: convert pa...
940
  		next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
942
943
944
  	}
  
  	if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
  	    atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
946
  		neigh->nud_state = NUD_FAILED;
  		notify = 1;
5ef12d98a   Timo Teras   neigh: fix state ...
947
  		neigh_invalidate(neigh);
5e2c21dce   Duan Jiong   neigh: directly g...
948
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
950
951
  	}
  
  	if (neigh->nud_state & NUD_IN_TIMER) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
953
  		if (time_before(next, jiffies + HZ/2))
  			next = jiffies + HZ/2;
6fb9974f4   Herbert Xu   [NEIGH] Fix add_t...
954
955
  		if (!mod_timer(&neigh->timer, next))
  			neigh_hold(neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
957
  	}
  	if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
958
  		neigh_probe(neigh);
9ff566074   David S. Miller   Revert "[NDISC]: ...
959
  	} else {
69cc64d8d   David S. Miller   [NDISC]: Fix race...
960
  out:
9ff566074   David S. Miller   Revert "[NDISC]: ...
961
962
  		write_unlock(&neigh->lock);
  	}
d961db358   Thomas Graf   [NEIGH]: Netlink ...
963

8d71740c5   Tom Tucker   [NET]: Core net c...
964
  	if (notify)
7b8f7a402   Roopa Prabhu   neighbour: fix nl...
965
  		neigh_update_notify(neigh, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
967
968
969
970
971
972
  	neigh_release(neigh);
  }
  
  int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
  {
  	int rc;
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
973
  	bool immediate_probe = false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
975
976
977
978
979
  
  	write_lock_bh(&neigh->lock);
  
  	rc = 0;
  	if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
  		goto out_unlock_bh;
2c51a97f7   Julian Anastasov   neigh: do not mod...
980
981
  	if (neigh->dead)
  		goto out_dead;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
  	if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
1f9248e56   Jiri Pirko   neigh: convert pa...
984
985
  		if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +
  		    NEIGH_VAR(neigh->parms, APP_PROBES)) {
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
986
  			unsigned long next, now = jiffies;
1f9248e56   Jiri Pirko   neigh: convert pa...
987
988
  			atomic_set(&neigh->probes,
  				   NEIGH_VAR(neigh->parms, UCAST_PROBES));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
  			neigh->nud_state     = NUD_INCOMPLETE;
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
990
  			neigh->updated = now;
1f9248e56   Jiri Pirko   neigh: convert pa...
991
992
  			next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
  					 HZ/2);
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
993
994
  			neigh_add_timer(neigh, next);
  			immediate_probe = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
996
  		} else {
  			neigh->nud_state = NUD_FAILED;
955aaa2fe   YOSHIFUJI Hideaki   [NET]: NEIGHBOUR:...
997
  			neigh->updated = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
  			write_unlock_bh(&neigh->lock);
f3fbbe0f6   Wei Yongjun   core: remove some...
999
  			kfree_skb(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
1001
1002
  			return 1;
  		}
  	} else if (neigh->nud_state & NUD_STALE) {
d5d427cda   Joe Perches   neighbour: Conver...
1003
1004
  		neigh_dbg(2, "neigh %p is delayed
  ", neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1005
  		neigh->nud_state = NUD_DELAY;
955aaa2fe   YOSHIFUJI Hideaki   [NET]: NEIGHBOUR:...
1006
  		neigh->updated = jiffies;
1f9248e56   Jiri Pirko   neigh: convert pa...
1007
1008
  		neigh_add_timer(neigh, jiffies +
  				NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009
1010
1011
1012
  	}
  
  	if (neigh->nud_state == NUD_INCOMPLETE) {
  		if (skb) {
8b5c171bb   Eric Dumazet   neigh: new unreso...
1013
  			while (neigh->arp_queue_len_bytes + skb->truesize >
1f9248e56   Jiri Pirko   neigh: convert pa...
1014
  			       NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
  				struct sk_buff *buff;
8b5c171bb   Eric Dumazet   neigh: new unreso...
1016

f72051b06   David S. Miller   neigh: Remove by-...
1017
  				buff = __skb_dequeue(&neigh->arp_queue);
8b5c171bb   Eric Dumazet   neigh: new unreso...
1018
1019
1020
  				if (!buff)
  					break;
  				neigh->arp_queue_len_bytes -= buff->truesize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1021
  				kfree_skb(buff);
9a6d276e8   Neil Horman   core: add stat to...
1022
  				NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023
  			}
a47311380   Eric Dumazet   net: fix __neigh_...
1024
  			skb_dst_force(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1025
  			__skb_queue_tail(&neigh->arp_queue, skb);
8b5c171bb   Eric Dumazet   neigh: new unreso...
1026
  			neigh->arp_queue_len_bytes += skb->truesize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1027
1028
1029
1030
  		}
  		rc = 1;
  	}
  out_unlock_bh:
cd28ca0a3   Eric Dumazet   neigh: reduce arp...
1031
1032
1033
1034
1035
  	if (immediate_probe)
  		neigh_probe(neigh);
  	else
  		write_unlock(&neigh->lock);
  	local_bh_enable();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1036
  	return rc;
2c51a97f7   Julian Anastasov   neigh: do not mod...
1037
1038
1039
1040
1041
1042
1043
  
  out_dead:
  	if (neigh->nud_state & NUD_STALE)
  		goto out_unlock_bh;
  	write_unlock_bh(&neigh->lock);
  	kfree_skb(skb);
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1045
  EXPORT_SYMBOL(__neigh_event_send);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046

f6b72b621   David S. Miller   net: Embed hh_cac...
1047
  static void neigh_update_hhs(struct neighbour *neigh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
1049
  {
  	struct hh_cache *hh;
3b04ddde0   Stephen Hemminger   [NET]: Move hardw...
1050
  	void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
91a72a705   Doug Kehn   net/core: neighbo...
1051
1052
1053
1054
  		= NULL;
  
  	if (neigh->dev->header_ops)
  		update = neigh->dev->header_ops->cache_update;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1055
1056
  
  	if (update) {
f6b72b621   David S. Miller   net: Embed hh_cac...
1057
1058
  		hh = &neigh->hh;
  		if (hh->hh_len) {
3644f0cee   Stephen Hemminger   [NET]: Convert hh...
1059
  			write_seqlock_bh(&hh->hh_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
  			update(hh, neigh->dev, neigh->ha);
3644f0cee   Stephen Hemminger   [NET]: Convert hh...
1061
  			write_sequnlock_bh(&hh->hh_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
  		}
  	}
  }
  
  
  
  /* 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...
1075
  				lladdr instead of overriding it
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
  				if it is different.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
  	NEIGH_UPDATE_F_ADMIN	means that the change is administrative.
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1078
  	NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1079
1080
1081
1082
1083
1084
1085
1086
  				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,
7b8f7a402   Roopa Prabhu   neighbour: fix nl...
1087
  		 u32 flags, u32 nlmsg_pid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
1089
1090
  {
  	u8 old;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1091
  	int notify = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
1093
1094
1095
1096
1097
1098
1099
  	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...
1100
  	if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
1102
  	    (old & (NUD_NOARP | NUD_PERMANENT)))
  		goto out;
2c51a97f7   Julian Anastasov   neigh: do not mod...
1103
1104
  	if (neigh->dead)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105
1106
1107
1108
1109
1110
1111
  
  	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
1112
  		notify = old & NUD_VALID;
5ef12d98a   Timo Teras   neigh: fix state ...
1113
1114
1115
1116
1117
  		if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
  		    (new & NUD_FAILED)) {
  			neigh_invalidate(neigh);
  			notify = 1;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
  		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...
1131
  		if ((old & NUD_VALID) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
  		    !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;
  	}
ff64a1a2c   Vasily Khoruzhick   neighbour: confir...
1143
1144
1145
1146
1147
  	/* Update confirmed timestamp for neighbour entry after we
  	 * received ARP packet even if it doesn't change IP to MAC binding.
  	 */
  	if (new & NUD_CONNECTED)
  		neigh->confirmed = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
  	/* 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 {
0e7bbcc10   Julian Anastasov   neigh: allow admi...
1163
1164
  			if (lladdr == neigh->ha && new == NUD_STALE &&
  			    !(flags & NEIGH_UPDATE_F_ADMIN))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
1167
  				new = old;
  		}
  	}
ff64a1a2c   Vasily Khoruzhick   neighbour: confir...
1168
  	/* Update timestamp only once we know we will make a change to the
77d712334   Ihar Hrachyshka   neighbour: update...
1169
1170
1171
  	 * neighbour entry. Otherwise we risk to move the locktime window with
  	 * noop updates and ignore relevant ARP updates.
  	 */
ff64a1a2c   Vasily Khoruzhick   neighbour: confir...
1172
  	if (new != old || lladdr != neigh->ha)
77d712334   Ihar Hrachyshka   neighbour: update...
1173
  		neigh->updated = jiffies;
77d712334   Ihar Hrachyshka   neighbour: update...
1174

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1175
1176
  	if (new != old) {
  		neigh_del_timer(neigh);
765c9c639   Erik Kline   neigh: Better han...
1177
1178
  		if (new & NUD_PROBE)
  			atomic_set(&neigh->probes, 0);
a43d8994b   Pavel Emelyanov   [NEIGH]: Make nei...
1179
  		if (new & NUD_IN_TIMER)
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1180
1181
  			neigh_add_timer(neigh, (jiffies +
  						((new & NUD_REACHABLE) ?
667347f1c   David S. Miller   [NEIGH]: Add debu...
1182
1183
  						 neigh->parms->reachable_time :
  						 0)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1184
  		neigh->nud_state = new;
53385d2d1   Bob Gilligan   neigh: Netlink no...
1185
  		notify = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1186
1187
1188
  	}
  
  	if (lladdr != neigh->ha) {
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1189
  		write_seqlock(&neigh->ha_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1190
  		memcpy(&neigh->ha, lladdr, dev->addr_len);
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1191
  		write_sequnlock(&neigh->ha_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
1193
1194
  		neigh_update_hhs(neigh);
  		if (!(new & NUD_CONNECTED))
  			neigh->confirmed = jiffies -
1f9248e56   Jiri Pirko   neigh: convert pa...
1195
  				      (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1196
  		notify = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
  	}
  	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...
1211
1212
  			struct dst_entry *dst = skb_dst(skb);
  			struct neighbour *n2, *n1 = neigh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1213
  			write_unlock_bh(&neigh->lock);
e049f2888   roy.qing.li@gmail.com   neigh: fix rcu sp...
1214
1215
  
  			rcu_read_lock();
13a43d94a   David S. Miller   neigh: Convert ov...
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
  
  			/* Why not just use 'neigh' as-is?  The problem is that
  			 * things such as shaper, eql, and sch_teql can end up
  			 * using alternative, different, neigh objects to output
  			 * the packet in the output path.  So what we need to do
  			 * here is re-lookup the top-level neigh in the path so
  			 * we can reinject the packet there.
  			 */
  			n2 = NULL;
  			if (dst) {
  				n2 = dst_neigh_lookup_skb(dst, skb);
  				if (n2)
  					n1 = n2;
  			}
8f40b161d   David S. Miller   neigh: Pass neigh...
1230
  			n1->output(n1, skb);
13a43d94a   David S. Miller   neigh: Convert ov...
1231
1232
  			if (n2)
  				neigh_release(n2);
e049f2888   roy.qing.li@gmail.com   neigh: fix rcu sp...
1233
  			rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1234
1235
  			write_lock_bh(&neigh->lock);
  		}
c9ab4d85d   Eric Dumazet   neighbour: fix a ...
1236
  		__skb_queue_purge(&neigh->arp_queue);
8b5c171bb   Eric Dumazet   neigh: new unreso...
1237
  		neigh->arp_queue_len_bytes = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
1239
1240
1241
1242
1243
1244
1245
  	}
  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...
1246
1247
  
  	if (notify)
7b8f7a402   Roopa Prabhu   neighbour: fix nl...
1248
  		neigh_update_notify(neigh, nlmsg_pid);
d961db358   Thomas Graf   [NEIGH]: Netlink ...
1249

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250
1251
  	return err;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1252
  EXPORT_SYMBOL(neigh_update);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1253

7e9805696   Jiri Benc   ipv6: router reac...
1254
1255
1256
1257
1258
  /* Update the neigh to listen temporarily for probe responses, even if it is
   * in a NUD_FAILED state. The caller has to hold neigh->lock for writing.
   */
  void __neigh_set_probe_once(struct neighbour *neigh)
  {
2c51a97f7   Julian Anastasov   neigh: do not mod...
1259
1260
  	if (neigh->dead)
  		return;
7e9805696   Jiri Benc   ipv6: router reac...
1261
1262
1263
  	neigh->updated = jiffies;
  	if (!(neigh->nud_state & NUD_FAILED))
  		return;
2176d5d41   Duan Jiong   neigh: set nud_st...
1264
1265
  	neigh->nud_state = NUD_INCOMPLETE;
  	atomic_set(&neigh->probes, neigh_max_probes(neigh));
7e9805696   Jiri Benc   ipv6: router reac...
1266
1267
1268
1269
  	neigh_add_timer(neigh,
  			jiffies + NEIGH_VAR(neigh->parms, RETRANS_TIME));
  }
  EXPORT_SYMBOL(__neigh_set_probe_once);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1270
1271
1272
1273
1274
1275
1276
  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...
1277
  		neigh_update(neigh, lladdr, NUD_STALE,
7b8f7a402   Roopa Prabhu   neighbour: fix nl...
1278
  			     NEIGH_UPDATE_F_OVERRIDE, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1279
1280
  	return neigh;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1281
  EXPORT_SYMBOL(neigh_event_ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1282

34d101dd6   Eric Dumazet   neigh: speedup ne...
1283
  /* called with read_lock_bh(&n->lock); */
bdf53c584   Eric W. Biederman   neigh: Don't requ...
1284
  static void neigh_hh_init(struct neighbour *n)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
  {
bdf53c584   Eric W. Biederman   neigh: Don't requ...
1286
1287
  	struct net_device *dev = n->dev;
  	__be16 prot = n->tbl->protocol;
f6b72b621   David S. Miller   net: Embed hh_cac...
1288
  	struct hh_cache	*hh = &n->hh;
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1289
1290
  
  	write_lock_bh(&n->lock);
34d101dd6   Eric Dumazet   neigh: speedup ne...
1291

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

0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1298
  	write_unlock_bh(&n->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1299
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1300
  /* Slow and careful. */
8f40b161d   David S. Miller   neigh: Pass neigh...
1301
  int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1302
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
  	int rc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1304
1305
1306
  	if (!neigh_event_send(neigh, skb)) {
  		int err;
  		struct net_device *dev = neigh->dev;
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1307
  		unsigned int seq;
34d101dd6   Eric Dumazet   neigh: speedup ne...
1308

f6b72b621   David S. Miller   net: Embed hh_cac...
1309
  		if (dev->header_ops->cache && !neigh->hh.hh_len)
bdf53c584   Eric W. Biederman   neigh: Don't requ...
1310
  			neigh_hh_init(neigh);
34d101dd6   Eric Dumazet   neigh: speedup ne...
1311

0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1312
  		do {
e1f165032   ramesh.nagappa@gmail.com   net: Fix skb_unde...
1313
  			__skb_pull(skb, skb_network_offset(skb));
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1314
1315
1316
1317
  			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...
1318

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1319
  		if (err >= 0)
542d4d685   David S. Miller   neigh: Kill ndisc...
1320
  			rc = dev_queue_xmit(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1321
1322
1323
1324
1325
  		else
  			goto out_kfree_skb;
  	}
  out:
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1326
1327
1328
1329
1330
  out_kfree_skb:
  	rc = -EINVAL;
  	kfree_skb(skb);
  	goto out;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1331
  EXPORT_SYMBOL(neigh_resolve_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1332
1333
  
  /* As fast as possible without hh cache */
8f40b161d   David S. Miller   neigh: Pass neigh...
1334
  int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1335
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1336
  	struct net_device *dev = neigh->dev;
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1337
  	unsigned int seq;
8f40b161d   David S. Miller   neigh: Pass neigh...
1338
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339

0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1340
  	do {
e1f165032   ramesh.nagappa@gmail.com   net: Fix skb_unde...
1341
  		__skb_pull(skb, skb_network_offset(skb));
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
1342
1343
1344
1345
  		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
1346
  	if (err >= 0)
542d4d685   David S. Miller   neigh: Kill ndisc...
1347
  		err = dev_queue_xmit(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1348
1349
1350
1351
1352
1353
  	else {
  		err = -EINVAL;
  		kfree_skb(skb);
  	}
  	return err;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1354
  EXPORT_SYMBOL(neigh_connected_output);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355

8f40b161d   David S. Miller   neigh: Pass neigh...
1356
1357
1358
1359
1360
  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
1361
1362
1363
1364
1365
  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-...
1366
  	struct sk_buff *skb, *n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367
1368
  
  	spin_lock(&tbl->proxy_queue.lock);
f72051b06   David S. Miller   neigh: Remove by-...
1369
1370
  	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
1371

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

f72051b06   David S. Miller   neigh: Remove by-...
1375
  			__skb_unlink(skb, &tbl->proxy_queue);
20e6074eb   Eric Dumazet   arp: fix rcu lock...
1376
1377
  			if (tbl->proxy_redo && netif_running(dev)) {
  				rcu_read_lock();
f72051b06   David S. Miller   neigh: Remove by-...
1378
  				tbl->proxy_redo(skb);
20e6074eb   Eric Dumazet   arp: fix rcu lock...
1379
1380
  				rcu_read_unlock();
  			} else {
f72051b06   David S. Miller   neigh: Remove by-...
1381
  				kfree_skb(skb);
20e6074eb   Eric Dumazet   arp: fix rcu lock...
1382
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
  
  			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;
63862b5be   Aruna-Hewapathirane   net: replace macr...
1398
1399
  
  	unsigned long sched_next = now + (prandom_u32() %
1f9248e56   Jiri Pirko   neigh: convert pa...
1400
  					  NEIGH_VAR(p, PROXY_DELAY));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1401

1f9248e56   Jiri Pirko   neigh: convert pa...
1402
  	if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403
1404
1405
  		kfree_skb(skb);
  		return;
  	}
a61bbcf28   Patrick McHardy   [NET]: Store skb-...
1406
1407
1408
  
  	NEIGH_CB(skb)->sched_next = sched_next;
  	NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
1410
1411
1412
1413
1414
  
  	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...
1415
  	skb_dst_drop(skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1416
1417
1418
1419
1420
  	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: ...
1421
  EXPORT_SYMBOL(pneigh_enqueue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1422

97fd5bc7f   Tobias Klauser   net: Rename looku...
1423
  static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl,
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
1424
1425
1426
  						      struct net *net, int ifindex)
  {
  	struct neigh_parms *p;
75fbfd332   Nicolas Dichtel   neigh: optimize n...
1427
  	list_for_each_entry(p, &tbl->parms_list, list) {
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1428
  		if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
170d6f995   Gao feng   neigh: only allow...
1429
  		    (!p->dev && !ifindex && net_eq(net, &init_net)))
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
1430
1431
1432
1433
1434
  			return p;
  	}
  
  	return NULL;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1435
1436
1437
1438
  
  struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
  				      struct neigh_table *tbl)
  {
cf89d6b28   Gao feng   neigh: no need to...
1439
  	struct neigh_parms *p;
008298231   Stephen Hemminger   netdev: add more ...
1440
1441
  	struct net *net = dev_net(dev);
  	const struct net_device_ops *ops = dev->netdev_ops;
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
1442

cf89d6b28   Gao feng   neigh: no need to...
1443
  	p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1444
  	if (p) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1445
  		p->tbl		  = tbl;
6343944bc   Reshetova, Elena   net: convert neig...
1446
  		refcount_set(&p->refcnt, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1447
  		p->reachable_time =
1f9248e56   Jiri Pirko   neigh: convert pa...
1448
  				neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
63134803a   Veaceslav Falico   neighbour: popula...
1449
1450
  		dev_hold(dev);
  		p->dev = dev;
efd7ef1c1   Eric W. Biederman   net: Kill hold_ne...
1451
  		write_pnet(&p->net, net);
63134803a   Veaceslav Falico   neighbour: popula...
1452
  		p->sysctl_table = NULL;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1453

008298231   Stephen Hemminger   netdev: add more ...
1454
  		if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
63134803a   Veaceslav Falico   neighbour: popula...
1455
  			dev_put(dev);
486b51d37   Denis V. Lunev   [ARP]: Remove ove...
1456
1457
  			kfree(p);
  			return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1458
  		}
486b51d37   Denis V. Lunev   [ARP]: Remove ove...
1459

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1460
  		write_lock_bh(&tbl->lock);
75fbfd332   Nicolas Dichtel   neigh: optimize n...
1461
  		list_add(&p->list, &tbl->parms.list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1462
  		write_unlock_bh(&tbl->lock);
1d4c8c298   Jiri Pirko   neigh: restore ol...
1463
1464
  
  		neigh_parms_data_state_cleanall(p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1465
1466
1467
  	}
  	return p;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1468
  EXPORT_SYMBOL(neigh_parms_alloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
  
  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)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1480
1481
1482
  	if (!parms || parms == &tbl->parms)
  		return;
  	write_lock_bh(&tbl->lock);
75fbfd332   Nicolas Dichtel   neigh: optimize n...
1483
1484
  	list_del(&parms->list);
  	parms->dead = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1485
  	write_unlock_bh(&tbl->lock);
75fbfd332   Nicolas Dichtel   neigh: optimize n...
1486
1487
1488
  	if (parms->dev)
  		dev_put(parms->dev);
  	call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1489
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1490
  EXPORT_SYMBOL(neigh_parms_release);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1491

06f0511df   Denis V. Lunev   [ARP]: neigh_parm...
1492
  static void neigh_parms_destroy(struct neigh_parms *parms)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1493
1494
1495
  {
  	kfree(parms);
  }
c2ecba717   Pavel Emelianov   [NET]: Set a sepa...
1496
  static struct lock_class_key neigh_table_proxy_queue_class;
d7480fd3b   WANG Cong   neigh: remove dyn...
1497
1498
1499
  static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly;
  
  void neigh_table_init(int index, struct neigh_table *tbl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1500
1501
1502
  {
  	unsigned long now = jiffies;
  	unsigned long phsize;
75fbfd332   Nicolas Dichtel   neigh: optimize n...
1503
1504
  	INIT_LIST_HEAD(&tbl->parms_list);
  	list_add(&tbl->parms.list, &tbl->parms_list);
e42ea986e   Eric Dumazet   net: Cleanup of n...
1505
  	write_pnet(&tbl->parms.net, &init_net);
6343944bc   Reshetova, Elena   net: convert neig...
1506
  	refcount_set(&tbl->parms.refcnt, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1507
  	tbl->parms.reachable_time =
1f9248e56   Jiri Pirko   neigh: convert pa...
1508
  			  neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1509

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1510
1511
1512
  	tbl->stats = alloc_percpu(struct neigh_statistics);
  	if (!tbl->stats)
  		panic("cannot create neighbour cache statistics");
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1513

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1514
  #ifdef CONFIG_PROC_FS
9b739ba5e   Alexey Dobriyan   net: remove struc...
1515
1516
  	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
1517
  		panic("cannot create neighbour proc dir entry");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1518
  #endif
cd0893369   David S. Miller   neigh: Store hash...
1519
  	RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1520
1521
  
  	phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *);
77d04bd95   Andrew Morton   [NET]: More kzall...
1522
  	tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1523

d6bf78171   Eric Dumazet   net neigh: RCU co...
1524
  	if (!tbl->nht || !tbl->phash_buckets)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1525
  		panic("cannot allocate neighbour cache hashes");
08433eff2   YOSHIFUJI Hideaki / 吉藤英明   net neigh: Optimi...
1526
1527
1528
1529
1530
  	if (!tbl->entry_size)
  		tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) +
  					tbl->key_len, NEIGH_PRIV_ALIGN);
  	else
  		WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1531
  	rwlock_init(&tbl->lock);
203b42f73   Tejun Heo   workqueue: make d...
1532
  	INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
f618002b0   viresh kumar   net/neighbour: qu...
1533
1534
  	queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,
  			tbl->parms.reachable_time);
b24b8a247   Pavel Emelyanov   [NET]: Convert in...
1535
  	setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl);
c2ecba717   Pavel Emelianov   [NET]: Set a sepa...
1536
1537
  	skb_queue_head_init_class(&tbl->proxy_queue,
  			&neigh_table_proxy_queue_class);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1538
1539
1540
  
  	tbl->last_flush = now;
  	tbl->last_rand	= now + tbl->parms.reachable_time * 20;
bd89efc53   Simon Kelley   [NEIGH]: Fix IP-o...
1541

d7480fd3b   WANG Cong   neigh: remove dyn...
1542
  	neigh_tables[index] = tbl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1543
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1544
  EXPORT_SYMBOL(neigh_table_init);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1545

d7480fd3b   WANG Cong   neigh: remove dyn...
1546
  int neigh_table_clear(int index, struct neigh_table *tbl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1547
  {
d7480fd3b   WANG Cong   neigh: remove dyn...
1548
  	neigh_tables[index] = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1549
  	/* It is not clean... Fix it to unload IPv6 module safely */
a5c30b349   Tejun Heo   net/neighbour: ca...
1550
  	cancel_delayed_work_sync(&tbl->gc_work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1551
1552
1553
1554
  	del_timer_sync(&tbl->proxy_timer);
  	pneigh_queue_purge(&tbl->proxy_queue);
  	neigh_ifdown(tbl, NULL);
  	if (atomic_read(&tbl->entries))
e005d193d   Joe Perches   net: core: Use pr...
1555
1556
  		pr_crit("neighbour leakage
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1557

6193d2be2   Eric Dumazet   neigh: __rcu anno...
1558
1559
  	call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu,
  		 neigh_hash_free_rcu);
d6bf78171   Eric Dumazet   net neigh: RCU co...
1560
  	tbl->nht = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1561
1562
1563
  
  	kfree(tbl->phash_buckets);
  	tbl->phash_buckets = NULL;
3f192b5c5   Alexey Dobriyan   [NET]: Remove /pr...
1564
  	remove_proc_entry(tbl->id, init_net.proc_net_stat);
3fcde74b3   Kirill Korotaev   [NEIGH]: neigh_ta...
1565
1566
  	free_percpu(tbl->stats);
  	tbl->stats = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1567
1568
  	return 0;
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
1569
  EXPORT_SYMBOL(neigh_table_clear);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1570

d7480fd3b   WANG Cong   neigh: remove dyn...
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
  static struct neigh_table *neigh_find_table(int family)
  {
  	struct neigh_table *tbl = NULL;
  
  	switch (family) {
  	case AF_INET:
  		tbl = neigh_tables[NEIGH_ARP_TABLE];
  		break;
  	case AF_INET6:
  		tbl = neigh_tables[NEIGH_ND_TABLE];
  		break;
  	case AF_DECnet:
  		tbl = neigh_tables[NEIGH_DN_TABLE];
  		break;
  	}
  
  	return tbl;
  }
c21ef3e34   David Ahern   net: rtnetlink: p...
1589
1590
  static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
  			struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1591
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1592
  	struct net *net = sock_net(skb->sk);
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1593
1594
  	struct ndmsg *ndm;
  	struct nlattr *dst_attr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1595
  	struct neigh_table *tbl;
d7480fd3b   WANG Cong   neigh: remove dyn...
1596
  	struct neighbour *neigh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1597
  	struct net_device *dev = NULL;
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1598
  	int err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1599

110b24993   Eric Dumazet   net neigh: neigh_...
1600
  	ASSERT_RTNL();
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1601
  	if (nlmsg_len(nlh) < sizeof(*ndm))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1602
  		goto out;
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1603
1604
1605
1606
1607
1608
  	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_...
1609
  		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1610
1611
1612
1613
1614
  		if (dev == NULL) {
  			err = -ENODEV;
  			goto out;
  		}
  	}
d7480fd3b   WANG Cong   neigh: remove dyn...
1615
1616
1617
  	tbl = neigh_find_table(ndm->ndm_family);
  	if (tbl == NULL)
  		return -EAFNOSUPPORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1618

d7480fd3b   WANG Cong   neigh: remove dyn...
1619
1620
  	if (nla_len(dst_attr) < tbl->key_len)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1621

d7480fd3b   WANG Cong   neigh: remove dyn...
1622
1623
1624
1625
  	if (ndm->ndm_flags & NTF_PROXY) {
  		err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1626

d7480fd3b   WANG Cong   neigh: remove dyn...
1627
1628
  	if (dev == NULL)
  		goto out;
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1629

d7480fd3b   WANG Cong   neigh: remove dyn...
1630
1631
1632
  	neigh = neigh_lookup(tbl, nla_data(dst_attr), dev);
  	if (neigh == NULL) {
  		err = -ENOENT;
110b24993   Eric Dumazet   net neigh: neigh_...
1633
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1634
  	}
d7480fd3b   WANG Cong   neigh: remove dyn...
1635
1636
1637
  
  	err = neigh_update(neigh, NULL, NUD_FAILED,
  			   NEIGH_UPDATE_F_OVERRIDE |
7b8f7a402   Roopa Prabhu   neighbour: fix nl...
1638
1639
  			   NEIGH_UPDATE_F_ADMIN,
  			   NETLINK_CB(skb).portid);
5071034e4   Sowmini Varadhan   neigh: Really del...
1640
  	write_lock_bh(&tbl->lock);
d7480fd3b   WANG Cong   neigh: remove dyn...
1641
  	neigh_release(neigh);
5071034e4   Sowmini Varadhan   neigh: Really del...
1642
1643
  	neigh_remove_one(neigh, tbl);
  	write_unlock_bh(&tbl->lock);
a14a49d2b   Thomas Graf   [NEIGH]: Convert ...
1644

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1645
1646
1647
  out:
  	return err;
  }
c21ef3e34   David Ahern   net: rtnetlink: p...
1648
1649
  static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
  		     struct netlink_ext_ack *extack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1650
  {
d7480fd3b   WANG Cong   neigh: remove dyn...
1651
  	int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1652
  	struct net *net = sock_net(skb->sk);
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1653
1654
  	struct ndmsg *ndm;
  	struct nlattr *tb[NDA_MAX+1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1655
1656
  	struct neigh_table *tbl;
  	struct net_device *dev = NULL;
d7480fd3b   WANG Cong   neigh: remove dyn...
1657
1658
  	struct neighbour *neigh;
  	void *dst, *lladdr;
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1659
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1660

110b24993   Eric Dumazet   net neigh: neigh_...
1661
  	ASSERT_RTNL();
c21ef3e34   David Ahern   net: rtnetlink: p...
1662
  	err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL, extack);
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1663
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1664
  		goto out;
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1665
1666
1667
1668
1669
1670
  	err = -EINVAL;
  	if (tb[NDA_DST] == NULL)
  		goto out;
  
  	ndm = nlmsg_data(nlh);
  	if (ndm->ndm_ifindex) {
110b24993   Eric Dumazet   net neigh: neigh_...
1671
  		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1672
1673
1674
1675
1676
1677
  		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_...
1678
  			goto out;
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1679
  	}
d7480fd3b   WANG Cong   neigh: remove dyn...
1680
1681
1682
  	tbl = neigh_find_table(ndm->ndm_family);
  	if (tbl == NULL)
  		return -EAFNOSUPPORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1683

d7480fd3b   WANG Cong   neigh: remove dyn...
1684
1685
1686
1687
  	if (nla_len(tb[NDA_DST]) < tbl->key_len)
  		goto out;
  	dst = nla_data(tb[NDA_DST]);
  	lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1688

d7480fd3b   WANG Cong   neigh: remove dyn...
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
  	if (ndm->ndm_flags & NTF_PROXY) {
  		struct pneigh_entry *pn;
  
  		err = -ENOBUFS;
  		pn = pneigh_lookup(tbl, net, dst, dev, 1);
  		if (pn) {
  			pn->flags = ndm->ndm_flags;
  			err = 0;
  		}
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1700

d7480fd3b   WANG Cong   neigh: remove dyn...
1701
1702
  	if (dev == NULL)
  		goto out;
62dd93181   Ville Nuorvala   [IPV6] NDISC: Set...
1703

d7480fd3b   WANG Cong   neigh: remove dyn...
1704
1705
1706
1707
  	neigh = neigh_lookup(tbl, dst, dev);
  	if (neigh == NULL) {
  		if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
  			err = -ENOENT;
110b24993   Eric Dumazet   net neigh: neigh_...
1708
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1709
  		}
d7480fd3b   WANG Cong   neigh: remove dyn...
1710
1711
1712
1713
1714
1715
1716
1717
1718
  		neigh = __neigh_lookup_errno(tbl, dst, dev);
  		if (IS_ERR(neigh)) {
  			err = PTR_ERR(neigh);
  			goto out;
  		}
  	} else {
  		if (nlh->nlmsg_flags & NLM_F_EXCL) {
  			err = -EEXIST;
  			neigh_release(neigh);
110b24993   Eric Dumazet   net neigh: neigh_...
1719
  			goto out;
5208debd0   Thomas Graf   [NEIGH]: Convert ...
1720
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1721

d7480fd3b   WANG Cong   neigh: remove dyn...
1722
1723
  		if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
  			flags &= ~NEIGH_UPDATE_F_OVERRIDE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1724
  	}
d7480fd3b   WANG Cong   neigh: remove dyn...
1725
1726
1727
1728
  	if (ndm->ndm_flags & NTF_USE) {
  		neigh_event_send(neigh, NULL);
  		err = 0;
  	} else
7b8f7a402   Roopa Prabhu   neighbour: fix nl...
1729
1730
  		err = neigh_update(neigh, lladdr, ndm->ndm_state, flags,
  				   NETLINK_CB(skb).portid);
d7480fd3b   WANG Cong   neigh: remove dyn...
1731
  	neigh_release(neigh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1732
1733
1734
  out:
  	return err;
  }
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1735
1736
  static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
  {
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1737
1738
1739
1740
1741
  	struct nlattr *nest;
  
  	nest = nla_nest_start(skb, NDTA_PARMS);
  	if (nest == NULL)
  		return -ENOBUFS;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1742

9a6308d74   David S. Miller   neighbour: Stop u...
1743
1744
  	if ((parms->dev &&
  	     nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
6343944bc   Reshetova, Elena   net: convert neig...
1745
  	    nla_put_u32(skb, NDTPA_REFCNT, refcount_read(&parms->refcnt)) ||
1f9248e56   Jiri Pirko   neigh: convert pa...
1746
1747
  	    nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
  			NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
9a6308d74   David S. Miller   neighbour: Stop u...
1748
1749
  	    /* approximative value for deprecated QUEUE_LEN (in packets) */
  	    nla_put_u32(skb, NDTPA_QUEUE_LEN,
1f9248e56   Jiri Pirko   neigh: convert pa...
1750
1751
1752
1753
1754
1755
1756
  			NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) ||
  	    nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) ||
  	    nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) ||
  	    nla_put_u32(skb, NDTPA_UCAST_PROBES,
  			NEIGH_VAR(parms, UCAST_PROBES)) ||
  	    nla_put_u32(skb, NDTPA_MCAST_PROBES,
  			NEIGH_VAR(parms, MCAST_PROBES)) ||
8da86466b   YOSHIFUJI Hideaki/吉藤英明   net: neighbour: A...
1757
1758
  	    nla_put_u32(skb, NDTPA_MCAST_REPROBES,
  			NEIGH_VAR(parms, MCAST_REPROBES)) ||
2175d87cc   Nicolas Dichtel   libnl: nla_put_ms...
1759
1760
  	    nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time,
  			  NDTPA_PAD) ||
9a6308d74   David S. Miller   neighbour: Stop u...
1761
  	    nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME,
2175d87cc   Nicolas Dichtel   libnl: nla_put_ms...
1762
  			  NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) ||
1f9248e56   Jiri Pirko   neigh: convert pa...
1763
  	    nla_put_msecs(skb, NDTPA_GC_STALETIME,
2175d87cc   Nicolas Dichtel   libnl: nla_put_ms...
1764
  			  NEIGH_VAR(parms, GC_STALETIME), NDTPA_PAD) ||
9a6308d74   David S. Miller   neighbour: Stop u...
1765
  	    nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME,
2175d87cc   Nicolas Dichtel   libnl: nla_put_ms...
1766
  			  NEIGH_VAR(parms, DELAY_PROBE_TIME), NDTPA_PAD) ||
1f9248e56   Jiri Pirko   neigh: convert pa...
1767
  	    nla_put_msecs(skb, NDTPA_RETRANS_TIME,
2175d87cc   Nicolas Dichtel   libnl: nla_put_ms...
1768
  			  NEIGH_VAR(parms, RETRANS_TIME), NDTPA_PAD) ||
1f9248e56   Jiri Pirko   neigh: convert pa...
1769
  	    nla_put_msecs(skb, NDTPA_ANYCAST_DELAY,
2175d87cc   Nicolas Dichtel   libnl: nla_put_ms...
1770
  			  NEIGH_VAR(parms, ANYCAST_DELAY), NDTPA_PAD) ||
1f9248e56   Jiri Pirko   neigh: convert pa...
1771
  	    nla_put_msecs(skb, NDTPA_PROXY_DELAY,
2175d87cc   Nicolas Dichtel   libnl: nla_put_ms...
1772
  			  NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) ||
1f9248e56   Jiri Pirko   neigh: convert pa...
1773
  	    nla_put_msecs(skb, NDTPA_LOCKTIME,
2175d87cc   Nicolas Dichtel   libnl: nla_put_ms...
1774
  			  NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD))
9a6308d74   David S. Miller   neighbour: Stop u...
1775
  		goto nla_put_failure;
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1776
  	return nla_nest_end(skb, nest);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1777

ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1778
  nla_put_failure:
bc3ed28ca   Thomas Graf   netlink: Improve ...
1779
1780
  	nla_nest_cancel(skb, nest);
  	return -EMSGSIZE;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1781
  }
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1782
1783
  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...
1784
1785
1786
  {
  	struct nlmsghdr *nlh;
  	struct ndtmsg *ndtmsg;
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1787
1788
  	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
  	if (nlh == NULL)
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1789
  		return -EMSGSIZE;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1790

ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1791
  	ndtmsg = nlmsg_data(nlh);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1792
1793
1794
  
  	read_lock_bh(&tbl->lock);
  	ndtmsg->ndtm_family = tbl->family;
9ef1d4c7c   Patrick McHardy   [NETLINK]: Missin...
1795
1796
  	ndtmsg->ndtm_pad1   = 0;
  	ndtmsg->ndtm_pad2   = 0;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1797

9a6308d74   David S. Miller   neighbour: Stop u...
1798
  	if (nla_put_string(skb, NDTA_NAME, tbl->id) ||
2175d87cc   Nicolas Dichtel   libnl: nla_put_ms...
1799
  	    nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval, NDTA_PAD) ||
9a6308d74   David S. Miller   neighbour: Stop u...
1800
1801
1802
1803
  	    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))
  		goto nla_put_failure;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1804
1805
1806
1807
  	{
  		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...
1808
  		struct neigh_hash_table *nht;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1809
1810
1811
1812
1813
1814
  		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...
1815
1816
  			.ndtc_proxy_qlen	= tbl->proxy_queue.qlen,
  		};
d6bf78171   Eric Dumazet   net neigh: RCU co...
1817
1818
  		rcu_read_lock_bh();
  		nht = rcu_dereference_bh(tbl->nht);
2c2aba6c5   David S. Miller   ipv6: Use univers...
1819
  		ndc.ndtc_hash_rnd = nht->hash_rnd[0];
cd0893369   David S. Miller   neigh: Store hash...
1820
  		ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1);
d6bf78171   Eric Dumazet   net neigh: RCU co...
1821
  		rcu_read_unlock_bh();
9a6308d74   David S. Miller   neighbour: Stop u...
1822
1823
  		if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc))
  			goto nla_put_failure;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1824
1825
1826
1827
1828
1829
1830
  	}
  
  	{
  		int cpu;
  		struct ndt_stats ndst;
  
  		memset(&ndst, 0, sizeof(ndst));
6f9120422   KAMEZAWA Hiroyuki   [PATCH] for_each_...
1831
  		for_each_possible_cpu(cpu) {
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1832
  			struct neigh_statistics	*st;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
  			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;
fb811395c   Rick Jones   net: add explicit...
1844
  			ndst.ndts_table_fulls		+= st->table_fulls;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1845
  		}
b676338fb   Nicolas Dichtel   neigh: align nlat...
1846
1847
  		if (nla_put_64bit(skb, NDTA_STATS, sizeof(ndst), &ndst,
  				  NDTA_PAD))
9a6308d74   David S. Miller   neighbour: Stop u...
1848
  			goto nla_put_failure;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1849
1850
1851
1852
  	}
  
  	BUG_ON(tbl->parms.dev);
  	if (neightbl_fill_parms(skb, &tbl->parms) < 0)
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1853
  		goto nla_put_failure;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1854
1855
  
  	read_unlock_bh(&tbl->lock);
053c095a8   Johannes Berg   netlink: make nlm...
1856
1857
  	nlmsg_end(skb, nlh);
  	return 0;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1858

ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1859
  nla_put_failure:
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1860
  	read_unlock_bh(&tbl->lock);
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1861
1862
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1863
  }
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1864
1865
  static int neightbl_fill_param_info(struct sk_buff *skb,
  				    struct neigh_table *tbl,
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1866
  				    struct neigh_parms *parms,
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1867
1868
  				    u32 pid, u32 seq, int type,
  				    unsigned int flags)
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1869
1870
1871
  {
  	struct ndtmsg *ndtmsg;
  	struct nlmsghdr *nlh;
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1872
1873
  	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags);
  	if (nlh == NULL)
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1874
  		return -EMSGSIZE;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1875

ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1876
  	ndtmsg = nlmsg_data(nlh);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1877
1878
1879
  
  	read_lock_bh(&tbl->lock);
  	ndtmsg->ndtm_family = tbl->family;
9ef1d4c7c   Patrick McHardy   [NETLINK]: Missin...
1880
1881
  	ndtmsg->ndtm_pad1   = 0;
  	ndtmsg->ndtm_pad2   = 0;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1882

ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1883
1884
1885
  	if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 ||
  	    neightbl_fill_parms(skb, parms) < 0)
  		goto errout;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1886
1887
  
  	read_unlock_bh(&tbl->lock);
053c095a8   Johannes Berg   netlink: make nlm...
1888
1889
  	nlmsg_end(skb, nlh);
  	return 0;
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
1890
  errout:
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1891
  	read_unlock_bh(&tbl->lock);
26932566a   Patrick McHardy   [NETLINK]: Don't ...
1892
1893
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1894
  }
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1895

ef7c79ed6   Patrick McHardy   [NETLINK]: Mark n...
1896
  static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1897
1898
1899
1900
1901
1902
1903
  	[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...
1904
  static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1905
1906
1907
1908
1909
1910
  	[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 },
8da86466b   YOSHIFUJI Hideaki/吉藤英明   net: neighbour: A...
1911
  	[NDTPA_MCAST_REPROBES]		= { .type = NLA_U32 },
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1912
1913
1914
1915
1916
1917
1918
1919
  	[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 },
  };
c21ef3e34   David Ahern   net: rtnetlink: p...
1920
1921
  static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
  			struct netlink_ext_ack *extack)
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1922
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
1923
  	struct net *net = sock_net(skb->sk);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1924
  	struct neigh_table *tbl;
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1925
1926
  	struct ndtmsg *ndtmsg;
  	struct nlattr *tb[NDTA_MAX+1];
d7480fd3b   WANG Cong   neigh: remove dyn...
1927
1928
  	bool found = false;
  	int err, tidx;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1929

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1930
  	err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
c21ef3e34   David Ahern   net: rtnetlink: p...
1931
  			  nl_neightbl_policy, extack);
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1932
1933
  	if (err < 0)
  		goto errout;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1934

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1935
1936
1937
1938
1939
1940
  	if (tb[NDTA_NAME] == NULL) {
  		err = -EINVAL;
  		goto errout;
  	}
  
  	ndtmsg = nlmsg_data(nlh);
d7480fd3b   WANG Cong   neigh: remove dyn...
1941
1942
1943
1944
1945
  
  	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
  		tbl = neigh_tables[tidx];
  		if (!tbl)
  			continue;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1946
1947
  		if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
  			continue;
d7480fd3b   WANG Cong   neigh: remove dyn...
1948
1949
  		if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) {
  			found = true;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1950
  			break;
d7480fd3b   WANG Cong   neigh: remove dyn...
1951
  		}
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1952
  	}
d7480fd3b   WANG Cong   neigh: remove dyn...
1953
1954
  	if (!found)
  		return -ENOENT;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1955

4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
1956
  	/*
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1957
1958
1959
1960
  	 * 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 ...
1961
1962
  	if (tb[NDTA_PARMS]) {
  		struct nlattr *tbp[NDTPA_MAX+1];
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1963
  		struct neigh_parms *p;
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1964
  		int i, ifindex = 0;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1965

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1966
  		err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
c21ef3e34   David Ahern   net: rtnetlink: p...
1967
  				       nl_ntbl_parm_policy, extack);
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1968
1969
  		if (err < 0)
  			goto errout_tbl_lock;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1970

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1971
1972
  		if (tbp[NDTPA_IFINDEX])
  			ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1973

97fd5bc7f   Tobias Klauser   net: Rename looku...
1974
  		p = lookup_neigh_parms(tbl, net, ifindex);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1975
1976
  		if (p == NULL) {
  			err = -ENOENT;
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1977
  			goto errout_tbl_lock;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1978
  		}
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1979

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1980
1981
1982
  		for (i = 1; i <= NDTPA_MAX; i++) {
  			if (tbp[i] == NULL)
  				continue;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
1983

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1984
1985
  			switch (i) {
  			case NDTPA_QUEUE_LEN:
1f9248e56   Jiri Pirko   neigh: convert pa...
1986
1987
1988
  				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
  					      nla_get_u32(tbp[i]) *
  					      SKB_TRUESIZE(ETH_FRAME_LEN));
8b5c171bb   Eric Dumazet   neigh: new unreso...
1989
1990
  				break;
  			case NDTPA_QUEUE_LENBYTES:
1f9248e56   Jiri Pirko   neigh: convert pa...
1991
1992
  				NEIGH_VAR_SET(p, QUEUE_LEN_BYTES,
  					      nla_get_u32(tbp[i]));
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1993
1994
  				break;
  			case NDTPA_PROXY_QLEN:
1f9248e56   Jiri Pirko   neigh: convert pa...
1995
1996
  				NEIGH_VAR_SET(p, PROXY_QLEN,
  					      nla_get_u32(tbp[i]));
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
1997
1998
  				break;
  			case NDTPA_APP_PROBES:
1f9248e56   Jiri Pirko   neigh: convert pa...
1999
2000
  				NEIGH_VAR_SET(p, APP_PROBES,
  					      nla_get_u32(tbp[i]));
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2001
2002
  				break;
  			case NDTPA_UCAST_PROBES:
1f9248e56   Jiri Pirko   neigh: convert pa...
2003
2004
  				NEIGH_VAR_SET(p, UCAST_PROBES,
  					      nla_get_u32(tbp[i]));
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2005
2006
  				break;
  			case NDTPA_MCAST_PROBES:
1f9248e56   Jiri Pirko   neigh: convert pa...
2007
2008
  				NEIGH_VAR_SET(p, MCAST_PROBES,
  					      nla_get_u32(tbp[i]));
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2009
  				break;
8da86466b   YOSHIFUJI Hideaki/吉藤英明   net: neighbour: A...
2010
2011
2012
2013
  			case NDTPA_MCAST_REPROBES:
  				NEIGH_VAR_SET(p, MCAST_REPROBES,
  					      nla_get_u32(tbp[i]));
  				break;
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2014
  			case NDTPA_BASE_REACHABLE_TIME:
1f9248e56   Jiri Pirko   neigh: convert pa...
2015
2016
  				NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
  					      nla_get_msecs(tbp[i]));
4bf6980dd   Jean-Francois Remy   neighbour: fix ba...
2017
2018
2019
2020
2021
2022
  				/* update reachable_time as well, otherwise, the change will
  				 * only be effective after the next time neigh_periodic_work
  				 * decides to recompute it (can be multiple minutes)
  				 */
  				p->reachable_time =
  					neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2023
2024
  				break;
  			case NDTPA_GC_STALETIME:
1f9248e56   Jiri Pirko   neigh: convert pa...
2025
2026
  				NEIGH_VAR_SET(p, GC_STALETIME,
  					      nla_get_msecs(tbp[i]));
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2027
2028
  				break;
  			case NDTPA_DELAY_PROBE_TIME:
1f9248e56   Jiri Pirko   neigh: convert pa...
2029
2030
  				NEIGH_VAR_SET(p, DELAY_PROBE_TIME,
  					      nla_get_msecs(tbp[i]));
2a4501ae1   Ido Schimmel   neigh: Send a not...
2031
  				call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2032
2033
  				break;
  			case NDTPA_RETRANS_TIME:
1f9248e56   Jiri Pirko   neigh: convert pa...
2034
2035
  				NEIGH_VAR_SET(p, RETRANS_TIME,
  					      nla_get_msecs(tbp[i]));
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2036
2037
  				break;
  			case NDTPA_ANYCAST_DELAY:
3977458c9   Jiri Pirko   neigh: split line...
2038
2039
  				NEIGH_VAR_SET(p, ANYCAST_DELAY,
  					      nla_get_msecs(tbp[i]));
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2040
2041
  				break;
  			case NDTPA_PROXY_DELAY:
3977458c9   Jiri Pirko   neigh: split line...
2042
2043
  				NEIGH_VAR_SET(p, PROXY_DELAY,
  					      nla_get_msecs(tbp[i]));
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2044
2045
  				break;
  			case NDTPA_LOCKTIME:
3977458c9   Jiri Pirko   neigh: split line...
2046
2047
  				NEIGH_VAR_SET(p, LOCKTIME,
  					      nla_get_msecs(tbp[i]));
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2048
2049
2050
2051
  				break;
  			}
  		}
  	}
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2052

dc25c676f   Gao feng   neigh: disallow u...
2053
2054
2055
2056
2057
  	err = -ENOENT;
  	if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] ||
  	     tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) &&
  	    !net_eq(net, &init_net))
  		goto errout_tbl_lock;
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2058
2059
  	if (tb[NDTA_THRESH1])
  		tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2060

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

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

6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2067
2068
  	if (tb[NDTA_GC_INTERVAL])
  		tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]);
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2069
2070
  
  	err = 0;
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2071
  errout_tbl_lock:
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2072
  	write_unlock_bh(&tbl->lock);
6b3f8674b   Thomas Graf   [NEIGH]: Convert ...
2073
  errout:
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2074
2075
  	return err;
  }
c8822a4e0   Thomas Graf   [NEIGH]: Use rtnl...
2076
  static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2077
  {
3b1e0a655   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2078
  	struct net *net = sock_net(skb->sk);
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2079
2080
2081
  	int family, tidx, nidx = 0;
  	int tbl_skip = cb->args[0];
  	int neigh_skip = cb->args[1];
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2082
  	struct neigh_table *tbl;
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2083
  	family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2084

d7480fd3b   WANG Cong   neigh: remove dyn...
2085
  	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2086
  		struct neigh_parms *p;
d7480fd3b   WANG Cong   neigh: remove dyn...
2087
2088
2089
  		tbl = neigh_tables[tidx];
  		if (!tbl)
  			continue;
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2090
  		if (tidx < tbl_skip || (family && tbl->family != family))
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2091
  			continue;
15e473046   Eric W. Biederman   netlink: Rename p...
2092
  		if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2093
  				       cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
7b46a644a   David S. Miller   netlink: Fix bugs...
2094
  				       NLM_F_MULTI) < 0)
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2095
  			break;
75fbfd332   Nicolas Dichtel   neigh: optimize n...
2096
2097
2098
  		nidx = 0;
  		p = list_next_entry(&tbl->parms, list);
  		list_for_each_entry_from(p, &tbl->parms_list, list) {
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2099
  			if (!net_eq(neigh_parms_net(p), net))
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
2100
  				continue;
efc683fc2   Gautam Kachroo   neigh: some entri...
2101
2102
  			if (nidx < neigh_skip)
  				goto next;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2103

ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2104
  			if (neightbl_fill_param_info(skb, tbl, p,
15e473046   Eric W. Biederman   netlink: Rename p...
2105
  						     NETLINK_CB(cb->skb).portid,
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2106
2107
  						     cb->nlh->nlmsg_seq,
  						     RTM_NEWNEIGHTBL,
7b46a644a   David S. Miller   netlink: Fix bugs...
2108
  						     NLM_F_MULTI) < 0)
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2109
  				goto out;
efc683fc2   Gautam Kachroo   neigh: some entri...
2110
2111
  		next:
  			nidx++;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2112
  		}
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2113
  		neigh_skip = 0;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2114
2115
  	}
  out:
ca860fb39   Thomas Graf   [NEIGH]: Convert ...
2116
2117
  	cb->args[0] = tidx;
  	cb->args[1] = nidx;
c7fb64db0   Thomas Graf   [NETLINK]: Neighb...
2118
2119
2120
  
  	return skb->len;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2121

8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2122
2123
  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
2124
2125
  {
  	unsigned long now = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2126
  	struct nda_cacheinfo ci;
8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2127
2128
2129
2130
2131
  	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 ...
2132
  		return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2133

8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2134
2135
  	ndm = nlmsg_data(nlh);
  	ndm->ndm_family	 = neigh->ops->family;
9ef1d4c7c   Patrick McHardy   [NETLINK]: Missin...
2136
2137
  	ndm->ndm_pad1    = 0;
  	ndm->ndm_pad2    = 0;
8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2138
2139
2140
  	ndm->ndm_flags	 = neigh->flags;
  	ndm->ndm_type	 = neigh->type;
  	ndm->ndm_ifindex = neigh->dev->ifindex;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2141

9a6308d74   David S. Miller   neighbour: Stop u...
2142
2143
  	if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key))
  		goto nla_put_failure;
8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2144
2145
2146
  
  	read_lock_bh(&neigh->lock);
  	ndm->ndm_state	 = neigh->nud_state;
0ed8ddf40   Eric Dumazet   neigh: Protect ne...
2147
2148
2149
2150
2151
2152
2153
2154
  	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 ...
2155
  	}
b9f5f52cc   Stephen Hemminger   net: neighbour ta...
2156
2157
2158
  	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);
9f2374301   Reshetova, Elena   net: convert neig...
2159
  	ci.ndm_refcnt	 = refcount_read(&neigh->refcnt) - 1;
8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2160
  	read_unlock_bh(&neigh->lock);
9a6308d74   David S. Miller   neighbour: Stop u...
2161
2162
2163
  	if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
  	    nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
  		goto nla_put_failure;
8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2164

053c095a8   Johannes Berg   netlink: make nlm...
2165
2166
  	nlmsg_end(skb, nlh);
  	return 0;
8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2167
2168
  
  nla_put_failure:
26932566a   Patrick McHardy   [NETLINK]: Don't ...
2169
2170
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2171
  }
84920c142   Tony Zelenoff   net: Allow ipv6 p...
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
  static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
  			    u32 pid, u32 seq, int type, unsigned int flags,
  			    struct neigh_table *tbl)
  {
  	struct nlmsghdr *nlh;
  	struct ndmsg *ndm;
  
  	nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags);
  	if (nlh == NULL)
  		return -EMSGSIZE;
  
  	ndm = nlmsg_data(nlh);
  	ndm->ndm_family	 = tbl->family;
  	ndm->ndm_pad1    = 0;
  	ndm->ndm_pad2    = 0;
  	ndm->ndm_flags	 = pn->flags | NTF_PROXY;
545469f7a   Jun Zhao   neighbour : fix n...
2188
  	ndm->ndm_type	 = RTN_UNICAST;
6adc5fd6a   Konstantin Khlebnikov   net/neighbour: fi...
2189
  	ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0;
84920c142   Tony Zelenoff   net: Allow ipv6 p...
2190
  	ndm->ndm_state	 = NUD_NONE;
9a6308d74   David S. Miller   neighbour: Stop u...
2191
2192
  	if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
  		goto nla_put_failure;
84920c142   Tony Zelenoff   net: Allow ipv6 p...
2193

053c095a8   Johannes Berg   netlink: make nlm...
2194
2195
  	nlmsg_end(skb, nlh);
  	return 0;
84920c142   Tony Zelenoff   net: Allow ipv6 p...
2196
2197
2198
2199
2200
  
  nla_put_failure:
  	nlmsg_cancel(skb, nlh);
  	return -EMSGSIZE;
  }
7b8f7a402   Roopa Prabhu   neighbour: fix nl...
2201
  static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid)
d961db358   Thomas Graf   [NEIGH]: Netlink ...
2202
2203
  {
  	call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
7b8f7a402   Roopa Prabhu   neighbour: fix nl...
2204
  	__neigh_notify(neigh, RTM_NEWNEIGH, 0, nlmsg_pid);
d961db358   Thomas Graf   [NEIGH]: Netlink ...
2205
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2206

21fdd092a   David Ahern   net: Add support ...
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
  static bool neigh_master_filtered(struct net_device *dev, int master_idx)
  {
  	struct net_device *master;
  
  	if (!master_idx)
  		return false;
  
  	master = netdev_master_upper_dev_get(dev);
  	if (!master || master->ifindex != master_idx)
  		return true;
  
  	return false;
  }
16660f0bd   David Ahern   net: Add support ...
2220
2221
2222
2223
2224
2225
2226
  static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx)
  {
  	if (filter_idx && dev->ifindex != filter_idx)
  		return true;
  
  	return false;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2227
2228
2229
  static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
  			    struct netlink_callback *cb)
  {
767e97e1e   Eric Dumazet   neigh: RCU conver...
2230
  	struct net *net = sock_net(skb->sk);
21fdd092a   David Ahern   net: Add support ...
2231
2232
  	const struct nlmsghdr *nlh = cb->nlh;
  	struct nlattr *tb[NDA_MAX + 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2233
2234
2235
  	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...
2236
  	struct neigh_hash_table *nht;
16660f0bd   David Ahern   net: Add support ...
2237
  	int filter_master_idx = 0, filter_idx = 0;
21fdd092a   David Ahern   net: Add support ...
2238
2239
  	unsigned int flags = NLM_F_MULTI;
  	int err;
fceb6435e   Johannes Berg   netlink: pass ext...
2240
  	err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL, NULL);
21fdd092a   David Ahern   net: Add support ...
2241
  	if (!err) {
15efa7832   Eric Dumazet   net: validate att...
2242
2243
2244
  		if (tb[NDA_IFINDEX]) {
  			if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32))
  				return -EINVAL;
16660f0bd   David Ahern   net: Add support ...
2245
  			filter_idx = nla_get_u32(tb[NDA_IFINDEX]);
15efa7832   Eric Dumazet   net: validate att...
2246
2247
2248
2249
  		}
  		if (tb[NDA_MASTER]) {
  			if (nla_len(tb[NDA_MASTER]) != sizeof(u32))
  				return -EINVAL;
21fdd092a   David Ahern   net: Add support ...
2250
  			filter_master_idx = nla_get_u32(tb[NDA_MASTER]);
15efa7832   Eric Dumazet   net: validate att...
2251
  		}
16660f0bd   David Ahern   net: Add support ...
2252
  		if (filter_idx || filter_master_idx)
21fdd092a   David Ahern   net: Add support ...
2253
2254
  			flags |= NLM_F_DUMP_FILTERED;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2255

d6bf78171   Eric Dumazet   net neigh: RCU co...
2256
2257
  	rcu_read_lock_bh();
  	nht = rcu_dereference_bh(tbl->nht);
4bd6683bd   Eric Dumazet   net: neighbour: f...
2258
  	for (h = s_h; h < (1 << nht->hash_shift); h++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2259
2260
  		if (h > s_h)
  			s_idx = 0;
767e97e1e   Eric Dumazet   neigh: RCU conver...
2261
2262
2263
  		for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0;
  		     n != NULL;
  		     n = rcu_dereference_bh(n->next)) {
18502acd9   Zhang Shengju   neigh: remove dup...
2264
2265
2266
2267
  			if (idx < s_idx || !net_eq(dev_net(n->dev), net))
  				goto next;
  			if (neigh_ifindex_filtered(n->dev, filter_idx) ||
  			    neigh_master_filtered(n->dev, filter_master_idx))
efc683fc2   Gautam Kachroo   neigh: some entri...
2268
  				goto next;
15e473046   Eric W. Biederman   netlink: Rename p...
2269
  			if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2270
  					    cb->nlh->nlmsg_seq,
b6544c0b4   Jamal Hadi Salim   [NETLINK]: Correc...
2271
  					    RTM_NEWNEIGH,
21fdd092a   David Ahern   net: Add support ...
2272
  					    flags) < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2273
2274
2275
  				rc = -1;
  				goto out;
  			}
767e97e1e   Eric Dumazet   neigh: RCU conver...
2276
  next:
efc683fc2   Gautam Kachroo   neigh: some entri...
2277
  			idx++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2278
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2279
2280
2281
  	}
  	rc = skb->len;
  out:
d6bf78171   Eric Dumazet   net neigh: RCU co...
2282
  	rcu_read_unlock_bh();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2283
2284
2285
2286
  	cb->args[1] = h;
  	cb->args[2] = idx;
  	return rc;
  }
84920c142   Tony Zelenoff   net: Allow ipv6 p...
2287
2288
2289
2290
2291
2292
2293
2294
2295
  static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
  			     struct netlink_callback *cb)
  {
  	struct pneigh_entry *n;
  	struct net *net = sock_net(skb->sk);
  	int rc, h, s_h = cb->args[3];
  	int idx, s_idx = idx = cb->args[4];
  
  	read_lock_bh(&tbl->lock);
4bd6683bd   Eric Dumazet   net: neighbour: f...
2296
  	for (h = s_h; h <= PNEIGH_HASHMASK; h++) {
84920c142   Tony Zelenoff   net: Allow ipv6 p...
2297
2298
2299
  		if (h > s_h)
  			s_idx = 0;
  		for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
18502acd9   Zhang Shengju   neigh: remove dup...
2300
  			if (idx < s_idx || pneigh_net(n) != net)
84920c142   Tony Zelenoff   net: Allow ipv6 p...
2301
  				goto next;
15e473046   Eric W. Biederman   netlink: Rename p...
2302
  			if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
84920c142   Tony Zelenoff   net: Allow ipv6 p...
2303
2304
  					    cb->nlh->nlmsg_seq,
  					    RTM_NEWNEIGH,
7b46a644a   David S. Miller   netlink: Fix bugs...
2305
  					    NLM_F_MULTI, tbl) < 0) {
84920c142   Tony Zelenoff   net: Allow ipv6 p...
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
  				read_unlock_bh(&tbl->lock);
  				rc = -1;
  				goto out;
  			}
  		next:
  			idx++;
  		}
  	}
  
  	read_unlock_bh(&tbl->lock);
  	rc = skb->len;
  out:
  	cb->args[3] = h;
  	cb->args[4] = idx;
  	return rc;
  
  }
c8822a4e0   Thomas Graf   [NEIGH]: Use rtnl...
2323
  static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2324
2325
2326
  {
  	struct neigh_table *tbl;
  	int t, family, s_t;
84920c142   Tony Zelenoff   net: Allow ipv6 p...
2327
  	int proxy = 0;
4bd6683bd   Eric Dumazet   net: neighbour: f...
2328
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2329

8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2330
  	family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
84920c142   Tony Zelenoff   net: Allow ipv6 p...
2331
2332
2333
2334
2335
2336
2337
  
  	/* check for full ndmsg structure presence, family member is
  	 * the same for both structures
  	 */
  	if (nlmsg_len(cb->nlh) >= sizeof(struct ndmsg) &&
  	    ((struct ndmsg *) nlmsg_data(cb->nlh))->ndm_flags == NTF_PROXY)
  		proxy = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2338
  	s_t = cb->args[0];
d7480fd3b   WANG Cong   neigh: remove dyn...
2339
2340
2341
2342
2343
  	for (t = 0; t < NEIGH_NR_TABLES; t++) {
  		tbl = neigh_tables[t];
  
  		if (!tbl)
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2344
2345
2346
2347
2348
  		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]));
84920c142   Tony Zelenoff   net: Allow ipv6 p...
2349
2350
2351
2352
  		if (proxy)
  			err = pneigh_dump_table(tbl, skb, cb);
  		else
  			err = neigh_dump_table(tbl, skb, cb);
4bd6683bd   Eric Dumazet   net: neighbour: f...
2353
2354
  		if (err < 0)
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2355
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2356
2357
2358
2359
2360
2361
2362
2363
  
  	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...
2364
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2365

d6bf78171   Eric Dumazet   net neigh: RCU co...
2366
2367
  	rcu_read_lock_bh();
  	nht = rcu_dereference_bh(tbl->nht);
767e97e1e   Eric Dumazet   neigh: RCU conver...
2368
  	read_lock(&tbl->lock); /* avoid resizes */
cd0893369   David S. Miller   neigh: Store hash...
2369
  	for (chain = 0; chain < (1 << nht->hash_shift); chain++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2370
  		struct neighbour *n;
767e97e1e   Eric Dumazet   neigh: RCU conver...
2371
2372
2373
  		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
2374
2375
  			cb(n, cookie);
  	}
d6bf78171   Eric Dumazet   net neigh: RCU co...
2376
2377
  	read_unlock(&tbl->lock);
  	rcu_read_unlock_bh();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2378
2379
2380
2381
2382
2383
2384
2385
  }
  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...
2386
  	struct neigh_hash_table *nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2387

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

d6bf78171   Eric Dumazet   net neigh: RCU co...
2394
  		np = &nht->hash_buckets[chain];
767e97e1e   Eric Dumazet   neigh: RCU conver...
2395
2396
  		while ((n = rcu_dereference_protected(*np,
  					lockdep_is_held(&tbl->lock))) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2397
2398
2399
2400
2401
  			int release;
  
  			write_lock(&n->lock);
  			release = cb(n);
  			if (release) {
767e97e1e   Eric Dumazet   neigh: RCU conver...
2402
2403
2404
  				rcu_assign_pointer(*np,
  					rcu_dereference_protected(n->next,
  						lockdep_is_held(&tbl->lock)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2405
2406
2407
2408
  				n->dead = 1;
  			} else
  				np = &n->next;
  			write_unlock(&n->lock);
4f494554f   Thomas Graf   [NEIGH]: Combine ...
2409
2410
  			if (release)
  				neigh_cleanup_and_release(n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2411
2412
2413
2414
  		}
  	}
  }
  EXPORT_SYMBOL(__neigh_for_each_release);
b79bda3d3   Eric W. Biederman   neigh: Use neigh ...
2415
  int neigh_xmit(int index, struct net_device *dev,
4fd3d7d9e   Eric W. Biederman   neigh: Add helper...
2416
2417
  	       const void *addr, struct sk_buff *skb)
  {
b79bda3d3   Eric W. Biederman   neigh: Use neigh ...
2418
2419
  	int err = -EAFNOSUPPORT;
  	if (likely(index < NEIGH_NR_TABLES)) {
4fd3d7d9e   Eric W. Biederman   neigh: Add helper...
2420
2421
  		struct neigh_table *tbl;
  		struct neighbour *neigh;
b79bda3d3   Eric W. Biederman   neigh: Use neigh ...
2422
  		tbl = neigh_tables[index];
4fd3d7d9e   Eric W. Biederman   neigh: Add helper...
2423
2424
  		if (!tbl)
  			goto out;
b560f03dd   David Barroso   neigh: Explicitly...
2425
  		rcu_read_lock_bh();
4fd3d7d9e   Eric W. Biederman   neigh: Add helper...
2426
2427
2428
2429
  		neigh = __neigh_lookup_noref(tbl, addr, dev);
  		if (!neigh)
  			neigh = __neigh_create(tbl, addr, dev, false);
  		err = PTR_ERR(neigh);
b560f03dd   David Barroso   neigh: Explicitly...
2430
2431
  		if (IS_ERR(neigh)) {
  			rcu_read_unlock_bh();
4fd3d7d9e   Eric W. Biederman   neigh: Add helper...
2432
  			goto out_kfree_skb;
b560f03dd   David Barroso   neigh: Explicitly...
2433
  		}
4fd3d7d9e   Eric W. Biederman   neigh: Add helper...
2434
  		err = neigh->output(neigh, skb);
b560f03dd   David Barroso   neigh: Explicitly...
2435
  		rcu_read_unlock_bh();
4fd3d7d9e   Eric W. Biederman   neigh: Add helper...
2436
  	}
b79bda3d3   Eric W. Biederman   neigh: Use neigh ...
2437
2438
2439
2440
2441
2442
2443
  	else if (index == NEIGH_LINK_TABLE) {
  		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
  				      addr, NULL, skb->len);
  		if (err < 0)
  			goto out_kfree_skb;
  		err = dev_queue_xmit(skb);
  	}
4fd3d7d9e   Eric W. Biederman   neigh: Add helper...
2444
2445
2446
2447
2448
2449
2450
  out:
  	return err;
  out_kfree_skb:
  	kfree_skb(skb);
  	goto out;
  }
  EXPORT_SYMBOL(neigh_xmit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2451
2452
2453
2454
2455
  #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...
2456
  	struct net *net = seq_file_net(seq);
d6bf78171   Eric Dumazet   net neigh: RCU co...
2457
  	struct neigh_hash_table *nht = state->nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2458
2459
2460
2461
  	struct neighbour *n = NULL;
  	int bucket = state->bucket;
  
  	state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
cd0893369   David S. Miller   neigh: Store hash...
2462
  	for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
767e97e1e   Eric Dumazet   neigh: RCU conver...
2463
  		n = rcu_dereference_bh(nht->hash_buckets[bucket]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2464
2465
  
  		while (n) {
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2466
  			if (!net_eq(dev_net(n->dev), net))
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
2467
  				goto next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
  			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...
2480
2481
  next:
  			n = rcu_dereference_bh(n->next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
  		}
  
  		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...
2497
  	struct net *net = seq_file_net(seq);
d6bf78171   Eric Dumazet   net neigh: RCU co...
2498
  	struct neigh_hash_table *nht = state->nht;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2499
2500
2501
2502
2503
2504
  
  	if (state->neigh_sub_iter) {
  		void *v = state->neigh_sub_iter(state, n, pos);
  		if (v)
  			return n;
  	}
767e97e1e   Eric Dumazet   neigh: RCU conver...
2505
  	n = rcu_dereference_bh(n->next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2506
2507
2508
  
  	while (1) {
  		while (n) {
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2509
  			if (!net_eq(dev_net(n->dev), net))
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
2510
  				goto next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
  			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...
2522
2523
  next:
  			n = rcu_dereference_bh(n->next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2524
2525
2526
2527
  		}
  
  		if (n)
  			break;
cd0893369   David S. Miller   neigh: Store hash...
2528
  		if (++state->bucket >= (1 << nht->hash_shift))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2529
  			break;
767e97e1e   Eric Dumazet   neigh: RCU conver...
2530
  		n = rcu_dereference_bh(nht->hash_buckets[state->bucket]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
  	}
  
  	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 ...
2543
  		--(*pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
  		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...
2556
  	struct net *net = seq_file_net(seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2557
2558
2559
2560
2561
2562
2563
  	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...
2564
  		while (pn && !net_eq(pneigh_net(pn), net))
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
2565
  			pn = pn->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
  		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...
2579
  	struct net *net = seq_file_net(seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2580
  	struct neigh_table *tbl = state->tbl;
df07a94cf   Jorge Boncompte [DTI2]   netns: fix proxy ...
2581
2582
2583
  	do {
  		pn = pn->next;
  	} while (pn && !net_eq(pneigh_net(pn), net));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2584
2585
2586
2587
  	while (!pn) {
  		if (++state->bucket > PNEIGH_HASHMASK)
  			break;
  		pn = tbl->phash_buckets[state->bucket];
878628fbf   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2588
  		while (pn && !net_eq(pneigh_net(pn), net))
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
2589
  			pn = pn->next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
  		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 ...
2605
  		--(*pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
  		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 ...
2619
  	loff_t idxpos = *pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2620

745e20316   Chris Larson   net: fix missing ...
2621
  	rc = neigh_get_idx(seq, &idxpos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2622
  	if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY))
745e20316   Chris Larson   net: fix missing ...
2623
  		rc = pneigh_get_idx(seq, &idxpos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2624
2625
2626
2627
2628
  
  	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...
2629
  	__acquires(rcu_bh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2630
2631
  {
  	struct neigh_seq_state *state = seq->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2632
2633
2634
2635
  
  	state->tbl = tbl;
  	state->bucket = 0;
  	state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH);
d6bf78171   Eric Dumazet   net neigh: RCU co...
2636
2637
  	rcu_read_lock_bh();
  	state->nht = rcu_dereference_bh(tbl->nht);
767e97e1e   Eric Dumazet   neigh: RCU conver...
2638

745e20316   Chris Larson   net: fix missing ...
2639
  	return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2640
2641
2642
2643
2644
2645
2646
2647
2648
  }
  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...
2649
  		rc = neigh_get_first(seq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
  		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...
2671
  	__releases(rcu_bh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2672
  {
d6bf78171   Eric Dumazet   net neigh: RCU co...
2673
  	rcu_read_unlock_bh();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2674
2675
2676
2677
2678
2679
2680
  }
  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...
2681
  	struct neigh_table *tbl = seq->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2682
2683
2684
2685
  	int cpu;
  
  	if (*pos == 0)
  		return SEQ_START_TOKEN;
4ec93edb1   YOSHIFUJI Hideaki   [NET] CORE: Fix w...
2686

0f23174aa   Rusty Russell   cpumask: prepare ...
2687
  	for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
  		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...
2698
  	struct neigh_table *tbl = seq->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2699
  	int cpu;
0f23174aa   Rusty Russell   cpumask: prepare ...
2700
  	for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
  		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...
2716
  	struct neigh_table *tbl = seq->private;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2717
2718
2719
  	struct neigh_statistics *st = v;
  
  	if (v == SEQ_START_TOKEN) {
fb811395c   Rick Jones   net: add explicit...
2720
2721
  		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 table_fulls
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2722
2723
2724
2725
  		return 0;
  	}
  
  	seq_printf(seq, "%08x  %08lx %08lx %08lx  %08lx %08lx  %08lx  "
fb811395c   Rick Jones   net: add explicit...
2726
2727
  			"%08lx %08lx  %08lx %08lx %08lx %08lx
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
  		   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...
2743
  		   st->forced_gc_runs,
fb811395c   Rick Jones   net: add explicit...
2744
2745
  		   st->unres_discards,
  		   st->table_fulls
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2746
2747
2748
2749
  		   );
  
  	return 0;
  }
f690808e1   Stephen Hemminger   [NET]: make seq_o...
2750
  static const struct seq_operations neigh_stat_seq_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
  	.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;
d9dda78ba   Al Viro   procfs: new helpe...
2763
  		sf->private = PDE_DATA(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2764
2765
2766
  	}
  	return ret;
  };
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
2767
  static const struct file_operations neigh_stat_seq_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2768
2769
2770
2771
2772
2773
2774
2775
  	.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...
2776
2777
2778
2779
2780
2781
2782
2783
  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 */
  }
7b8f7a402   Roopa Prabhu   neighbour: fix nl...
2784
2785
  static void __neigh_notify(struct neighbour *n, int type, int flags,
  			   u32 pid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2786
  {
c346dca10   YOSHIFUJI Hideaki   [NET] NETNS: Omit...
2787
  	struct net *net = dev_net(n->dev);
8b8aec508   Thomas Graf   [NEIGH]: Convert ...
2788
  	struct sk_buff *skb;
b86733118   Thomas Graf   [NEIGH]: Convert ...
2789
  	int err = -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2790

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

7b8f7a402   Roopa Prabhu   neighbour: fix nl...
2795
  	err = neigh_fill_info(skb, n, pid, 0, type, flags);
26932566a   Patrick McHardy   [NETLINK]: Don't ...
2796
2797
2798
2799
2800
2801
  	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...
2802
2803
  	rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
  	return;
b86733118   Thomas Graf   [NEIGH]: Convert ...
2804
2805
  errout:
  	if (err < 0)
426b5303e   Eric W. Biederman   [NETNS]: Modify t...
2806
  		rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2807
  }
b86733118   Thomas Graf   [NEIGH]: Convert ...
2808
  void neigh_app_ns(struct neighbour *n)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2809
  {
7b8f7a402   Roopa Prabhu   neighbour: fix nl...
2810
  	__neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST, 0);
b86733118   Thomas Graf   [NEIGH]: Convert ...
2811
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
2812
  EXPORT_SYMBOL(neigh_app_ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2813
2814
  
  #ifdef CONFIG_SYSCTL
b93196dc5   Cong Wang   net: fix some com...
2815
  static int zero;
555445cd1   Francesco Fusco   neigh: prevent ov...
2816
  static int int_max = INT_MAX;
b93196dc5   Cong Wang   net: fix some com...
2817
  static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2818

fe2c6338f   Joe Perches   net: Convert uses...
2819
2820
  static int proc_unres_qlen(struct ctl_table *ctl, int write,
  			   void __user *buffer, size_t *lenp, loff_t *ppos)
8b5c171bb   Eric Dumazet   neigh: new unreso...
2821
2822
  {
  	int size, ret;
fe2c6338f   Joe Perches   net: Convert uses...
2823
  	struct ctl_table tmp = *ctl;
8b5c171bb   Eric Dumazet   neigh: new unreso...
2824

ce46cc64d   Shan Wei   net: neighbour: p...
2825
2826
  	tmp.extra1 = &zero;
  	tmp.extra2 = &unres_qlen_max;
8b5c171bb   Eric Dumazet   neigh: new unreso...
2827
  	tmp.data = &size;
ce46cc64d   Shan Wei   net: neighbour: p...
2828
2829
2830
  
  	size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN);
  	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
8b5c171bb   Eric Dumazet   neigh: new unreso...
2831
2832
2833
2834
  	if (write && !ret)
  		*(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN);
  	return ret;
  }
1d4c8c298   Jiri Pirko   neigh: restore ol...
2835
2836
2837
  static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
  						   int family)
  {
bba24896f   Jiri Pirko   neigh: ipv6: resp...
2838
2839
  	switch (family) {
  	case AF_INET:
1d4c8c298   Jiri Pirko   neigh: restore ol...
2840
  		return __in_dev_arp_parms_get_rcu(dev);
bba24896f   Jiri Pirko   neigh: ipv6: resp...
2841
2842
2843
  	case AF_INET6:
  		return __in6_dev_nd_parms_get_rcu(dev);
  	}
1d4c8c298   Jiri Pirko   neigh: restore ol...
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
  	return NULL;
  }
  
  static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
  				  int index)
  {
  	struct net_device *dev;
  	int family = neigh_parms_family(p);
  
  	rcu_read_lock();
  	for_each_netdev_rcu(net, dev) {
  		struct neigh_parms *dst_p =
  				neigh_get_dev_parms_rcu(dev, family);
  
  		if (dst_p && !test_bit(index, dst_p->data_state))
  			dst_p->data[index] = p->data[index];
  	}
  	rcu_read_unlock();
  }
  
  static void neigh_proc_update(struct ctl_table *ctl, int write)
  {
  	struct net_device *dev = ctl->extra1;
  	struct neigh_parms *p = ctl->extra2;
77d47afbf   Jiri Pirko   neigh: use neigh_...
2868
  	struct net *net = neigh_parms_net(p);
1d4c8c298   Jiri Pirko   neigh: restore ol...
2869
2870
2871
2872
2873
2874
  	int index = (int *) ctl->data - p->data;
  
  	if (!write)
  		return;
  
  	set_bit(index, p->data_state);
7627ae603   Marcus Huewe   net: neigh: Fix n...
2875
2876
  	if (index == NEIGH_VAR_DELAY_PROBE_TIME)
  		call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p);
1d4c8c298   Jiri Pirko   neigh: restore ol...
2877
2878
2879
  	if (!dev) /* NULL dev means this is default value */
  		neigh_copy_dflt_parms(net, p, index);
  }
1f9248e56   Jiri Pirko   neigh: convert pa...
2880
2881
2882
2883
2884
  static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
  					   void __user *buffer,
  					   size_t *lenp, loff_t *ppos)
  {
  	struct ctl_table tmp = *ctl;
1d4c8c298   Jiri Pirko   neigh: restore ol...
2885
  	int ret;
1f9248e56   Jiri Pirko   neigh: convert pa...
2886
2887
2888
  
  	tmp.extra1 = &zero;
  	tmp.extra2 = &int_max;
1d4c8c298   Jiri Pirko   neigh: restore ol...
2889
2890
2891
  	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
  	neigh_proc_update(ctl, write);
  	return ret;
1f9248e56   Jiri Pirko   neigh: convert pa...
2892
  }
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
2893
2894
2895
  int neigh_proc_dointvec(struct ctl_table *ctl, int write,
  			void __user *buffer, size_t *lenp, loff_t *ppos)
  {
1d4c8c298   Jiri Pirko   neigh: restore ol...
2896
2897
2898
2899
  	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
  
  	neigh_proc_update(ctl, write);
  	return ret;
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
2900
2901
2902
2903
2904
2905
2906
  }
  EXPORT_SYMBOL(neigh_proc_dointvec);
  
  int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write,
  				void __user *buffer,
  				size_t *lenp, loff_t *ppos)
  {
1d4c8c298   Jiri Pirko   neigh: restore ol...
2907
2908
2909
2910
  	int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
  
  	neigh_proc_update(ctl, write);
  	return ret;
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
2911
2912
2913
2914
2915
2916
2917
  }
  EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
  
  static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
  					      void __user *buffer,
  					      size_t *lenp, loff_t *ppos)
  {
1d4c8c298   Jiri Pirko   neigh: restore ol...
2918
2919
2920
2921
  	int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
  
  	neigh_proc_update(ctl, write);
  	return ret;
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
2922
2923
2924
2925
2926
2927
  }
  
  int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
  				   void __user *buffer,
  				   size_t *lenp, loff_t *ppos)
  {
1d4c8c298   Jiri Pirko   neigh: restore ol...
2928
2929
2930
2931
  	int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
  
  	neigh_proc_update(ctl, write);
  	return ret;
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
2932
2933
2934
2935
2936
2937
2938
  }
  EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
  
  static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
  					  void __user *buffer,
  					  size_t *lenp, loff_t *ppos)
  {
1d4c8c298   Jiri Pirko   neigh: restore ol...
2939
2940
2941
2942
  	int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
  
  	neigh_proc_update(ctl, write);
  	return ret;
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
2943
  }
4bf6980dd   Jean-Francois Remy   neighbour: fix ba...
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
  static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
  					  void __user *buffer,
  					  size_t *lenp, loff_t *ppos)
  {
  	struct neigh_parms *p = ctl->extra2;
  	int ret;
  
  	if (strcmp(ctl->procname, "base_reachable_time") == 0)
  		ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
  	else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0)
  		ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
  	else
  		ret = -1;
  
  	if (write && ret == 0) {
  		/* update reachable_time as well, otherwise, the change will
  		 * only be effective after the next time neigh_periodic_work
  		 * decides to recompute it
  		 */
  		p->reachable_time =
  			neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
  	}
  	return ret;
  }
1f9248e56   Jiri Pirko   neigh: convert pa...
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
  #define NEIGH_PARMS_DATA_OFFSET(index)	\
  	(&((struct neigh_parms *) 0)->data[index])
  
  #define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \
  	[NEIGH_VAR_ ## attr] = { \
  		.procname	= name, \
  		.data		= NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \
  		.maxlen		= sizeof(int), \
  		.mode		= mval, \
  		.proc_handler	= proc, \
  	}
  
  #define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \
  	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax)
  
  #define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
2984
  	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies)
1f9248e56   Jiri Pirko   neigh: convert pa...
2985
2986
  
  #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
2987
  	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
1f9248e56   Jiri Pirko   neigh: convert pa...
2988
2989
  
  #define NEIGH_SYSCTL_MS_JIFFIES_ENTRY(attr, name) \
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
2990
  	NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
1f9248e56   Jiri Pirko   neigh: convert pa...
2991
2992
  
  #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
2993
  	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
1f9248e56   Jiri Pirko   neigh: convert pa...
2994
2995
  
  #define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
2996
  	NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen)
54716e3be   Eric W. Biederman   net neigh: Decoup...
2997

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2998
2999
  static struct neigh_sysctl_table {
  	struct ctl_table_header *sysctl_header;
8b5c171bb   Eric Dumazet   neigh: new unreso...
3000
  	struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1];
ab32ea5d8   Brian Haley   [NET/IPV4/IPV6]: ...
3001
  } neigh_sysctl_template __read_mostly = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3002
  	.neigh_vars = {
1f9248e56   Jiri Pirko   neigh: convert pa...
3003
3004
3005
  		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"),
  		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"),
  		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"),
8da86466b   YOSHIFUJI Hideaki/吉藤英明   net: neighbour: A...
3006
  		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_REPROBES, "mcast_resolicit"),
1f9248e56   Jiri Pirko   neigh: convert pa...
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
  		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"),
  		NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"),
  		NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"),
  		NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"),
  		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"),
  		NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"),
  		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"),
  		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"),
  		NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"),
  		NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"),
  		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"),
  		NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"),
8b5c171bb   Eric Dumazet   neigh: new unreso...
3019
  		[NEIGH_VAR_GC_INTERVAL] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3020
3021
3022
  			.procname	= "gc_interval",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
6d9f239a1   Alexey Dobriyan   net: '&' redux
3023
  			.proc_handler	= proc_dointvec_jiffies,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3024
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
3025
  		[NEIGH_VAR_GC_THRESH1] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3026
3027
3028
  			.procname	= "gc_thresh1",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
555445cd1   Francesco Fusco   neigh: prevent ov...
3029
3030
3031
  			.extra1 	= &zero,
  			.extra2		= &int_max,
  			.proc_handler	= proc_dointvec_minmax,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3032
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
3033
  		[NEIGH_VAR_GC_THRESH2] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3034
3035
3036
  			.procname	= "gc_thresh2",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
555445cd1   Francesco Fusco   neigh: prevent ov...
3037
3038
3039
  			.extra1 	= &zero,
  			.extra2		= &int_max,
  			.proc_handler	= proc_dointvec_minmax,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3040
  		},
8b5c171bb   Eric Dumazet   neigh: new unreso...
3041
  		[NEIGH_VAR_GC_THRESH3] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3042
3043
3044
  			.procname	= "gc_thresh3",
  			.maxlen		= sizeof(int),
  			.mode		= 0644,
555445cd1   Francesco Fusco   neigh: prevent ov...
3045
3046
3047
  			.extra1 	= &zero,
  			.extra2		= &int_max,
  			.proc_handler	= proc_dointvec_minmax,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3048
  		},
c3bac5a71   Pavel Emelyanov   [NEIGH]: Use the ...
3049
  		{},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3050
3051
3052
3053
  	},
  };
  
  int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
73af614ae   Jiri Pirko   neigh: use tbl->f...
3054
  			  proc_handler *handler)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3055
  {
1f9248e56   Jiri Pirko   neigh: convert pa...
3056
  	int i;
3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
3057
  	struct neigh_sysctl_table *t;
1f9248e56   Jiri Pirko   neigh: convert pa...
3058
  	const char *dev_name_source;
8f40a1f98   Eric W. Biederman   net neighbour: Co...
3059
  	char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ];
73af614ae   Jiri Pirko   neigh: use tbl->f...
3060
  	char *p_name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3061

3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
3062
  	t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3063
  	if (!t)
3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
3064
  		goto err;
b194c1f1d   Jiri Pirko   neigh: fix settin...
3065
  	for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
1f9248e56   Jiri Pirko   neigh: convert pa...
3066
  		t->neigh_vars[i].data += (long) p;
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
3067
  		t->neigh_vars[i].extra1 = dev;
1d4c8c298   Jiri Pirko   neigh: restore ol...
3068
  		t->neigh_vars[i].extra2 = p;
cb5b09c17   Jiri Pirko   neigh: wrap proc ...
3069
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3070
3071
3072
  
  	if (dev) {
  		dev_name_source = dev->name;
d12af679b   Eric W. Biederman   sysctl: fix neigh...
3073
  		/* Terminate the table early */
8b5c171bb   Eric Dumazet   neigh: new unreso...
3074
3075
  		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
3076
  	} else {
9ecf07a1d   Mathias Krause   neigh: sysctl - s...
3077
  		struct neigh_table *tbl = p->tbl;
8f40a1f98   Eric W. Biederman   net neighbour: Co...
3078
  		dev_name_source = "default";
9ecf07a1d   Mathias Krause   neigh: sysctl - s...
3079
3080
3081
3082
  		t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval;
  		t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1;
  		t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2;
  		t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3083
  	}
f8572d8f2   Eric W. Biederman   sysctl net: Remov...
3084
  	if (handler) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3085
  		/* RetransTime */
8b5c171bb   Eric Dumazet   neigh: new unreso...
3086
  		t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3087
  		/* ReachableTime */
8b5c171bb   Eric Dumazet   neigh: new unreso...
3088
  		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3089
  		/* RetransTime (in milliseconds)*/
8b5c171bb   Eric Dumazet   neigh: new unreso...
3090
  		t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3091
  		/* ReachableTime (in milliseconds) */
8b5c171bb   Eric Dumazet   neigh: new unreso...
3092
  		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
4bf6980dd   Jean-Francois Remy   neighbour: fix ba...
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
  	} else {
  		/* Those handlers will update p->reachable_time after
  		 * base_reachable_time(_ms) is set to ensure the new timer starts being
  		 * applied after the next neighbour update instead of waiting for
  		 * neigh_periodic_work to update its value (can be multiple minutes)
  		 * So any handler that replaces them should do this as well
  		 */
  		/* ReachableTime */
  		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler =
  			neigh_proc_base_reachable_time;
  		/* ReachableTime (in milliseconds) */
  		t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler =
  			neigh_proc_base_reachable_time;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3106
  	}
464dc801c   Eric W. Biederman   net: Don't export...
3107
3108
3109
  	/* Don't export sysctls to unprivileged users */
  	if (neigh_parms_net(p)->user_ns != &init_user_ns)
  		t->neigh_vars[0].procname = NULL;
73af614ae   Jiri Pirko   neigh: use tbl->f...
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
  	switch (neigh_parms_family(p)) {
  	case AF_INET:
  	      p_name = "ipv4";
  	      break;
  	case AF_INET6:
  	      p_name = "ipv6";
  	      break;
  	default:
  	      BUG();
  	}
8f40a1f98   Eric W. Biederman   net neighbour: Co...
3120
3121
  	snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s",
  		p_name, dev_name_source);
4ab438fcd   Denis V. Lunev   [NETNS]: Register...
3122
  	t->sysctl_header =
8f40a1f98   Eric W. Biederman   net neighbour: Co...
3123
  		register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars);
3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
3124
  	if (!t->sysctl_header)
8f40a1f98   Eric W. Biederman   net neighbour: Co...
3125
  		goto free;
3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
3126

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3127
3128
  	p->sysctl_table = t;
  	return 0;
3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
3129
  free:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3130
  	kfree(t);
3c607bbb4   Pavel Emelyanov   [NEIGH]: Cleanup ...
3131
3132
  err:
  	return -ENOBUFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3133
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
3134
  EXPORT_SYMBOL(neigh_sysctl_register);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3135
3136
3137
3138
3139
3140
  
  void neigh_sysctl_unregister(struct neigh_parms *p)
  {
  	if (p->sysctl_table) {
  		struct neigh_sysctl_table *t = p->sysctl_table;
  		p->sysctl_table = NULL;
5dd3df105   Eric W. Biederman   net: Move all of ...
3141
  		unregister_net_sysctl_table(t->sysctl_header);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3142
3143
3144
  		kfree(t);
  	}
  }
0a204500f   YOSHIFUJI Hideaki   [NET] NEIGHBOUR: ...
3145
  EXPORT_SYMBOL(neigh_sysctl_unregister);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3146
3147
  
  #endif	/* CONFIG_SYSCTL */
c8822a4e0   Thomas Graf   [NEIGH]: Use rtnl...
3148
3149
  static int __init neigh_init(void)
  {
b97bac64a   Florian Westphal   rtnetlink: make r...
3150
3151
3152
  	rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
  	rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
  	rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, 0);
c8822a4e0   Thomas Graf   [NEIGH]: Use rtnl...
3153

c7ac8679b   Greg Rose   rtnetlink: Comput...
3154
  	rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
b97bac64a   Florian Westphal   rtnetlink: make r...
3155
3156
  		      0);
  	rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, 0);
c8822a4e0   Thomas Graf   [NEIGH]: Use rtnl...
3157
3158
3159
3160
3161
  
  	return 0;
  }
  
  subsys_initcall(neigh_init);