.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Generic address resolution entity |
---|
3 | 4 | * |
---|
4 | 5 | * Authors: |
---|
5 | 6 | * Pedro Roque <roque@di.fc.ul.pt> |
---|
6 | 7 | * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or |
---|
9 | | - * modify it under the terms of the GNU General Public License |
---|
10 | | - * as published by the Free Software Foundation; either version |
---|
11 | | - * 2 of the License, or (at your option) any later version. |
---|
12 | 8 | * |
---|
13 | 9 | * Fixes: |
---|
14 | 10 | * Vitaly E. Lavrov releasing NULL neighbor in neigh_add. |
---|
.. | .. |
---|
42 | 38 | #include <linux/log2.h> |
---|
43 | 39 | #include <linux/inetdevice.h> |
---|
44 | 40 | #include <net/addrconf.h> |
---|
| 41 | + |
---|
| 42 | +#include <trace/events/neigh.h> |
---|
45 | 43 | |
---|
46 | 44 | #define DEBUG |
---|
47 | 45 | #define NEIGH_DEBUG 1 |
---|
.. | .. |
---|
100 | 98 | |
---|
101 | 99 | static void neigh_cleanup_and_release(struct neighbour *neigh) |
---|
102 | 100 | { |
---|
103 | | - if (neigh->parms->neigh_cleanup) |
---|
104 | | - neigh->parms->neigh_cleanup(neigh); |
---|
105 | | - |
---|
| 101 | + trace_neigh_cleanup_and_release(neigh, 0); |
---|
106 | 102 | __neigh_notify(neigh, RTM_DELNEIGH, 0, 0); |
---|
107 | 103 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh); |
---|
108 | 104 | neigh_release(neigh); |
---|
.. | .. |
---|
120 | 116 | } |
---|
121 | 117 | EXPORT_SYMBOL(neigh_rand_reach_time); |
---|
122 | 118 | |
---|
| 119 | +static void neigh_mark_dead(struct neighbour *n) |
---|
| 120 | +{ |
---|
| 121 | + n->dead = 1; |
---|
| 122 | + if (!list_empty(&n->gc_list)) { |
---|
| 123 | + list_del_init(&n->gc_list); |
---|
| 124 | + atomic_dec(&n->tbl->gc_entries); |
---|
| 125 | + } |
---|
| 126 | +} |
---|
123 | 127 | |
---|
124 | | -static bool neigh_del(struct neighbour *n, __u8 state, __u8 flags, |
---|
125 | | - struct neighbour __rcu **np, struct neigh_table *tbl) |
---|
| 128 | +static void neigh_update_gc_list(struct neighbour *n) |
---|
| 129 | +{ |
---|
| 130 | + bool on_gc_list, exempt_from_gc; |
---|
| 131 | + |
---|
| 132 | + write_lock_bh(&n->tbl->lock); |
---|
| 133 | + write_lock(&n->lock); |
---|
| 134 | + |
---|
| 135 | + if (n->dead) |
---|
| 136 | + goto out; |
---|
| 137 | + |
---|
| 138 | + /* remove from the gc list if new state is permanent or if neighbor |
---|
| 139 | + * is externally learned; otherwise entry should be on the gc list |
---|
| 140 | + */ |
---|
| 141 | + exempt_from_gc = n->nud_state & NUD_PERMANENT || |
---|
| 142 | + n->flags & NTF_EXT_LEARNED; |
---|
| 143 | + on_gc_list = !list_empty(&n->gc_list); |
---|
| 144 | + |
---|
| 145 | + if (exempt_from_gc && on_gc_list) { |
---|
| 146 | + list_del_init(&n->gc_list); |
---|
| 147 | + atomic_dec(&n->tbl->gc_entries); |
---|
| 148 | + } else if (!exempt_from_gc && !on_gc_list) { |
---|
| 149 | + /* add entries to the tail; cleaning removes from the front */ |
---|
| 150 | + list_add_tail(&n->gc_list, &n->tbl->gc_list); |
---|
| 151 | + atomic_inc(&n->tbl->gc_entries); |
---|
| 152 | + } |
---|
| 153 | + |
---|
| 154 | +out: |
---|
| 155 | + write_unlock(&n->lock); |
---|
| 156 | + write_unlock_bh(&n->tbl->lock); |
---|
| 157 | +} |
---|
| 158 | + |
---|
| 159 | +static bool neigh_update_ext_learned(struct neighbour *neigh, u32 flags, |
---|
| 160 | + int *notify) |
---|
| 161 | +{ |
---|
| 162 | + bool rc = false; |
---|
| 163 | + u8 ndm_flags; |
---|
| 164 | + |
---|
| 165 | + if (!(flags & NEIGH_UPDATE_F_ADMIN)) |
---|
| 166 | + return rc; |
---|
| 167 | + |
---|
| 168 | + ndm_flags = (flags & NEIGH_UPDATE_F_EXT_LEARNED) ? NTF_EXT_LEARNED : 0; |
---|
| 169 | + if ((neigh->flags ^ ndm_flags) & NTF_EXT_LEARNED) { |
---|
| 170 | + if (ndm_flags & NTF_EXT_LEARNED) |
---|
| 171 | + neigh->flags |= NTF_EXT_LEARNED; |
---|
| 172 | + else |
---|
| 173 | + neigh->flags &= ~NTF_EXT_LEARNED; |
---|
| 174 | + rc = true; |
---|
| 175 | + *notify = 1; |
---|
| 176 | + } |
---|
| 177 | + |
---|
| 178 | + return rc; |
---|
| 179 | +} |
---|
| 180 | + |
---|
| 181 | +static bool neigh_del(struct neighbour *n, struct neighbour __rcu **np, |
---|
| 182 | + struct neigh_table *tbl) |
---|
126 | 183 | { |
---|
127 | 184 | bool retval = false; |
---|
128 | 185 | |
---|
129 | 186 | write_lock(&n->lock); |
---|
130 | | - if (refcount_read(&n->refcnt) == 1 && !(n->nud_state & state) && |
---|
131 | | - !(n->flags & flags)) { |
---|
| 187 | + if (refcount_read(&n->refcnt) == 1) { |
---|
132 | 188 | struct neighbour *neigh; |
---|
133 | 189 | |
---|
134 | 190 | neigh = rcu_dereference_protected(n->next, |
---|
135 | 191 | lockdep_is_held(&tbl->lock)); |
---|
136 | 192 | rcu_assign_pointer(*np, neigh); |
---|
137 | | - n->dead = 1; |
---|
| 193 | + neigh_mark_dead(n); |
---|
138 | 194 | retval = true; |
---|
139 | 195 | } |
---|
140 | 196 | write_unlock(&n->lock); |
---|
.. | .. |
---|
160 | 216 | while ((n = rcu_dereference_protected(*np, |
---|
161 | 217 | lockdep_is_held(&tbl->lock)))) { |
---|
162 | 218 | if (n == ndel) |
---|
163 | | - return neigh_del(n, 0, 0, np, tbl); |
---|
| 219 | + return neigh_del(n, np, tbl); |
---|
164 | 220 | np = &n->next; |
---|
165 | 221 | } |
---|
166 | 222 | return false; |
---|
.. | .. |
---|
168 | 224 | |
---|
169 | 225 | static int neigh_forced_gc(struct neigh_table *tbl) |
---|
170 | 226 | { |
---|
| 227 | + int max_clean = atomic_read(&tbl->gc_entries) - tbl->gc_thresh2; |
---|
| 228 | + unsigned long tref = jiffies - 5 * HZ; |
---|
| 229 | + struct neighbour *n, *tmp; |
---|
171 | 230 | int shrunk = 0; |
---|
172 | | - int i; |
---|
173 | | - struct neigh_hash_table *nht; |
---|
174 | 231 | |
---|
175 | 232 | NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs); |
---|
176 | 233 | |
---|
177 | 234 | write_lock_bh(&tbl->lock); |
---|
178 | | - nht = rcu_dereference_protected(tbl->nht, |
---|
179 | | - lockdep_is_held(&tbl->lock)); |
---|
180 | | - for (i = 0; i < (1 << nht->hash_shift); i++) { |
---|
181 | | - struct neighbour *n; |
---|
182 | | - struct neighbour __rcu **np; |
---|
183 | 235 | |
---|
184 | | - np = &nht->hash_buckets[i]; |
---|
185 | | - while ((n = rcu_dereference_protected(*np, |
---|
186 | | - lockdep_is_held(&tbl->lock))) != NULL) { |
---|
187 | | - /* Neighbour record may be discarded if: |
---|
188 | | - * - nobody refers to it. |
---|
189 | | - * - it is not permanent |
---|
190 | | - */ |
---|
191 | | - if (neigh_del(n, NUD_PERMANENT, NTF_EXT_LEARNED, np, |
---|
192 | | - tbl)) { |
---|
193 | | - shrunk = 1; |
---|
194 | | - continue; |
---|
195 | | - } |
---|
196 | | - np = &n->next; |
---|
| 236 | + list_for_each_entry_safe(n, tmp, &tbl->gc_list, gc_list) { |
---|
| 237 | + if (refcount_read(&n->refcnt) == 1) { |
---|
| 238 | + bool remove = false; |
---|
| 239 | + |
---|
| 240 | + write_lock(&n->lock); |
---|
| 241 | + if ((n->nud_state == NUD_FAILED) || |
---|
| 242 | + (n->nud_state == NUD_NOARP) || |
---|
| 243 | + (tbl->is_multicast && |
---|
| 244 | + tbl->is_multicast(n->primary_key)) || |
---|
| 245 | + !time_in_range(n->updated, tref, jiffies)) |
---|
| 246 | + remove = true; |
---|
| 247 | + write_unlock(&n->lock); |
---|
| 248 | + |
---|
| 249 | + if (remove && neigh_remove_one(n, tbl)) |
---|
| 250 | + shrunk++; |
---|
| 251 | + if (shrunk >= max_clean) |
---|
| 252 | + break; |
---|
197 | 253 | } |
---|
198 | 254 | } |
---|
199 | 255 | |
---|
.. | .. |
---|
206 | 262 | |
---|
207 | 263 | static void neigh_add_timer(struct neighbour *n, unsigned long when) |
---|
208 | 264 | { |
---|
| 265 | + /* Use safe distance from the jiffies - LONG_MAX point while timer |
---|
| 266 | + * is running in DELAY/PROBE state but still show to user space |
---|
| 267 | + * large times in the past. |
---|
| 268 | + */ |
---|
| 269 | + unsigned long mint = jiffies - (LONG_MAX - 86400 * HZ); |
---|
| 270 | + |
---|
209 | 271 | neigh_hold(n); |
---|
| 272 | + if (!time_in_range(n->confirmed, mint, jiffies)) |
---|
| 273 | + n->confirmed = mint; |
---|
| 274 | + if (time_before(n->used, n->confirmed)) |
---|
| 275 | + n->used = n->confirmed; |
---|
210 | 276 | if (unlikely(mod_timer(&n->timer, when))) { |
---|
211 | 277 | printk("NEIGH: BUG, double timer add, state is %x\n", |
---|
212 | 278 | n->nud_state); |
---|
.. | .. |
---|
224 | 290 | return 0; |
---|
225 | 291 | } |
---|
226 | 292 | |
---|
227 | | -static void pneigh_queue_purge(struct sk_buff_head *list) |
---|
| 293 | +static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net) |
---|
228 | 294 | { |
---|
| 295 | + struct sk_buff_head tmp; |
---|
| 296 | + unsigned long flags; |
---|
229 | 297 | struct sk_buff *skb; |
---|
230 | 298 | |
---|
231 | | - while ((skb = skb_dequeue(list)) != NULL) { |
---|
| 299 | + skb_queue_head_init(&tmp); |
---|
| 300 | + spin_lock_irqsave(&list->lock, flags); |
---|
| 301 | + skb = skb_peek(list); |
---|
| 302 | + while (skb != NULL) { |
---|
| 303 | + struct sk_buff *skb_next = skb_peek_next(skb, list); |
---|
| 304 | + if (net == NULL || net_eq(dev_net(skb->dev), net)) { |
---|
| 305 | + __skb_unlink(skb, list); |
---|
| 306 | + __skb_queue_tail(&tmp, skb); |
---|
| 307 | + } |
---|
| 308 | + skb = skb_next; |
---|
| 309 | + } |
---|
| 310 | + spin_unlock_irqrestore(&list->lock, flags); |
---|
| 311 | + |
---|
| 312 | + while ((skb = __skb_dequeue(&tmp))) { |
---|
232 | 313 | dev_put(skb->dev); |
---|
233 | 314 | kfree_skb(skb); |
---|
234 | 315 | } |
---|
235 | 316 | } |
---|
236 | 317 | |
---|
237 | | -static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev) |
---|
| 318 | +static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev, |
---|
| 319 | + bool skip_perm) |
---|
238 | 320 | { |
---|
239 | 321 | int i; |
---|
240 | 322 | struct neigh_hash_table *nht; |
---|
.. | .. |
---|
252 | 334 | np = &n->next; |
---|
253 | 335 | continue; |
---|
254 | 336 | } |
---|
| 337 | + if (skip_perm && n->nud_state & NUD_PERMANENT) { |
---|
| 338 | + np = &n->next; |
---|
| 339 | + continue; |
---|
| 340 | + } |
---|
255 | 341 | rcu_assign_pointer(*np, |
---|
256 | 342 | rcu_dereference_protected(n->next, |
---|
257 | 343 | lockdep_is_held(&tbl->lock))); |
---|
258 | 344 | write_lock(&n->lock); |
---|
259 | 345 | neigh_del_timer(n); |
---|
260 | | - n->dead = 1; |
---|
261 | | - |
---|
| 346 | + neigh_mark_dead(n); |
---|
262 | 347 | if (refcount_read(&n->refcnt) != 1) { |
---|
263 | 348 | /* The most unpleasant situation. |
---|
264 | 349 | We must destroy neighbour entry, |
---|
.. | .. |
---|
287 | 372 | void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev) |
---|
288 | 373 | { |
---|
289 | 374 | write_lock_bh(&tbl->lock); |
---|
290 | | - neigh_flush_dev(tbl, dev); |
---|
| 375 | + neigh_flush_dev(tbl, dev, false); |
---|
291 | 376 | write_unlock_bh(&tbl->lock); |
---|
292 | 377 | } |
---|
293 | 378 | EXPORT_SYMBOL(neigh_changeaddr); |
---|
294 | 379 | |
---|
295 | | -int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) |
---|
| 380 | +static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev, |
---|
| 381 | + bool skip_perm) |
---|
296 | 382 | { |
---|
297 | 383 | write_lock_bh(&tbl->lock); |
---|
298 | | - neigh_flush_dev(tbl, dev); |
---|
| 384 | + neigh_flush_dev(tbl, dev, skip_perm); |
---|
299 | 385 | pneigh_ifdown_and_unlock(tbl, dev); |
---|
| 386 | + pneigh_queue_purge(&tbl->proxy_queue, dev ? dev_net(dev) : NULL); |
---|
| 387 | + if (skb_queue_empty_lockless(&tbl->proxy_queue)) |
---|
| 388 | + del_timer_sync(&tbl->proxy_timer); |
---|
| 389 | + return 0; |
---|
| 390 | +} |
---|
300 | 391 | |
---|
301 | | - del_timer_sync(&tbl->proxy_timer); |
---|
302 | | - pneigh_queue_purge(&tbl->proxy_queue); |
---|
| 392 | +int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev) |
---|
| 393 | +{ |
---|
| 394 | + __neigh_ifdown(tbl, dev, true); |
---|
| 395 | + return 0; |
---|
| 396 | +} |
---|
| 397 | +EXPORT_SYMBOL(neigh_carrier_down); |
---|
| 398 | + |
---|
| 399 | +int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) |
---|
| 400 | +{ |
---|
| 401 | + __neigh_ifdown(tbl, dev, false); |
---|
303 | 402 | return 0; |
---|
304 | 403 | } |
---|
305 | 404 | EXPORT_SYMBOL(neigh_ifdown); |
---|
306 | 405 | |
---|
307 | | -static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev) |
---|
| 406 | +static struct neighbour *neigh_alloc(struct neigh_table *tbl, |
---|
| 407 | + struct net_device *dev, |
---|
| 408 | + u8 flags, bool exempt_from_gc) |
---|
308 | 409 | { |
---|
309 | 410 | struct neighbour *n = NULL; |
---|
310 | 411 | unsigned long now = jiffies; |
---|
311 | 412 | int entries; |
---|
312 | 413 | |
---|
313 | | - entries = atomic_inc_return(&tbl->entries) - 1; |
---|
| 414 | + if (exempt_from_gc) |
---|
| 415 | + goto do_alloc; |
---|
| 416 | + |
---|
| 417 | + entries = atomic_inc_return(&tbl->gc_entries) - 1; |
---|
314 | 418 | if (entries >= tbl->gc_thresh3 || |
---|
315 | 419 | (entries >= tbl->gc_thresh2 && |
---|
316 | 420 | time_after(now, tbl->last_flush + 5 * HZ))) { |
---|
.. | .. |
---|
323 | 427 | } |
---|
324 | 428 | } |
---|
325 | 429 | |
---|
| 430 | +do_alloc: |
---|
326 | 431 | n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC); |
---|
327 | 432 | if (!n) |
---|
328 | 433 | goto out_entries; |
---|
.. | .. |
---|
333 | 438 | n->updated = n->used = now; |
---|
334 | 439 | n->nud_state = NUD_NONE; |
---|
335 | 440 | n->output = neigh_blackhole; |
---|
| 441 | + n->flags = flags; |
---|
336 | 442 | seqlock_init(&n->hh.hh_lock); |
---|
337 | 443 | n->parms = neigh_parms_clone(&tbl->parms); |
---|
338 | 444 | timer_setup(&n->timer, neigh_timer_handler, 0); |
---|
.. | .. |
---|
341 | 447 | n->tbl = tbl; |
---|
342 | 448 | refcount_set(&n->refcnt, 1); |
---|
343 | 449 | n->dead = 1; |
---|
| 450 | + INIT_LIST_HEAD(&n->gc_list); |
---|
| 451 | + |
---|
| 452 | + atomic_inc(&tbl->entries); |
---|
344 | 453 | out: |
---|
345 | 454 | return n; |
---|
346 | 455 | |
---|
347 | 456 | out_entries: |
---|
348 | | - atomic_dec(&tbl->entries); |
---|
| 457 | + if (!exempt_from_gc) |
---|
| 458 | + atomic_dec(&tbl->gc_entries); |
---|
349 | 459 | goto out; |
---|
350 | 460 | } |
---|
351 | 461 | |
---|
.. | .. |
---|
461 | 571 | } |
---|
462 | 572 | EXPORT_SYMBOL(neigh_lookup); |
---|
463 | 573 | |
---|
464 | | -struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net, |
---|
465 | | - const void *pkey) |
---|
| 574 | +static struct neighbour * |
---|
| 575 | +___neigh_create(struct neigh_table *tbl, const void *pkey, |
---|
| 576 | + struct net_device *dev, u8 flags, |
---|
| 577 | + bool exempt_from_gc, bool want_ref) |
---|
466 | 578 | { |
---|
467 | | - struct neighbour *n; |
---|
468 | | - unsigned int key_len = tbl->key_len; |
---|
469 | | - u32 hash_val; |
---|
| 579 | + u32 hash_val, key_len = tbl->key_len; |
---|
| 580 | + struct neighbour *n1, *rc, *n; |
---|
470 | 581 | struct neigh_hash_table *nht; |
---|
471 | | - |
---|
472 | | - NEIGH_CACHE_STAT_INC(tbl, lookups); |
---|
473 | | - |
---|
474 | | - rcu_read_lock_bh(); |
---|
475 | | - nht = rcu_dereference_bh(tbl->nht); |
---|
476 | | - hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift); |
---|
477 | | - |
---|
478 | | - for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]); |
---|
479 | | - n != NULL; |
---|
480 | | - n = rcu_dereference_bh(n->next)) { |
---|
481 | | - if (!memcmp(n->primary_key, pkey, key_len) && |
---|
482 | | - net_eq(dev_net(n->dev), net)) { |
---|
483 | | - if (!refcount_inc_not_zero(&n->refcnt)) |
---|
484 | | - n = NULL; |
---|
485 | | - NEIGH_CACHE_STAT_INC(tbl, hits); |
---|
486 | | - break; |
---|
487 | | - } |
---|
488 | | - } |
---|
489 | | - |
---|
490 | | - rcu_read_unlock_bh(); |
---|
491 | | - return n; |
---|
492 | | -} |
---|
493 | | -EXPORT_SYMBOL(neigh_lookup_nodev); |
---|
494 | | - |
---|
495 | | -struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey, |
---|
496 | | - struct net_device *dev, bool want_ref) |
---|
497 | | -{ |
---|
498 | | - u32 hash_val; |
---|
499 | | - unsigned int key_len = tbl->key_len; |
---|
500 | 582 | int error; |
---|
501 | | - struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev); |
---|
502 | | - struct neigh_hash_table *nht; |
---|
503 | 583 | |
---|
| 584 | + n = neigh_alloc(tbl, dev, flags, exempt_from_gc); |
---|
| 585 | + trace_neigh_create(tbl, dev, pkey, n, exempt_from_gc); |
---|
504 | 586 | if (!n) { |
---|
505 | 587 | rc = ERR_PTR(-ENOBUFS); |
---|
506 | 588 | goto out; |
---|
.. | .. |
---|
561 | 643 | } |
---|
562 | 644 | |
---|
563 | 645 | n->dead = 0; |
---|
| 646 | + if (!exempt_from_gc) |
---|
| 647 | + list_add_tail(&n->gc_list, &n->tbl->gc_list); |
---|
| 648 | + |
---|
564 | 649 | if (want_ref) |
---|
565 | 650 | neigh_hold(n); |
---|
566 | 651 | rcu_assign_pointer(n->next, |
---|
.. | .. |
---|
575 | 660 | out_tbl_unlock: |
---|
576 | 661 | write_unlock_bh(&tbl->lock); |
---|
577 | 662 | out_neigh_release: |
---|
| 663 | + if (!exempt_from_gc) |
---|
| 664 | + atomic_dec(&tbl->gc_entries); |
---|
578 | 665 | neigh_release(n); |
---|
579 | 666 | goto out; |
---|
| 667 | +} |
---|
| 668 | + |
---|
| 669 | +struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey, |
---|
| 670 | + struct net_device *dev, bool want_ref) |
---|
| 671 | +{ |
---|
| 672 | + return ___neigh_create(tbl, pkey, dev, 0, false, want_ref); |
---|
580 | 673 | } |
---|
581 | 674 | EXPORT_SYMBOL(__neigh_create); |
---|
582 | 675 | |
---|
.. | .. |
---|
834 | 927 | goto next_elt; |
---|
835 | 928 | } |
---|
836 | 929 | |
---|
837 | | - if (time_before(n->used, n->confirmed)) |
---|
| 930 | + if (time_before(n->used, n->confirmed) && |
---|
| 931 | + time_is_before_eq_jiffies(n->confirmed)) |
---|
838 | 932 | n->used = n->confirmed; |
---|
839 | 933 | |
---|
840 | 934 | if (refcount_read(&n->refcnt) == 1 && |
---|
841 | 935 | (state == NUD_FAILED || |
---|
842 | | - time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) { |
---|
843 | | - *np = n->next; |
---|
844 | | - n->dead = 1; |
---|
| 936 | + !time_in_range_open(jiffies, n->used, |
---|
| 937 | + n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) { |
---|
| 938 | + rcu_assign_pointer(*np, |
---|
| 939 | + rcu_dereference_protected(n->next, |
---|
| 940 | + lockdep_is_held(&tbl->lock))); |
---|
| 941 | + neigh_mark_dead(n); |
---|
845 | 942 | write_unlock(&n->lock); |
---|
846 | 943 | neigh_cleanup_and_release(n); |
---|
847 | 944 | continue; |
---|
.. | .. |
---|
915 | 1012 | if (neigh->ops->solicit) |
---|
916 | 1013 | neigh->ops->solicit(neigh, skb); |
---|
917 | 1014 | atomic_inc(&neigh->probes); |
---|
918 | | - kfree_skb(skb); |
---|
| 1015 | + consume_skb(skb); |
---|
919 | 1016 | } |
---|
920 | 1017 | |
---|
921 | 1018 | /* Called when a timer expires for a neighbour entry. */ |
---|
.. | .. |
---|
972 | 1069 | neigh->updated = jiffies; |
---|
973 | 1070 | atomic_set(&neigh->probes, 0); |
---|
974 | 1071 | notify = 1; |
---|
975 | | - next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME); |
---|
| 1072 | + next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), |
---|
| 1073 | + HZ/100); |
---|
976 | 1074 | } |
---|
977 | 1075 | } else { |
---|
978 | 1076 | /* NUD_PROBE|NUD_INCOMPLETE */ |
---|
979 | | - next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME); |
---|
| 1077 | + next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), HZ/100); |
---|
980 | 1078 | } |
---|
981 | 1079 | |
---|
982 | 1080 | if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) && |
---|
.. | .. |
---|
988 | 1086 | } |
---|
989 | 1087 | |
---|
990 | 1088 | if (neigh->nud_state & NUD_IN_TIMER) { |
---|
991 | | - if (time_before(next, jiffies + HZ/2)) |
---|
992 | | - next = jiffies + HZ/2; |
---|
| 1089 | + if (time_before(next, jiffies + HZ/100)) |
---|
| 1090 | + next = jiffies + HZ/100; |
---|
993 | 1091 | if (!mod_timer(&neigh->timer, next)) |
---|
994 | 1092 | neigh_hold(neigh); |
---|
995 | 1093 | } |
---|
.. | .. |
---|
1002 | 1100 | |
---|
1003 | 1101 | if (notify) |
---|
1004 | 1102 | neigh_update_notify(neigh, 0); |
---|
| 1103 | + |
---|
| 1104 | + trace_neigh_timer_handler(neigh, 0); |
---|
1005 | 1105 | |
---|
1006 | 1106 | neigh_release(neigh); |
---|
1007 | 1107 | } |
---|
.. | .. |
---|
1030 | 1130 | neigh->nud_state = NUD_INCOMPLETE; |
---|
1031 | 1131 | neigh->updated = now; |
---|
1032 | 1132 | next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), |
---|
1033 | | - HZ/2); |
---|
| 1133 | + HZ/100); |
---|
1034 | 1134 | neigh_add_timer(neigh, next); |
---|
1035 | 1135 | immediate_probe = true; |
---|
1036 | 1136 | } else { |
---|
.. | .. |
---|
1075 | 1175 | else |
---|
1076 | 1176 | write_unlock(&neigh->lock); |
---|
1077 | 1177 | local_bh_enable(); |
---|
| 1178 | + trace_neigh_event_send_done(neigh, rc); |
---|
1078 | 1179 | return rc; |
---|
1079 | 1180 | |
---|
1080 | 1181 | out_dead: |
---|
.. | .. |
---|
1082 | 1183 | goto out_unlock_bh; |
---|
1083 | 1184 | write_unlock_bh(&neigh->lock); |
---|
1084 | 1185 | kfree_skb(skb); |
---|
| 1186 | + trace_neigh_event_send_dead(neigh, 1); |
---|
1085 | 1187 | return 1; |
---|
1086 | 1188 | } |
---|
1087 | 1189 | EXPORT_SYMBOL(__neigh_event_send); |
---|
.. | .. |
---|
1117 | 1219 | lladdr instead of overriding it |
---|
1118 | 1220 | if it is different. |
---|
1119 | 1221 | NEIGH_UPDATE_F_ADMIN means that the change is administrative. |
---|
1120 | | - |
---|
| 1222 | + NEIGH_UPDATE_F_USE means that the entry is user triggered. |
---|
1121 | 1223 | NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing |
---|
1122 | 1224 | NTF_ROUTER flag. |
---|
1123 | 1225 | NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as |
---|
.. | .. |
---|
1126 | 1228 | Caller MUST hold reference count on the entry. |
---|
1127 | 1229 | */ |
---|
1128 | 1230 | |
---|
1129 | | -int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, |
---|
1130 | | - u32 flags, u32 nlmsg_pid) |
---|
| 1231 | +static int __neigh_update(struct neighbour *neigh, const u8 *lladdr, |
---|
| 1232 | + u8 new, u32 flags, u32 nlmsg_pid, |
---|
| 1233 | + struct netlink_ext_ack *extack) |
---|
1131 | 1234 | { |
---|
| 1235 | + bool ext_learn_change = false; |
---|
1132 | 1236 | u8 old; |
---|
1133 | 1237 | int err; |
---|
1134 | 1238 | int notify = 0; |
---|
1135 | 1239 | struct net_device *dev; |
---|
1136 | 1240 | int update_isrouter = 0; |
---|
| 1241 | + |
---|
| 1242 | + trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid); |
---|
1137 | 1243 | |
---|
1138 | 1244 | write_lock_bh(&neigh->lock); |
---|
1139 | 1245 | |
---|
.. | .. |
---|
1141 | 1247 | old = neigh->nud_state; |
---|
1142 | 1248 | err = -EPERM; |
---|
1143 | 1249 | |
---|
| 1250 | + if (neigh->dead) { |
---|
| 1251 | + NL_SET_ERR_MSG(extack, "Neighbor entry is now dead"); |
---|
| 1252 | + new = old; |
---|
| 1253 | + goto out; |
---|
| 1254 | + } |
---|
1144 | 1255 | if (!(flags & NEIGH_UPDATE_F_ADMIN) && |
---|
1145 | 1256 | (old & (NUD_NOARP | NUD_PERMANENT))) |
---|
1146 | 1257 | goto out; |
---|
1147 | | - if (neigh->dead) |
---|
1148 | | - goto out; |
---|
1149 | 1258 | |
---|
1150 | | - neigh_update_ext_learned(neigh, flags, ¬ify); |
---|
| 1259 | + ext_learn_change = neigh_update_ext_learned(neigh, flags, ¬ify); |
---|
| 1260 | + if (flags & NEIGH_UPDATE_F_USE) { |
---|
| 1261 | + new = old & ~NUD_PERMANENT; |
---|
| 1262 | + neigh->nud_state = new; |
---|
| 1263 | + err = 0; |
---|
| 1264 | + goto out; |
---|
| 1265 | + } |
---|
1151 | 1266 | |
---|
1152 | 1267 | if (!(new & NUD_VALID)) { |
---|
1153 | 1268 | neigh_del_timer(neigh); |
---|
.. | .. |
---|
1182 | 1297 | use it, otherwise discard the request. |
---|
1183 | 1298 | */ |
---|
1184 | 1299 | err = -EINVAL; |
---|
1185 | | - if (!(old & NUD_VALID)) |
---|
| 1300 | + if (!(old & NUD_VALID)) { |
---|
| 1301 | + NL_SET_ERR_MSG(extack, "No link layer address given"); |
---|
1186 | 1302 | goto out; |
---|
| 1303 | + } |
---|
1187 | 1304 | lladdr = neigh->ha; |
---|
1188 | 1305 | } |
---|
1189 | 1306 | |
---|
.. | .. |
---|
1287 | 1404 | neigh->arp_queue_len_bytes = 0; |
---|
1288 | 1405 | } |
---|
1289 | 1406 | out: |
---|
1290 | | - if (update_isrouter) { |
---|
1291 | | - neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ? |
---|
1292 | | - (neigh->flags | NTF_ROUTER) : |
---|
1293 | | - (neigh->flags & ~NTF_ROUTER); |
---|
1294 | | - } |
---|
| 1407 | + if (update_isrouter) |
---|
| 1408 | + neigh_update_is_router(neigh, flags, ¬ify); |
---|
1295 | 1409 | write_unlock_bh(&neigh->lock); |
---|
| 1410 | + |
---|
| 1411 | + if (((new ^ old) & NUD_PERMANENT) || ext_learn_change) |
---|
| 1412 | + neigh_update_gc_list(neigh); |
---|
1296 | 1413 | |
---|
1297 | 1414 | if (notify) |
---|
1298 | 1415 | neigh_update_notify(neigh, nlmsg_pid); |
---|
1299 | 1416 | |
---|
| 1417 | + trace_neigh_update_done(neigh, err); |
---|
| 1418 | + |
---|
1300 | 1419 | return err; |
---|
| 1420 | +} |
---|
| 1421 | + |
---|
| 1422 | +int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, |
---|
| 1423 | + u32 flags, u32 nlmsg_pid) |
---|
| 1424 | +{ |
---|
| 1425 | + return __neigh_update(neigh, lladdr, new, flags, nlmsg_pid, NULL); |
---|
1301 | 1426 | } |
---|
1302 | 1427 | EXPORT_SYMBOL(neigh_update); |
---|
1303 | 1428 | |
---|
.. | .. |
---|
1314 | 1439 | neigh->nud_state = NUD_INCOMPLETE; |
---|
1315 | 1440 | atomic_set(&neigh->probes, neigh_max_probes(neigh)); |
---|
1316 | 1441 | neigh_add_timer(neigh, |
---|
1317 | | - jiffies + NEIGH_VAR(neigh->parms, RETRANS_TIME)); |
---|
| 1442 | + jiffies + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), |
---|
| 1443 | + HZ/100)); |
---|
1318 | 1444 | } |
---|
1319 | 1445 | EXPORT_SYMBOL(__neigh_set_probe_once); |
---|
1320 | 1446 | |
---|
.. | .. |
---|
1563 | 1689 | unsigned long phsize; |
---|
1564 | 1690 | |
---|
1565 | 1691 | INIT_LIST_HEAD(&tbl->parms_list); |
---|
| 1692 | + INIT_LIST_HEAD(&tbl->gc_list); |
---|
1566 | 1693 | list_add(&tbl->parms.list, &tbl->parms_list); |
---|
1567 | 1694 | write_pnet(&tbl->parms.net, &init_net); |
---|
1568 | 1695 | refcount_set(&tbl->parms.refcnt, 1); |
---|
.. | .. |
---|
1614 | 1741 | /* It is not clean... Fix it to unload IPv6 module safely */ |
---|
1615 | 1742 | cancel_delayed_work_sync(&tbl->gc_work); |
---|
1616 | 1743 | del_timer_sync(&tbl->proxy_timer); |
---|
1617 | | - pneigh_queue_purge(&tbl->proxy_queue); |
---|
| 1744 | + pneigh_queue_purge(&tbl->proxy_queue, NULL); |
---|
1618 | 1745 | neigh_ifdown(tbl, NULL); |
---|
1619 | 1746 | if (atomic_read(&tbl->entries)) |
---|
1620 | 1747 | pr_crit("neighbour leakage\n"); |
---|
.. | .. |
---|
1646 | 1773 | case AF_INET6: |
---|
1647 | 1774 | tbl = neigh_tables[NEIGH_ND_TABLE]; |
---|
1648 | 1775 | break; |
---|
1649 | | - case AF_DECnet: |
---|
1650 | | - tbl = neigh_tables[NEIGH_DN_TABLE]; |
---|
1651 | | - break; |
---|
1652 | 1776 | } |
---|
1653 | 1777 | |
---|
1654 | 1778 | return tbl; |
---|
1655 | 1779 | } |
---|
| 1780 | + |
---|
| 1781 | +const struct nla_policy nda_policy[NDA_MAX+1] = { |
---|
| 1782 | + [NDA_UNSPEC] = { .strict_start_type = NDA_NH_ID }, |
---|
| 1783 | + [NDA_DST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, |
---|
| 1784 | + [NDA_LLADDR] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, |
---|
| 1785 | + [NDA_CACHEINFO] = { .len = sizeof(struct nda_cacheinfo) }, |
---|
| 1786 | + [NDA_PROBES] = { .type = NLA_U32 }, |
---|
| 1787 | + [NDA_VLAN] = { .type = NLA_U16 }, |
---|
| 1788 | + [NDA_PORT] = { .type = NLA_U16 }, |
---|
| 1789 | + [NDA_VNI] = { .type = NLA_U32 }, |
---|
| 1790 | + [NDA_IFINDEX] = { .type = NLA_U32 }, |
---|
| 1791 | + [NDA_MASTER] = { .type = NLA_U32 }, |
---|
| 1792 | + [NDA_PROTOCOL] = { .type = NLA_U8 }, |
---|
| 1793 | + [NDA_NH_ID] = { .type = NLA_U32 }, |
---|
| 1794 | + [NDA_FDB_EXT_ATTRS] = { .type = NLA_NESTED }, |
---|
| 1795 | +}; |
---|
1656 | 1796 | |
---|
1657 | 1797 | static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
1658 | 1798 | struct netlink_ext_ack *extack) |
---|
.. | .. |
---|
1670 | 1810 | goto out; |
---|
1671 | 1811 | |
---|
1672 | 1812 | dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST); |
---|
1673 | | - if (dst_attr == NULL) |
---|
| 1813 | + if (!dst_attr) { |
---|
| 1814 | + NL_SET_ERR_MSG(extack, "Network address not specified"); |
---|
1674 | 1815 | goto out; |
---|
| 1816 | + } |
---|
1675 | 1817 | |
---|
1676 | 1818 | ndm = nlmsg_data(nlh); |
---|
1677 | 1819 | if (ndm->ndm_ifindex) { |
---|
.. | .. |
---|
1686 | 1828 | if (tbl == NULL) |
---|
1687 | 1829 | return -EAFNOSUPPORT; |
---|
1688 | 1830 | |
---|
1689 | | - if (nla_len(dst_attr) < (int)tbl->key_len) |
---|
| 1831 | + if (nla_len(dst_attr) < (int)tbl->key_len) { |
---|
| 1832 | + NL_SET_ERR_MSG(extack, "Invalid network address"); |
---|
1690 | 1833 | goto out; |
---|
| 1834 | + } |
---|
1691 | 1835 | |
---|
1692 | 1836 | if (ndm->ndm_flags & NTF_PROXY) { |
---|
1693 | 1837 | err = pneigh_delete(tbl, net, nla_data(dst_attr), dev); |
---|
.. | .. |
---|
1703 | 1847 | goto out; |
---|
1704 | 1848 | } |
---|
1705 | 1849 | |
---|
1706 | | - err = neigh_update(neigh, NULL, NUD_FAILED, |
---|
1707 | | - NEIGH_UPDATE_F_OVERRIDE | |
---|
1708 | | - NEIGH_UPDATE_F_ADMIN, |
---|
1709 | | - NETLINK_CB(skb).portid); |
---|
| 1850 | + err = __neigh_update(neigh, NULL, NUD_FAILED, |
---|
| 1851 | + NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN, |
---|
| 1852 | + NETLINK_CB(skb).portid, extack); |
---|
1710 | 1853 | write_lock_bh(&tbl->lock); |
---|
1711 | 1854 | neigh_release(neigh); |
---|
1712 | 1855 | neigh_remove_one(neigh, tbl); |
---|
.. | .. |
---|
1719 | 1862 | static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, |
---|
1720 | 1863 | struct netlink_ext_ack *extack) |
---|
1721 | 1864 | { |
---|
1722 | | - int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE; |
---|
| 1865 | + int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE | |
---|
| 1866 | + NEIGH_UPDATE_F_OVERRIDE_ISROUTER; |
---|
1723 | 1867 | struct net *net = sock_net(skb->sk); |
---|
1724 | 1868 | struct ndmsg *ndm; |
---|
1725 | 1869 | struct nlattr *tb[NDA_MAX+1]; |
---|
.. | .. |
---|
1727 | 1871 | struct net_device *dev = NULL; |
---|
1728 | 1872 | struct neighbour *neigh; |
---|
1729 | 1873 | void *dst, *lladdr; |
---|
| 1874 | + u8 protocol = 0; |
---|
1730 | 1875 | int err; |
---|
1731 | 1876 | |
---|
1732 | 1877 | ASSERT_RTNL(); |
---|
1733 | | - err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL, extack); |
---|
| 1878 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX, |
---|
| 1879 | + nda_policy, extack); |
---|
1734 | 1880 | if (err < 0) |
---|
1735 | 1881 | goto out; |
---|
1736 | 1882 | |
---|
1737 | 1883 | err = -EINVAL; |
---|
1738 | | - if (tb[NDA_DST] == NULL) |
---|
| 1884 | + if (!tb[NDA_DST]) { |
---|
| 1885 | + NL_SET_ERR_MSG(extack, "Network address not specified"); |
---|
1739 | 1886 | goto out; |
---|
| 1887 | + } |
---|
1740 | 1888 | |
---|
1741 | 1889 | ndm = nlmsg_data(nlh); |
---|
1742 | 1890 | if (ndm->ndm_ifindex) { |
---|
.. | .. |
---|
1746 | 1894 | goto out; |
---|
1747 | 1895 | } |
---|
1748 | 1896 | |
---|
1749 | | - if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) |
---|
| 1897 | + if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) { |
---|
| 1898 | + NL_SET_ERR_MSG(extack, "Invalid link address"); |
---|
1750 | 1899 | goto out; |
---|
| 1900 | + } |
---|
1751 | 1901 | } |
---|
1752 | 1902 | |
---|
1753 | 1903 | tbl = neigh_find_table(ndm->ndm_family); |
---|
1754 | 1904 | if (tbl == NULL) |
---|
1755 | 1905 | return -EAFNOSUPPORT; |
---|
1756 | 1906 | |
---|
1757 | | - if (nla_len(tb[NDA_DST]) < (int)tbl->key_len) |
---|
| 1907 | + if (nla_len(tb[NDA_DST]) < (int)tbl->key_len) { |
---|
| 1908 | + NL_SET_ERR_MSG(extack, "Invalid network address"); |
---|
1758 | 1909 | goto out; |
---|
| 1910 | + } |
---|
| 1911 | + |
---|
1759 | 1912 | dst = nla_data(tb[NDA_DST]); |
---|
1760 | 1913 | lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL; |
---|
| 1914 | + |
---|
| 1915 | + if (tb[NDA_PROTOCOL]) |
---|
| 1916 | + protocol = nla_get_u8(tb[NDA_PROTOCOL]); |
---|
1761 | 1917 | |
---|
1762 | 1918 | if (ndm->ndm_flags & NTF_PROXY) { |
---|
1763 | 1919 | struct pneigh_entry *pn; |
---|
.. | .. |
---|
1766 | 1922 | pn = pneigh_lookup(tbl, net, dst, dev, 1); |
---|
1767 | 1923 | if (pn) { |
---|
1768 | 1924 | pn->flags = ndm->ndm_flags; |
---|
| 1925 | + if (protocol) |
---|
| 1926 | + pn->protocol = protocol; |
---|
1769 | 1927 | err = 0; |
---|
1770 | 1928 | } |
---|
1771 | 1929 | goto out; |
---|
1772 | 1930 | } |
---|
1773 | 1931 | |
---|
1774 | | - if (dev == NULL) |
---|
| 1932 | + if (!dev) { |
---|
| 1933 | + NL_SET_ERR_MSG(extack, "Device not specified"); |
---|
1775 | 1934 | goto out; |
---|
| 1935 | + } |
---|
| 1936 | + |
---|
| 1937 | + if (tbl->allow_add && !tbl->allow_add(dev, extack)) { |
---|
| 1938 | + err = -EINVAL; |
---|
| 1939 | + goto out; |
---|
| 1940 | + } |
---|
1776 | 1941 | |
---|
1777 | 1942 | neigh = neigh_lookup(tbl, dst, dev); |
---|
1778 | 1943 | if (neigh == NULL) { |
---|
| 1944 | + bool exempt_from_gc; |
---|
| 1945 | + |
---|
1779 | 1946 | if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { |
---|
1780 | 1947 | err = -ENOENT; |
---|
1781 | 1948 | goto out; |
---|
1782 | 1949 | } |
---|
1783 | 1950 | |
---|
1784 | | - neigh = __neigh_lookup_errno(tbl, dst, dev); |
---|
| 1951 | + exempt_from_gc = ndm->ndm_state & NUD_PERMANENT || |
---|
| 1952 | + ndm->ndm_flags & NTF_EXT_LEARNED; |
---|
| 1953 | + neigh = ___neigh_create(tbl, dst, dev, |
---|
| 1954 | + ndm->ndm_flags & NTF_EXT_LEARNED, |
---|
| 1955 | + exempt_from_gc, true); |
---|
1785 | 1956 | if (IS_ERR(neigh)) { |
---|
1786 | 1957 | err = PTR_ERR(neigh); |
---|
1787 | 1958 | goto out; |
---|
.. | .. |
---|
1794 | 1965 | } |
---|
1795 | 1966 | |
---|
1796 | 1967 | if (!(nlh->nlmsg_flags & NLM_F_REPLACE)) |
---|
1797 | | - flags &= ~NEIGH_UPDATE_F_OVERRIDE; |
---|
| 1968 | + flags &= ~(NEIGH_UPDATE_F_OVERRIDE | |
---|
| 1969 | + NEIGH_UPDATE_F_OVERRIDE_ISROUTER); |
---|
1798 | 1970 | } |
---|
1799 | 1971 | |
---|
| 1972 | + if (protocol) |
---|
| 1973 | + neigh->protocol = protocol; |
---|
1800 | 1974 | if (ndm->ndm_flags & NTF_EXT_LEARNED) |
---|
1801 | 1975 | flags |= NEIGH_UPDATE_F_EXT_LEARNED; |
---|
| 1976 | + if (ndm->ndm_flags & NTF_ROUTER) |
---|
| 1977 | + flags |= NEIGH_UPDATE_F_ISROUTER; |
---|
| 1978 | + if (ndm->ndm_flags & NTF_USE) |
---|
| 1979 | + flags |= NEIGH_UPDATE_F_USE; |
---|
1802 | 1980 | |
---|
1803 | | - if (ndm->ndm_flags & NTF_USE) { |
---|
| 1981 | + err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags, |
---|
| 1982 | + NETLINK_CB(skb).portid, extack); |
---|
| 1983 | + if (!err && ndm->ndm_flags & NTF_USE) { |
---|
1804 | 1984 | neigh_event_send(neigh, NULL); |
---|
1805 | 1985 | err = 0; |
---|
1806 | | - } else |
---|
1807 | | - err = neigh_update(neigh, lladdr, ndm->ndm_state, flags, |
---|
1808 | | - NETLINK_CB(skb).portid); |
---|
| 1986 | + } |
---|
1809 | 1987 | neigh_release(neigh); |
---|
1810 | | - |
---|
1811 | 1988 | out: |
---|
1812 | 1989 | return err; |
---|
1813 | 1990 | } |
---|
.. | .. |
---|
1816 | 1993 | { |
---|
1817 | 1994 | struct nlattr *nest; |
---|
1818 | 1995 | |
---|
1819 | | - nest = nla_nest_start(skb, NDTA_PARMS); |
---|
| 1996 | + nest = nla_nest_start_noflag(skb, NDTA_PARMS); |
---|
1820 | 1997 | if (nest == NULL) |
---|
1821 | 1998 | return -ENOBUFS; |
---|
1822 | 1999 | |
---|
.. | .. |
---|
2018 | 2195 | bool found = false; |
---|
2019 | 2196 | int err, tidx; |
---|
2020 | 2197 | |
---|
2021 | | - err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX, |
---|
2022 | | - nl_neightbl_policy, extack); |
---|
| 2198 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ndtmsg), tb, NDTA_MAX, |
---|
| 2199 | + nl_neightbl_policy, extack); |
---|
2023 | 2200 | if (err < 0) |
---|
2024 | 2201 | goto errout; |
---|
2025 | 2202 | |
---|
.. | .. |
---|
2056 | 2233 | struct neigh_parms *p; |
---|
2057 | 2234 | int i, ifindex = 0; |
---|
2058 | 2235 | |
---|
2059 | | - err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS], |
---|
2060 | | - nl_ntbl_parm_policy, extack); |
---|
| 2236 | + err = nla_parse_nested_deprecated(tbp, NDTPA_MAX, |
---|
| 2237 | + tb[NDTA_PARMS], |
---|
| 2238 | + nl_ntbl_parm_policy, extack); |
---|
2061 | 2239 | if (err < 0) |
---|
2062 | 2240 | goto errout_tbl_lock; |
---|
2063 | 2241 | |
---|
.. | .. |
---|
2169 | 2347 | return err; |
---|
2170 | 2348 | } |
---|
2171 | 2349 | |
---|
| 2350 | +static int neightbl_valid_dump_info(const struct nlmsghdr *nlh, |
---|
| 2351 | + struct netlink_ext_ack *extack) |
---|
| 2352 | +{ |
---|
| 2353 | + struct ndtmsg *ndtm; |
---|
| 2354 | + |
---|
| 2355 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) { |
---|
| 2356 | + NL_SET_ERR_MSG(extack, "Invalid header for neighbor table dump request"); |
---|
| 2357 | + return -EINVAL; |
---|
| 2358 | + } |
---|
| 2359 | + |
---|
| 2360 | + ndtm = nlmsg_data(nlh); |
---|
| 2361 | + if (ndtm->ndtm_pad1 || ndtm->ndtm_pad2) { |
---|
| 2362 | + NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor table dump request"); |
---|
| 2363 | + return -EINVAL; |
---|
| 2364 | + } |
---|
| 2365 | + |
---|
| 2366 | + if (nlmsg_attrlen(nlh, sizeof(*ndtm))) { |
---|
| 2367 | + NL_SET_ERR_MSG(extack, "Invalid data after header in neighbor table dump request"); |
---|
| 2368 | + return -EINVAL; |
---|
| 2369 | + } |
---|
| 2370 | + |
---|
| 2371 | + return 0; |
---|
| 2372 | +} |
---|
| 2373 | + |
---|
2172 | 2374 | static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) |
---|
2173 | 2375 | { |
---|
| 2376 | + const struct nlmsghdr *nlh = cb->nlh; |
---|
2174 | 2377 | struct net *net = sock_net(skb->sk); |
---|
2175 | 2378 | int family, tidx, nidx = 0; |
---|
2176 | 2379 | int tbl_skip = cb->args[0]; |
---|
2177 | 2380 | int neigh_skip = cb->args[1]; |
---|
2178 | 2381 | struct neigh_table *tbl; |
---|
2179 | 2382 | |
---|
2180 | | - family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; |
---|
| 2383 | + if (cb->strict_check) { |
---|
| 2384 | + int err = neightbl_valid_dump_info(nlh, cb->extack); |
---|
| 2385 | + |
---|
| 2386 | + if (err < 0) |
---|
| 2387 | + return err; |
---|
| 2388 | + } |
---|
| 2389 | + |
---|
| 2390 | + family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family; |
---|
2181 | 2391 | |
---|
2182 | 2392 | for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { |
---|
2183 | 2393 | struct neigh_parms *p; |
---|
.. | .. |
---|
2190 | 2400 | continue; |
---|
2191 | 2401 | |
---|
2192 | 2402 | if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid, |
---|
2193 | | - cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL, |
---|
| 2403 | + nlh->nlmsg_seq, RTM_NEWNEIGHTBL, |
---|
2194 | 2404 | NLM_F_MULTI) < 0) |
---|
2195 | 2405 | break; |
---|
2196 | 2406 | |
---|
.. | .. |
---|
2205 | 2415 | |
---|
2206 | 2416 | if (neightbl_fill_param_info(skb, tbl, p, |
---|
2207 | 2417 | NETLINK_CB(cb->skb).portid, |
---|
2208 | | - cb->nlh->nlmsg_seq, |
---|
| 2418 | + nlh->nlmsg_seq, |
---|
2209 | 2419 | RTM_NEWNEIGHTBL, |
---|
2210 | 2420 | NLM_F_MULTI) < 0) |
---|
2211 | 2421 | goto out; |
---|
.. | .. |
---|
2267 | 2477 | nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci)) |
---|
2268 | 2478 | goto nla_put_failure; |
---|
2269 | 2479 | |
---|
| 2480 | + if (neigh->protocol && nla_put_u8(skb, NDA_PROTOCOL, neigh->protocol)) |
---|
| 2481 | + goto nla_put_failure; |
---|
| 2482 | + |
---|
2270 | 2483 | nlmsg_end(skb, nlh); |
---|
2271 | 2484 | return 0; |
---|
2272 | 2485 | |
---|
.. | .. |
---|
2298 | 2511 | if (nla_put(skb, NDA_DST, tbl->key_len, pn->key)) |
---|
2299 | 2512 | goto nla_put_failure; |
---|
2300 | 2513 | |
---|
| 2514 | + if (pn->protocol && nla_put_u8(skb, NDA_PROTOCOL, pn->protocol)) |
---|
| 2515 | + goto nla_put_failure; |
---|
| 2516 | + |
---|
2301 | 2517 | nlmsg_end(skb, nlh); |
---|
2302 | 2518 | return 0; |
---|
2303 | 2519 | |
---|
.. | .. |
---|
2319 | 2535 | if (!master_idx) |
---|
2320 | 2536 | return false; |
---|
2321 | 2537 | |
---|
2322 | | - master = netdev_master_upper_dev_get(dev); |
---|
| 2538 | + master = dev ? netdev_master_upper_dev_get(dev) : NULL; |
---|
2323 | 2539 | if (!master || master->ifindex != master_idx) |
---|
2324 | 2540 | return true; |
---|
2325 | 2541 | |
---|
.. | .. |
---|
2328 | 2544 | |
---|
2329 | 2545 | static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx) |
---|
2330 | 2546 | { |
---|
2331 | | - if (filter_idx && dev->ifindex != filter_idx) |
---|
| 2547 | + if (filter_idx && (!dev || dev->ifindex != filter_idx)) |
---|
2332 | 2548 | return true; |
---|
2333 | 2549 | |
---|
2334 | 2550 | return false; |
---|
2335 | 2551 | } |
---|
2336 | 2552 | |
---|
| 2553 | +struct neigh_dump_filter { |
---|
| 2554 | + int master_idx; |
---|
| 2555 | + int dev_idx; |
---|
| 2556 | +}; |
---|
| 2557 | + |
---|
2337 | 2558 | static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, |
---|
2338 | | - struct netlink_callback *cb) |
---|
| 2559 | + struct netlink_callback *cb, |
---|
| 2560 | + struct neigh_dump_filter *filter) |
---|
2339 | 2561 | { |
---|
2340 | 2562 | struct net *net = sock_net(skb->sk); |
---|
2341 | | - const struct nlmsghdr *nlh = cb->nlh; |
---|
2342 | | - struct nlattr *tb[NDA_MAX + 1]; |
---|
2343 | 2563 | struct neighbour *n; |
---|
2344 | 2564 | int rc, h, s_h = cb->args[1]; |
---|
2345 | 2565 | int idx, s_idx = idx = cb->args[2]; |
---|
2346 | 2566 | struct neigh_hash_table *nht; |
---|
2347 | | - int filter_master_idx = 0, filter_idx = 0; |
---|
2348 | 2567 | unsigned int flags = NLM_F_MULTI; |
---|
2349 | | - int err; |
---|
2350 | 2568 | |
---|
2351 | | - err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL, NULL); |
---|
2352 | | - if (!err) { |
---|
2353 | | - if (tb[NDA_IFINDEX]) { |
---|
2354 | | - if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32)) |
---|
2355 | | - return -EINVAL; |
---|
2356 | | - filter_idx = nla_get_u32(tb[NDA_IFINDEX]); |
---|
2357 | | - } |
---|
2358 | | - if (tb[NDA_MASTER]) { |
---|
2359 | | - if (nla_len(tb[NDA_MASTER]) != sizeof(u32)) |
---|
2360 | | - return -EINVAL; |
---|
2361 | | - filter_master_idx = nla_get_u32(tb[NDA_MASTER]); |
---|
2362 | | - } |
---|
2363 | | - if (filter_idx || filter_master_idx) |
---|
2364 | | - flags |= NLM_F_DUMP_FILTERED; |
---|
2365 | | - } |
---|
| 2569 | + if (filter->dev_idx || filter->master_idx) |
---|
| 2570 | + flags |= NLM_F_DUMP_FILTERED; |
---|
2366 | 2571 | |
---|
2367 | 2572 | rcu_read_lock_bh(); |
---|
2368 | 2573 | nht = rcu_dereference_bh(tbl->nht); |
---|
.. | .. |
---|
2375 | 2580 | n = rcu_dereference_bh(n->next)) { |
---|
2376 | 2581 | if (idx < s_idx || !net_eq(dev_net(n->dev), net)) |
---|
2377 | 2582 | goto next; |
---|
2378 | | - if (neigh_ifindex_filtered(n->dev, filter_idx) || |
---|
2379 | | - neigh_master_filtered(n->dev, filter_master_idx)) |
---|
| 2583 | + if (neigh_ifindex_filtered(n->dev, filter->dev_idx) || |
---|
| 2584 | + neigh_master_filtered(n->dev, filter->master_idx)) |
---|
2380 | 2585 | goto next; |
---|
2381 | 2586 | if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid, |
---|
2382 | 2587 | cb->nlh->nlmsg_seq, |
---|
.. | .. |
---|
2398 | 2603 | } |
---|
2399 | 2604 | |
---|
2400 | 2605 | static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, |
---|
2401 | | - struct netlink_callback *cb) |
---|
| 2606 | + struct netlink_callback *cb, |
---|
| 2607 | + struct neigh_dump_filter *filter) |
---|
2402 | 2608 | { |
---|
2403 | 2609 | struct pneigh_entry *n; |
---|
2404 | 2610 | struct net *net = sock_net(skb->sk); |
---|
2405 | 2611 | int rc, h, s_h = cb->args[3]; |
---|
2406 | 2612 | int idx, s_idx = idx = cb->args[4]; |
---|
| 2613 | + unsigned int flags = NLM_F_MULTI; |
---|
| 2614 | + |
---|
| 2615 | + if (filter->dev_idx || filter->master_idx) |
---|
| 2616 | + flags |= NLM_F_DUMP_FILTERED; |
---|
2407 | 2617 | |
---|
2408 | 2618 | read_lock_bh(&tbl->lock); |
---|
2409 | 2619 | |
---|
.. | .. |
---|
2413 | 2623 | for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) { |
---|
2414 | 2624 | if (idx < s_idx || pneigh_net(n) != net) |
---|
2415 | 2625 | goto next; |
---|
| 2626 | + if (neigh_ifindex_filtered(n->dev, filter->dev_idx) || |
---|
| 2627 | + neigh_master_filtered(n->dev, filter->master_idx)) |
---|
| 2628 | + goto next; |
---|
2416 | 2629 | if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid, |
---|
2417 | 2630 | cb->nlh->nlmsg_seq, |
---|
2418 | | - RTM_NEWNEIGH, |
---|
2419 | | - NLM_F_MULTI, tbl) < 0) { |
---|
| 2631 | + RTM_NEWNEIGH, flags, tbl) < 0) { |
---|
2420 | 2632 | read_unlock_bh(&tbl->lock); |
---|
2421 | 2633 | rc = -1; |
---|
2422 | 2634 | goto out; |
---|
.. | .. |
---|
2435 | 2647 | |
---|
2436 | 2648 | } |
---|
2437 | 2649 | |
---|
| 2650 | +static int neigh_valid_dump_req(const struct nlmsghdr *nlh, |
---|
| 2651 | + bool strict_check, |
---|
| 2652 | + struct neigh_dump_filter *filter, |
---|
| 2653 | + struct netlink_ext_ack *extack) |
---|
| 2654 | +{ |
---|
| 2655 | + struct nlattr *tb[NDA_MAX + 1]; |
---|
| 2656 | + int err, i; |
---|
| 2657 | + |
---|
| 2658 | + if (strict_check) { |
---|
| 2659 | + struct ndmsg *ndm; |
---|
| 2660 | + |
---|
| 2661 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) { |
---|
| 2662 | + NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request"); |
---|
| 2663 | + return -EINVAL; |
---|
| 2664 | + } |
---|
| 2665 | + |
---|
| 2666 | + ndm = nlmsg_data(nlh); |
---|
| 2667 | + if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_ifindex || |
---|
| 2668 | + ndm->ndm_state || ndm->ndm_type) { |
---|
| 2669 | + NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request"); |
---|
| 2670 | + return -EINVAL; |
---|
| 2671 | + } |
---|
| 2672 | + |
---|
| 2673 | + if (ndm->ndm_flags & ~NTF_PROXY) { |
---|
| 2674 | + NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor dump request"); |
---|
| 2675 | + return -EINVAL; |
---|
| 2676 | + } |
---|
| 2677 | + |
---|
| 2678 | + err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), |
---|
| 2679 | + tb, NDA_MAX, nda_policy, |
---|
| 2680 | + extack); |
---|
| 2681 | + } else { |
---|
| 2682 | + err = nlmsg_parse_deprecated(nlh, sizeof(struct ndmsg), tb, |
---|
| 2683 | + NDA_MAX, nda_policy, extack); |
---|
| 2684 | + } |
---|
| 2685 | + if (err < 0) |
---|
| 2686 | + return err; |
---|
| 2687 | + |
---|
| 2688 | + for (i = 0; i <= NDA_MAX; ++i) { |
---|
| 2689 | + if (!tb[i]) |
---|
| 2690 | + continue; |
---|
| 2691 | + |
---|
| 2692 | + /* all new attributes should require strict_check */ |
---|
| 2693 | + switch (i) { |
---|
| 2694 | + case NDA_IFINDEX: |
---|
| 2695 | + filter->dev_idx = nla_get_u32(tb[i]); |
---|
| 2696 | + break; |
---|
| 2697 | + case NDA_MASTER: |
---|
| 2698 | + filter->master_idx = nla_get_u32(tb[i]); |
---|
| 2699 | + break; |
---|
| 2700 | + default: |
---|
| 2701 | + if (strict_check) { |
---|
| 2702 | + NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request"); |
---|
| 2703 | + return -EINVAL; |
---|
| 2704 | + } |
---|
| 2705 | + } |
---|
| 2706 | + } |
---|
| 2707 | + |
---|
| 2708 | + return 0; |
---|
| 2709 | +} |
---|
| 2710 | + |
---|
2438 | 2711 | static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) |
---|
2439 | 2712 | { |
---|
| 2713 | + const struct nlmsghdr *nlh = cb->nlh; |
---|
| 2714 | + struct neigh_dump_filter filter = {}; |
---|
2440 | 2715 | struct neigh_table *tbl; |
---|
2441 | 2716 | int t, family, s_t; |
---|
2442 | 2717 | int proxy = 0; |
---|
2443 | 2718 | int err; |
---|
2444 | 2719 | |
---|
2445 | | - family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; |
---|
| 2720 | + family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family; |
---|
2446 | 2721 | |
---|
2447 | 2722 | /* check for full ndmsg structure presence, family member is |
---|
2448 | 2723 | * the same for both structures |
---|
2449 | 2724 | */ |
---|
2450 | | - if (nlmsg_len(cb->nlh) >= sizeof(struct ndmsg) && |
---|
2451 | | - ((struct ndmsg *) nlmsg_data(cb->nlh))->ndm_flags == NTF_PROXY) |
---|
| 2725 | + if (nlmsg_len(nlh) >= sizeof(struct ndmsg) && |
---|
| 2726 | + ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY) |
---|
2452 | 2727 | proxy = 1; |
---|
| 2728 | + |
---|
| 2729 | + err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack); |
---|
| 2730 | + if (err < 0 && cb->strict_check) |
---|
| 2731 | + return err; |
---|
2453 | 2732 | |
---|
2454 | 2733 | s_t = cb->args[0]; |
---|
2455 | 2734 | |
---|
.. | .. |
---|
2464 | 2743 | memset(&cb->args[1], 0, sizeof(cb->args) - |
---|
2465 | 2744 | sizeof(cb->args[0])); |
---|
2466 | 2745 | if (proxy) |
---|
2467 | | - err = pneigh_dump_table(tbl, skb, cb); |
---|
| 2746 | + err = pneigh_dump_table(tbl, skb, cb, &filter); |
---|
2468 | 2747 | else |
---|
2469 | | - err = neigh_dump_table(tbl, skb, cb); |
---|
| 2748 | + err = neigh_dump_table(tbl, skb, cb, &filter); |
---|
2470 | 2749 | if (err < 0) |
---|
2471 | 2750 | break; |
---|
2472 | 2751 | } |
---|
2473 | 2752 | |
---|
2474 | 2753 | cb->args[0] = t; |
---|
2475 | 2754 | return skb->len; |
---|
| 2755 | +} |
---|
| 2756 | + |
---|
| 2757 | +static int neigh_valid_get_req(const struct nlmsghdr *nlh, |
---|
| 2758 | + struct neigh_table **tbl, |
---|
| 2759 | + void **dst, int *dev_idx, u8 *ndm_flags, |
---|
| 2760 | + struct netlink_ext_ack *extack) |
---|
| 2761 | +{ |
---|
| 2762 | + struct nlattr *tb[NDA_MAX + 1]; |
---|
| 2763 | + struct ndmsg *ndm; |
---|
| 2764 | + int err, i; |
---|
| 2765 | + |
---|
| 2766 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) { |
---|
| 2767 | + NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request"); |
---|
| 2768 | + return -EINVAL; |
---|
| 2769 | + } |
---|
| 2770 | + |
---|
| 2771 | + ndm = nlmsg_data(nlh); |
---|
| 2772 | + if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_state || |
---|
| 2773 | + ndm->ndm_type) { |
---|
| 2774 | + NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request"); |
---|
| 2775 | + return -EINVAL; |
---|
| 2776 | + } |
---|
| 2777 | + |
---|
| 2778 | + if (ndm->ndm_flags & ~NTF_PROXY) { |
---|
| 2779 | + NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request"); |
---|
| 2780 | + return -EINVAL; |
---|
| 2781 | + } |
---|
| 2782 | + |
---|
| 2783 | + err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb, |
---|
| 2784 | + NDA_MAX, nda_policy, extack); |
---|
| 2785 | + if (err < 0) |
---|
| 2786 | + return err; |
---|
| 2787 | + |
---|
| 2788 | + *ndm_flags = ndm->ndm_flags; |
---|
| 2789 | + *dev_idx = ndm->ndm_ifindex; |
---|
| 2790 | + *tbl = neigh_find_table(ndm->ndm_family); |
---|
| 2791 | + if (*tbl == NULL) { |
---|
| 2792 | + NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request"); |
---|
| 2793 | + return -EAFNOSUPPORT; |
---|
| 2794 | + } |
---|
| 2795 | + |
---|
| 2796 | + for (i = 0; i <= NDA_MAX; ++i) { |
---|
| 2797 | + if (!tb[i]) |
---|
| 2798 | + continue; |
---|
| 2799 | + |
---|
| 2800 | + switch (i) { |
---|
| 2801 | + case NDA_DST: |
---|
| 2802 | + if (nla_len(tb[i]) != (int)(*tbl)->key_len) { |
---|
| 2803 | + NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request"); |
---|
| 2804 | + return -EINVAL; |
---|
| 2805 | + } |
---|
| 2806 | + *dst = nla_data(tb[i]); |
---|
| 2807 | + break; |
---|
| 2808 | + default: |
---|
| 2809 | + NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request"); |
---|
| 2810 | + return -EINVAL; |
---|
| 2811 | + } |
---|
| 2812 | + } |
---|
| 2813 | + |
---|
| 2814 | + return 0; |
---|
| 2815 | +} |
---|
| 2816 | + |
---|
| 2817 | +static inline size_t neigh_nlmsg_size(void) |
---|
| 2818 | +{ |
---|
| 2819 | + return NLMSG_ALIGN(sizeof(struct ndmsg)) |
---|
| 2820 | + + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */ |
---|
| 2821 | + + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */ |
---|
| 2822 | + + nla_total_size(sizeof(struct nda_cacheinfo)) |
---|
| 2823 | + + nla_total_size(4) /* NDA_PROBES */ |
---|
| 2824 | + + nla_total_size(1); /* NDA_PROTOCOL */ |
---|
| 2825 | +} |
---|
| 2826 | + |
---|
| 2827 | +static int neigh_get_reply(struct net *net, struct neighbour *neigh, |
---|
| 2828 | + u32 pid, u32 seq) |
---|
| 2829 | +{ |
---|
| 2830 | + struct sk_buff *skb; |
---|
| 2831 | + int err = 0; |
---|
| 2832 | + |
---|
| 2833 | + skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL); |
---|
| 2834 | + if (!skb) |
---|
| 2835 | + return -ENOBUFS; |
---|
| 2836 | + |
---|
| 2837 | + err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0); |
---|
| 2838 | + if (err) { |
---|
| 2839 | + kfree_skb(skb); |
---|
| 2840 | + goto errout; |
---|
| 2841 | + } |
---|
| 2842 | + |
---|
| 2843 | + err = rtnl_unicast(skb, net, pid); |
---|
| 2844 | +errout: |
---|
| 2845 | + return err; |
---|
| 2846 | +} |
---|
| 2847 | + |
---|
| 2848 | +static inline size_t pneigh_nlmsg_size(void) |
---|
| 2849 | +{ |
---|
| 2850 | + return NLMSG_ALIGN(sizeof(struct ndmsg)) |
---|
| 2851 | + + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */ |
---|
| 2852 | + + nla_total_size(1); /* NDA_PROTOCOL */ |
---|
| 2853 | +} |
---|
| 2854 | + |
---|
| 2855 | +static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh, |
---|
| 2856 | + u32 pid, u32 seq, struct neigh_table *tbl) |
---|
| 2857 | +{ |
---|
| 2858 | + struct sk_buff *skb; |
---|
| 2859 | + int err = 0; |
---|
| 2860 | + |
---|
| 2861 | + skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL); |
---|
| 2862 | + if (!skb) |
---|
| 2863 | + return -ENOBUFS; |
---|
| 2864 | + |
---|
| 2865 | + err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl); |
---|
| 2866 | + if (err) { |
---|
| 2867 | + kfree_skb(skb); |
---|
| 2868 | + goto errout; |
---|
| 2869 | + } |
---|
| 2870 | + |
---|
| 2871 | + err = rtnl_unicast(skb, net, pid); |
---|
| 2872 | +errout: |
---|
| 2873 | + return err; |
---|
| 2874 | +} |
---|
| 2875 | + |
---|
| 2876 | +static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh, |
---|
| 2877 | + struct netlink_ext_ack *extack) |
---|
| 2878 | +{ |
---|
| 2879 | + struct net *net = sock_net(in_skb->sk); |
---|
| 2880 | + struct net_device *dev = NULL; |
---|
| 2881 | + struct neigh_table *tbl = NULL; |
---|
| 2882 | + struct neighbour *neigh; |
---|
| 2883 | + void *dst = NULL; |
---|
| 2884 | + u8 ndm_flags = 0; |
---|
| 2885 | + int dev_idx = 0; |
---|
| 2886 | + int err; |
---|
| 2887 | + |
---|
| 2888 | + err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags, |
---|
| 2889 | + extack); |
---|
| 2890 | + if (err < 0) |
---|
| 2891 | + return err; |
---|
| 2892 | + |
---|
| 2893 | + if (dev_idx) { |
---|
| 2894 | + dev = __dev_get_by_index(net, dev_idx); |
---|
| 2895 | + if (!dev) { |
---|
| 2896 | + NL_SET_ERR_MSG(extack, "Unknown device ifindex"); |
---|
| 2897 | + return -ENODEV; |
---|
| 2898 | + } |
---|
| 2899 | + } |
---|
| 2900 | + |
---|
| 2901 | + if (!dst) { |
---|
| 2902 | + NL_SET_ERR_MSG(extack, "Network address not specified"); |
---|
| 2903 | + return -EINVAL; |
---|
| 2904 | + } |
---|
| 2905 | + |
---|
| 2906 | + if (ndm_flags & NTF_PROXY) { |
---|
| 2907 | + struct pneigh_entry *pn; |
---|
| 2908 | + |
---|
| 2909 | + pn = pneigh_lookup(tbl, net, dst, dev, 0); |
---|
| 2910 | + if (!pn) { |
---|
| 2911 | + NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found"); |
---|
| 2912 | + return -ENOENT; |
---|
| 2913 | + } |
---|
| 2914 | + return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid, |
---|
| 2915 | + nlh->nlmsg_seq, tbl); |
---|
| 2916 | + } |
---|
| 2917 | + |
---|
| 2918 | + if (!dev) { |
---|
| 2919 | + NL_SET_ERR_MSG(extack, "No device specified"); |
---|
| 2920 | + return -EINVAL; |
---|
| 2921 | + } |
---|
| 2922 | + |
---|
| 2923 | + neigh = neigh_lookup(tbl, dst, dev); |
---|
| 2924 | + if (!neigh) { |
---|
| 2925 | + NL_SET_ERR_MSG(extack, "Neighbour entry not found"); |
---|
| 2926 | + return -ENOENT; |
---|
| 2927 | + } |
---|
| 2928 | + |
---|
| 2929 | + err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid, |
---|
| 2930 | + nlh->nlmsg_seq); |
---|
| 2931 | + |
---|
| 2932 | + neigh_release(neigh); |
---|
| 2933 | + |
---|
| 2934 | + return err; |
---|
2476 | 2935 | } |
---|
2477 | 2936 | |
---|
2478 | 2937 | void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie) |
---|
.. | .. |
---|
2521 | 2980 | rcu_assign_pointer(*np, |
---|
2522 | 2981 | rcu_dereference_protected(n->next, |
---|
2523 | 2982 | lockdep_is_held(&tbl->lock))); |
---|
2524 | | - n->dead = 1; |
---|
| 2983 | + neigh_mark_dead(n); |
---|
2525 | 2984 | } else |
---|
2526 | 2985 | np = &n->next; |
---|
2527 | 2986 | write_unlock(&n->lock); |
---|
.. | .. |
---|
2584 | 3043 | struct net *net = seq_file_net(seq); |
---|
2585 | 3044 | struct neigh_hash_table *nht = state->nht; |
---|
2586 | 3045 | struct neighbour *n = NULL; |
---|
2587 | | - int bucket = state->bucket; |
---|
| 3046 | + int bucket; |
---|
2588 | 3047 | |
---|
2589 | 3048 | state->flags &= ~NEIGH_SEQ_IS_PNEIGH; |
---|
2590 | 3049 | for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) { |
---|
.. | .. |
---|
2896 | 3355 | }; |
---|
2897 | 3356 | #endif /* CONFIG_PROC_FS */ |
---|
2898 | 3357 | |
---|
2899 | | -static inline size_t neigh_nlmsg_size(void) |
---|
2900 | | -{ |
---|
2901 | | - return NLMSG_ALIGN(sizeof(struct ndmsg)) |
---|
2902 | | - + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */ |
---|
2903 | | - + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */ |
---|
2904 | | - + nla_total_size(sizeof(struct nda_cacheinfo)) |
---|
2905 | | - + nla_total_size(4); /* NDA_PROBES */ |
---|
2906 | | -} |
---|
2907 | | - |
---|
2908 | 3358 | static void __neigh_notify(struct neighbour *n, int type, int flags, |
---|
2909 | 3359 | u32 pid) |
---|
2910 | 3360 | { |
---|
.. | .. |
---|
2937 | 3387 | EXPORT_SYMBOL(neigh_app_ns); |
---|
2938 | 3388 | |
---|
2939 | 3389 | #ifdef CONFIG_SYSCTL |
---|
2940 | | -static int zero; |
---|
2941 | | -static int int_max = INT_MAX; |
---|
2942 | 3390 | static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN); |
---|
2943 | 3391 | |
---|
2944 | 3392 | static int proc_unres_qlen(struct ctl_table *ctl, int write, |
---|
2945 | | - void __user *buffer, size_t *lenp, loff_t *ppos) |
---|
| 3393 | + void *buffer, size_t *lenp, loff_t *ppos) |
---|
2946 | 3394 | { |
---|
2947 | 3395 | int size, ret; |
---|
2948 | 3396 | struct ctl_table tmp = *ctl; |
---|
2949 | 3397 | |
---|
2950 | | - tmp.extra1 = &zero; |
---|
| 3398 | + tmp.extra1 = SYSCTL_ZERO; |
---|
2951 | 3399 | tmp.extra2 = &unres_qlen_max; |
---|
2952 | 3400 | tmp.data = &size; |
---|
2953 | 3401 | |
---|
.. | .. |
---|
3006 | 3454 | } |
---|
3007 | 3455 | |
---|
3008 | 3456 | static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write, |
---|
3009 | | - void __user *buffer, |
---|
3010 | | - size_t *lenp, loff_t *ppos) |
---|
| 3457 | + void *buffer, size_t *lenp, |
---|
| 3458 | + loff_t *ppos) |
---|
3011 | 3459 | { |
---|
3012 | 3460 | struct ctl_table tmp = *ctl; |
---|
3013 | 3461 | int ret; |
---|
3014 | 3462 | |
---|
3015 | | - tmp.extra1 = &zero; |
---|
3016 | | - tmp.extra2 = &int_max; |
---|
| 3463 | + tmp.extra1 = SYSCTL_ZERO; |
---|
| 3464 | + tmp.extra2 = SYSCTL_INT_MAX; |
---|
3017 | 3465 | |
---|
3018 | 3466 | ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); |
---|
3019 | 3467 | neigh_proc_update(ctl, write); |
---|
3020 | 3468 | return ret; |
---|
3021 | 3469 | } |
---|
3022 | 3470 | |
---|
3023 | | -int neigh_proc_dointvec(struct ctl_table *ctl, int write, |
---|
3024 | | - void __user *buffer, size_t *lenp, loff_t *ppos) |
---|
| 3471 | +int neigh_proc_dointvec(struct ctl_table *ctl, int write, void *buffer, |
---|
| 3472 | + size_t *lenp, loff_t *ppos) |
---|
3025 | 3473 | { |
---|
3026 | 3474 | int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); |
---|
3027 | 3475 | |
---|
.. | .. |
---|
3030 | 3478 | } |
---|
3031 | 3479 | EXPORT_SYMBOL(neigh_proc_dointvec); |
---|
3032 | 3480 | |
---|
3033 | | -int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, |
---|
3034 | | - void __user *buffer, |
---|
| 3481 | +int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, void *buffer, |
---|
3035 | 3482 | size_t *lenp, loff_t *ppos) |
---|
3036 | 3483 | { |
---|
3037 | 3484 | int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos); |
---|
.. | .. |
---|
3042 | 3489 | EXPORT_SYMBOL(neigh_proc_dointvec_jiffies); |
---|
3043 | 3490 | |
---|
3044 | 3491 | static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write, |
---|
3045 | | - void __user *buffer, |
---|
3046 | | - size_t *lenp, loff_t *ppos) |
---|
| 3492 | + void *buffer, size_t *lenp, |
---|
| 3493 | + loff_t *ppos) |
---|
3047 | 3494 | { |
---|
3048 | 3495 | int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos); |
---|
3049 | 3496 | |
---|
.. | .. |
---|
3052 | 3499 | } |
---|
3053 | 3500 | |
---|
3054 | 3501 | int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write, |
---|
3055 | | - void __user *buffer, |
---|
3056 | | - size_t *lenp, loff_t *ppos) |
---|
| 3502 | + void *buffer, size_t *lenp, loff_t *ppos) |
---|
3057 | 3503 | { |
---|
3058 | 3504 | int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos); |
---|
3059 | 3505 | |
---|
.. | .. |
---|
3063 | 3509 | EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies); |
---|
3064 | 3510 | |
---|
3065 | 3511 | static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write, |
---|
3066 | | - void __user *buffer, |
---|
3067 | | - size_t *lenp, loff_t *ppos) |
---|
| 3512 | + void *buffer, size_t *lenp, |
---|
| 3513 | + loff_t *ppos) |
---|
3068 | 3514 | { |
---|
3069 | 3515 | int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos); |
---|
3070 | 3516 | |
---|
.. | .. |
---|
3073 | 3519 | } |
---|
3074 | 3520 | |
---|
3075 | 3521 | static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write, |
---|
3076 | | - void __user *buffer, |
---|
3077 | | - size_t *lenp, loff_t *ppos) |
---|
| 3522 | + void *buffer, size_t *lenp, |
---|
| 3523 | + loff_t *ppos) |
---|
3078 | 3524 | { |
---|
3079 | 3525 | struct neigh_parms *p = ctl->extra2; |
---|
3080 | 3526 | int ret; |
---|
.. | .. |
---|
3118 | 3564 | #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \ |
---|
3119 | 3565 | NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies) |
---|
3120 | 3566 | |
---|
3121 | | -#define NEIGH_SYSCTL_MS_JIFFIES_ENTRY(attr, name) \ |
---|
3122 | | - NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies) |
---|
3123 | | - |
---|
3124 | 3567 | #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \ |
---|
3125 | 3568 | NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies) |
---|
3126 | 3569 | |
---|
.. | .. |
---|
3158 | 3601 | .procname = "gc_thresh1", |
---|
3159 | 3602 | .maxlen = sizeof(int), |
---|
3160 | 3603 | .mode = 0644, |
---|
3161 | | - .extra1 = &zero, |
---|
3162 | | - .extra2 = &int_max, |
---|
| 3604 | + .extra1 = SYSCTL_ZERO, |
---|
| 3605 | + .extra2 = SYSCTL_INT_MAX, |
---|
3163 | 3606 | .proc_handler = proc_dointvec_minmax, |
---|
3164 | 3607 | }, |
---|
3165 | 3608 | [NEIGH_VAR_GC_THRESH2] = { |
---|
3166 | 3609 | .procname = "gc_thresh2", |
---|
3167 | 3610 | .maxlen = sizeof(int), |
---|
3168 | 3611 | .mode = 0644, |
---|
3169 | | - .extra1 = &zero, |
---|
3170 | | - .extra2 = &int_max, |
---|
| 3612 | + .extra1 = SYSCTL_ZERO, |
---|
| 3613 | + .extra2 = SYSCTL_INT_MAX, |
---|
3171 | 3614 | .proc_handler = proc_dointvec_minmax, |
---|
3172 | 3615 | }, |
---|
3173 | 3616 | [NEIGH_VAR_GC_THRESH3] = { |
---|
3174 | 3617 | .procname = "gc_thresh3", |
---|
3175 | 3618 | .maxlen = sizeof(int), |
---|
3176 | 3619 | .mode = 0644, |
---|
3177 | | - .extra1 = &zero, |
---|
3178 | | - .extra2 = &int_max, |
---|
| 3620 | + .extra1 = SYSCTL_ZERO, |
---|
| 3621 | + .extra2 = SYSCTL_INT_MAX, |
---|
3179 | 3622 | .proc_handler = proc_dointvec_minmax, |
---|
3180 | 3623 | }, |
---|
3181 | 3624 | {}, |
---|
.. | .. |
---|
3288 | 3731 | { |
---|
3289 | 3732 | rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0); |
---|
3290 | 3733 | rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0); |
---|
3291 | | - rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, 0); |
---|
| 3734 | + rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0); |
---|
3292 | 3735 | |
---|
3293 | 3736 | rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info, |
---|
3294 | 3737 | 0); |
---|