forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/net/core/neighbour.c
....@@ -1,14 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Generic address resolution entity
34 *
45 * Authors:
56 * Pedro Roque <roque@di.fc.ul.pt>
67 * 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.
128 *
139 * Fixes:
1410 * Vitaly E. Lavrov releasing NULL neighbor in neigh_add.
....@@ -42,6 +38,8 @@
4238 #include <linux/log2.h>
4339 #include <linux/inetdevice.h>
4440 #include <net/addrconf.h>
41
+
42
+#include <trace/events/neigh.h>
4543
4644 #define DEBUG
4745 #define NEIGH_DEBUG 1
....@@ -100,9 +98,7 @@
10098
10199 static void neigh_cleanup_and_release(struct neighbour *neigh)
102100 {
103
- if (neigh->parms->neigh_cleanup)
104
- neigh->parms->neigh_cleanup(neigh);
105
-
101
+ trace_neigh_cleanup_and_release(neigh, 0);
106102 __neigh_notify(neigh, RTM_DELNEIGH, 0, 0);
107103 call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
108104 neigh_release(neigh);
....@@ -120,21 +116,81 @@
120116 }
121117 EXPORT_SYMBOL(neigh_rand_reach_time);
122118
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
+}
123127
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)
126183 {
127184 bool retval = false;
128185
129186 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) {
132188 struct neighbour *neigh;
133189
134190 neigh = rcu_dereference_protected(n->next,
135191 lockdep_is_held(&tbl->lock));
136192 rcu_assign_pointer(*np, neigh);
137
- n->dead = 1;
193
+ neigh_mark_dead(n);
138194 retval = true;
139195 }
140196 write_unlock(&n->lock);
....@@ -160,7 +216,7 @@
160216 while ((n = rcu_dereference_protected(*np,
161217 lockdep_is_held(&tbl->lock)))) {
162218 if (n == ndel)
163
- return neigh_del(n, 0, 0, np, tbl);
219
+ return neigh_del(n, np, tbl);
164220 np = &n->next;
165221 }
166222 return false;
....@@ -168,32 +224,32 @@
168224
169225 static int neigh_forced_gc(struct neigh_table *tbl)
170226 {
227
+ int max_clean = atomic_read(&tbl->gc_entries) - tbl->gc_thresh2;
228
+ unsigned long tref = jiffies - 5 * HZ;
229
+ struct neighbour *n, *tmp;
171230 int shrunk = 0;
172
- int i;
173
- struct neigh_hash_table *nht;
174231
175232 NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs);
176233
177234 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;
183235
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_after(tref, n->updated))
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;
197253 }
198254 }
199255
....@@ -224,17 +280,33 @@
224280 return 0;
225281 }
226282
227
-static void pneigh_queue_purge(struct sk_buff_head *list)
283
+static void pneigh_queue_purge(struct sk_buff_head *list, struct net *net)
228284 {
285
+ struct sk_buff_head tmp;
286
+ unsigned long flags;
229287 struct sk_buff *skb;
230288
231
- while ((skb = skb_dequeue(list)) != NULL) {
289
+ skb_queue_head_init(&tmp);
290
+ spin_lock_irqsave(&list->lock, flags);
291
+ skb = skb_peek(list);
292
+ while (skb != NULL) {
293
+ struct sk_buff *skb_next = skb_peek_next(skb, list);
294
+ if (net == NULL || net_eq(dev_net(skb->dev), net)) {
295
+ __skb_unlink(skb, list);
296
+ __skb_queue_tail(&tmp, skb);
297
+ }
298
+ skb = skb_next;
299
+ }
300
+ spin_unlock_irqrestore(&list->lock, flags);
301
+
302
+ while ((skb = __skb_dequeue(&tmp))) {
232303 dev_put(skb->dev);
233304 kfree_skb(skb);
234305 }
235306 }
236307
237
-static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
308
+static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
309
+ bool skip_perm)
238310 {
239311 int i;
240312 struct neigh_hash_table *nht;
....@@ -252,13 +324,16 @@
252324 np = &n->next;
253325 continue;
254326 }
327
+ if (skip_perm && n->nud_state & NUD_PERMANENT) {
328
+ np = &n->next;
329
+ continue;
330
+ }
255331 rcu_assign_pointer(*np,
256332 rcu_dereference_protected(n->next,
257333 lockdep_is_held(&tbl->lock)));
258334 write_lock(&n->lock);
259335 neigh_del_timer(n);
260
- n->dead = 1;
261
-
336
+ neigh_mark_dead(n);
262337 if (refcount_read(&n->refcnt) != 1) {
263338 /* The most unpleasant situation.
264339 We must destroy neighbour entry,
....@@ -287,30 +362,49 @@
287362 void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
288363 {
289364 write_lock_bh(&tbl->lock);
290
- neigh_flush_dev(tbl, dev);
365
+ neigh_flush_dev(tbl, dev, false);
291366 write_unlock_bh(&tbl->lock);
292367 }
293368 EXPORT_SYMBOL(neigh_changeaddr);
294369
295
-int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
370
+static int __neigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
371
+ bool skip_perm)
296372 {
297373 write_lock_bh(&tbl->lock);
298
- neigh_flush_dev(tbl, dev);
374
+ neigh_flush_dev(tbl, dev, skip_perm);
299375 pneigh_ifdown_and_unlock(tbl, dev);
376
+ pneigh_queue_purge(&tbl->proxy_queue, dev ? dev_net(dev) : NULL);
377
+ if (skb_queue_empty_lockless(&tbl->proxy_queue))
378
+ del_timer_sync(&tbl->proxy_timer);
379
+ return 0;
380
+}
300381
301
- del_timer_sync(&tbl->proxy_timer);
302
- pneigh_queue_purge(&tbl->proxy_queue);
382
+int neigh_carrier_down(struct neigh_table *tbl, struct net_device *dev)
383
+{
384
+ __neigh_ifdown(tbl, dev, true);
385
+ return 0;
386
+}
387
+EXPORT_SYMBOL(neigh_carrier_down);
388
+
389
+int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
390
+{
391
+ __neigh_ifdown(tbl, dev, false);
303392 return 0;
304393 }
305394 EXPORT_SYMBOL(neigh_ifdown);
306395
307
-static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev)
396
+static struct neighbour *neigh_alloc(struct neigh_table *tbl,
397
+ struct net_device *dev,
398
+ u8 flags, bool exempt_from_gc)
308399 {
309400 struct neighbour *n = NULL;
310401 unsigned long now = jiffies;
311402 int entries;
312403
313
- entries = atomic_inc_return(&tbl->entries) - 1;
404
+ if (exempt_from_gc)
405
+ goto do_alloc;
406
+
407
+ entries = atomic_inc_return(&tbl->gc_entries) - 1;
314408 if (entries >= tbl->gc_thresh3 ||
315409 (entries >= tbl->gc_thresh2 &&
316410 time_after(now, tbl->last_flush + 5 * HZ))) {
....@@ -323,6 +417,7 @@
323417 }
324418 }
325419
420
+do_alloc:
326421 n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC);
327422 if (!n)
328423 goto out_entries;
....@@ -333,6 +428,7 @@
333428 n->updated = n->used = now;
334429 n->nud_state = NUD_NONE;
335430 n->output = neigh_blackhole;
431
+ n->flags = flags;
336432 seqlock_init(&n->hh.hh_lock);
337433 n->parms = neigh_parms_clone(&tbl->parms);
338434 timer_setup(&n->timer, neigh_timer_handler, 0);
....@@ -341,11 +437,15 @@
341437 n->tbl = tbl;
342438 refcount_set(&n->refcnt, 1);
343439 n->dead = 1;
440
+ INIT_LIST_HEAD(&n->gc_list);
441
+
442
+ atomic_inc(&tbl->entries);
344443 out:
345444 return n;
346445
347446 out_entries:
348
- atomic_dec(&tbl->entries);
447
+ if (!exempt_from_gc)
448
+ atomic_dec(&tbl->gc_entries);
349449 goto out;
350450 }
351451
....@@ -492,15 +592,18 @@
492592 }
493593 EXPORT_SYMBOL(neigh_lookup_nodev);
494594
495
-struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
496
- struct net_device *dev, bool want_ref)
595
+static struct neighbour *
596
+___neigh_create(struct neigh_table *tbl, const void *pkey,
597
+ struct net_device *dev, u8 flags,
598
+ bool exempt_from_gc, bool want_ref)
497599 {
498
- u32 hash_val;
499
- unsigned int key_len = tbl->key_len;
500
- int error;
501
- struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev);
600
+ u32 hash_val, key_len = tbl->key_len;
601
+ struct neighbour *n1, *rc, *n;
502602 struct neigh_hash_table *nht;
603
+ int error;
503604
605
+ n = neigh_alloc(tbl, dev, flags, exempt_from_gc);
606
+ trace_neigh_create(tbl, dev, pkey, n, exempt_from_gc);
504607 if (!n) {
505608 rc = ERR_PTR(-ENOBUFS);
506609 goto out;
....@@ -561,6 +664,9 @@
561664 }
562665
563666 n->dead = 0;
667
+ if (!exempt_from_gc)
668
+ list_add_tail(&n->gc_list, &n->tbl->gc_list);
669
+
564670 if (want_ref)
565671 neigh_hold(n);
566672 rcu_assign_pointer(n->next,
....@@ -575,8 +681,16 @@
575681 out_tbl_unlock:
576682 write_unlock_bh(&tbl->lock);
577683 out_neigh_release:
684
+ if (!exempt_from_gc)
685
+ atomic_dec(&tbl->gc_entries);
578686 neigh_release(n);
579687 goto out;
688
+}
689
+
690
+struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
691
+ struct net_device *dev, bool want_ref)
692
+{
693
+ return ___neigh_create(tbl, pkey, dev, 0, false, want_ref);
580694 }
581695 EXPORT_SYMBOL(__neigh_create);
582696
....@@ -841,7 +955,7 @@
841955 (state == NUD_FAILED ||
842956 time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
843957 *np = n->next;
844
- n->dead = 1;
958
+ neigh_mark_dead(n);
845959 write_unlock(&n->lock);
846960 neigh_cleanup_and_release(n);
847961 continue;
....@@ -915,7 +1029,7 @@
9151029 if (neigh->ops->solicit)
9161030 neigh->ops->solicit(neigh, skb);
9171031 atomic_inc(&neigh->probes);
918
- kfree_skb(skb);
1032
+ consume_skb(skb);
9191033 }
9201034
9211035 /* Called when a timer expires for a neighbour entry. */
....@@ -972,11 +1086,12 @@
9721086 neigh->updated = jiffies;
9731087 atomic_set(&neigh->probes, 0);
9741088 notify = 1;
975
- next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
1089
+ next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
1090
+ HZ/100);
9761091 }
9771092 } else {
9781093 /* NUD_PROBE|NUD_INCOMPLETE */
979
- next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME);
1094
+ next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), HZ/100);
9801095 }
9811096
9821097 if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
....@@ -988,8 +1103,8 @@
9881103 }
9891104
9901105 if (neigh->nud_state & NUD_IN_TIMER) {
991
- if (time_before(next, jiffies + HZ/2))
992
- next = jiffies + HZ/2;
1106
+ if (time_before(next, jiffies + HZ/100))
1107
+ next = jiffies + HZ/100;
9931108 if (!mod_timer(&neigh->timer, next))
9941109 neigh_hold(neigh);
9951110 }
....@@ -1002,6 +1117,8 @@
10021117
10031118 if (notify)
10041119 neigh_update_notify(neigh, 0);
1120
+
1121
+ trace_neigh_timer_handler(neigh, 0);
10051122
10061123 neigh_release(neigh);
10071124 }
....@@ -1030,7 +1147,7 @@
10301147 neigh->nud_state = NUD_INCOMPLETE;
10311148 neigh->updated = now;
10321149 next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
1033
- HZ/2);
1150
+ HZ/100);
10341151 neigh_add_timer(neigh, next);
10351152 immediate_probe = true;
10361153 } else {
....@@ -1075,6 +1192,7 @@
10751192 else
10761193 write_unlock(&neigh->lock);
10771194 local_bh_enable();
1195
+ trace_neigh_event_send_done(neigh, rc);
10781196 return rc;
10791197
10801198 out_dead:
....@@ -1082,6 +1200,7 @@
10821200 goto out_unlock_bh;
10831201 write_unlock_bh(&neigh->lock);
10841202 kfree_skb(skb);
1203
+ trace_neigh_event_send_dead(neigh, 1);
10851204 return 1;
10861205 }
10871206 EXPORT_SYMBOL(__neigh_event_send);
....@@ -1117,7 +1236,7 @@
11171236 lladdr instead of overriding it
11181237 if it is different.
11191238 NEIGH_UPDATE_F_ADMIN means that the change is administrative.
1120
-
1239
+ NEIGH_UPDATE_F_USE means that the entry is user triggered.
11211240 NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
11221241 NTF_ROUTER flag.
11231242 NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
....@@ -1126,14 +1245,18 @@
11261245 Caller MUST hold reference count on the entry.
11271246 */
11281247
1129
-int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
1130
- u32 flags, u32 nlmsg_pid)
1248
+static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
1249
+ u8 new, u32 flags, u32 nlmsg_pid,
1250
+ struct netlink_ext_ack *extack)
11311251 {
1252
+ bool ext_learn_change = false;
11321253 u8 old;
11331254 int err;
11341255 int notify = 0;
11351256 struct net_device *dev;
11361257 int update_isrouter = 0;
1258
+
1259
+ trace_neigh_update(neigh, lladdr, new, flags, nlmsg_pid);
11371260
11381261 write_lock_bh(&neigh->lock);
11391262
....@@ -1141,13 +1264,22 @@
11411264 old = neigh->nud_state;
11421265 err = -EPERM;
11431266
1267
+ if (neigh->dead) {
1268
+ NL_SET_ERR_MSG(extack, "Neighbor entry is now dead");
1269
+ new = old;
1270
+ goto out;
1271
+ }
11441272 if (!(flags & NEIGH_UPDATE_F_ADMIN) &&
11451273 (old & (NUD_NOARP | NUD_PERMANENT)))
11461274 goto out;
1147
- if (neigh->dead)
1148
- goto out;
11491275
1150
- neigh_update_ext_learned(neigh, flags, &notify);
1276
+ ext_learn_change = neigh_update_ext_learned(neigh, flags, &notify);
1277
+ if (flags & NEIGH_UPDATE_F_USE) {
1278
+ new = old & ~NUD_PERMANENT;
1279
+ neigh->nud_state = new;
1280
+ err = 0;
1281
+ goto out;
1282
+ }
11511283
11521284 if (!(new & NUD_VALID)) {
11531285 neigh_del_timer(neigh);
....@@ -1182,8 +1314,10 @@
11821314 use it, otherwise discard the request.
11831315 */
11841316 err = -EINVAL;
1185
- if (!(old & NUD_VALID))
1317
+ if (!(old & NUD_VALID)) {
1318
+ NL_SET_ERR_MSG(extack, "No link layer address given");
11861319 goto out;
1320
+ }
11871321 lladdr = neigh->ha;
11881322 }
11891323
....@@ -1287,17 +1421,25 @@
12871421 neigh->arp_queue_len_bytes = 0;
12881422 }
12891423 out:
1290
- if (update_isrouter) {
1291
- neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?
1292
- (neigh->flags | NTF_ROUTER) :
1293
- (neigh->flags & ~NTF_ROUTER);
1294
- }
1424
+ if (update_isrouter)
1425
+ neigh_update_is_router(neigh, flags, &notify);
12951426 write_unlock_bh(&neigh->lock);
1427
+
1428
+ if (((new ^ old) & NUD_PERMANENT) || ext_learn_change)
1429
+ neigh_update_gc_list(neigh);
12961430
12971431 if (notify)
12981432 neigh_update_notify(neigh, nlmsg_pid);
12991433
1434
+ trace_neigh_update_done(neigh, err);
1435
+
13001436 return err;
1437
+}
1438
+
1439
+int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
1440
+ u32 flags, u32 nlmsg_pid)
1441
+{
1442
+ return __neigh_update(neigh, lladdr, new, flags, nlmsg_pid, NULL);
13011443 }
13021444 EXPORT_SYMBOL(neigh_update);
13031445
....@@ -1314,7 +1456,8 @@
13141456 neigh->nud_state = NUD_INCOMPLETE;
13151457 atomic_set(&neigh->probes, neigh_max_probes(neigh));
13161458 neigh_add_timer(neigh,
1317
- jiffies + NEIGH_VAR(neigh->parms, RETRANS_TIME));
1459
+ jiffies + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),
1460
+ HZ/100));
13181461 }
13191462 EXPORT_SYMBOL(__neigh_set_probe_once);
13201463
....@@ -1563,6 +1706,7 @@
15631706 unsigned long phsize;
15641707
15651708 INIT_LIST_HEAD(&tbl->parms_list);
1709
+ INIT_LIST_HEAD(&tbl->gc_list);
15661710 list_add(&tbl->parms.list, &tbl->parms_list);
15671711 write_pnet(&tbl->parms.net, &init_net);
15681712 refcount_set(&tbl->parms.refcnt, 1);
....@@ -1614,7 +1758,7 @@
16141758 /* It is not clean... Fix it to unload IPv6 module safely */
16151759 cancel_delayed_work_sync(&tbl->gc_work);
16161760 del_timer_sync(&tbl->proxy_timer);
1617
- pneigh_queue_purge(&tbl->proxy_queue);
1761
+ pneigh_queue_purge(&tbl->proxy_queue, NULL);
16181762 neigh_ifdown(tbl, NULL);
16191763 if (atomic_read(&tbl->entries))
16201764 pr_crit("neighbour leakage\n");
....@@ -1654,6 +1798,22 @@
16541798 return tbl;
16551799 }
16561800
1801
+const struct nla_policy nda_policy[NDA_MAX+1] = {
1802
+ [NDA_UNSPEC] = { .strict_start_type = NDA_NH_ID },
1803
+ [NDA_DST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
1804
+ [NDA_LLADDR] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
1805
+ [NDA_CACHEINFO] = { .len = sizeof(struct nda_cacheinfo) },
1806
+ [NDA_PROBES] = { .type = NLA_U32 },
1807
+ [NDA_VLAN] = { .type = NLA_U16 },
1808
+ [NDA_PORT] = { .type = NLA_U16 },
1809
+ [NDA_VNI] = { .type = NLA_U32 },
1810
+ [NDA_IFINDEX] = { .type = NLA_U32 },
1811
+ [NDA_MASTER] = { .type = NLA_U32 },
1812
+ [NDA_PROTOCOL] = { .type = NLA_U8 },
1813
+ [NDA_NH_ID] = { .type = NLA_U32 },
1814
+ [NDA_FDB_EXT_ATTRS] = { .type = NLA_NESTED },
1815
+};
1816
+
16571817 static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
16581818 struct netlink_ext_ack *extack)
16591819 {
....@@ -1670,8 +1830,10 @@
16701830 goto out;
16711831
16721832 dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST);
1673
- if (dst_attr == NULL)
1833
+ if (!dst_attr) {
1834
+ NL_SET_ERR_MSG(extack, "Network address not specified");
16741835 goto out;
1836
+ }
16751837
16761838 ndm = nlmsg_data(nlh);
16771839 if (ndm->ndm_ifindex) {
....@@ -1686,8 +1848,10 @@
16861848 if (tbl == NULL)
16871849 return -EAFNOSUPPORT;
16881850
1689
- if (nla_len(dst_attr) < (int)tbl->key_len)
1851
+ if (nla_len(dst_attr) < (int)tbl->key_len) {
1852
+ NL_SET_ERR_MSG(extack, "Invalid network address");
16901853 goto out;
1854
+ }
16911855
16921856 if (ndm->ndm_flags & NTF_PROXY) {
16931857 err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
....@@ -1703,10 +1867,9 @@
17031867 goto out;
17041868 }
17051869
1706
- err = neigh_update(neigh, NULL, NUD_FAILED,
1707
- NEIGH_UPDATE_F_OVERRIDE |
1708
- NEIGH_UPDATE_F_ADMIN,
1709
- NETLINK_CB(skb).portid);
1870
+ err = __neigh_update(neigh, NULL, NUD_FAILED,
1871
+ NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN,
1872
+ NETLINK_CB(skb).portid, extack);
17101873 write_lock_bh(&tbl->lock);
17111874 neigh_release(neigh);
17121875 neigh_remove_one(neigh, tbl);
....@@ -1719,7 +1882,8 @@
17191882 static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
17201883 struct netlink_ext_ack *extack)
17211884 {
1722
- int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE;
1885
+ int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE |
1886
+ NEIGH_UPDATE_F_OVERRIDE_ISROUTER;
17231887 struct net *net = sock_net(skb->sk);
17241888 struct ndmsg *ndm;
17251889 struct nlattr *tb[NDA_MAX+1];
....@@ -1727,16 +1891,20 @@
17271891 struct net_device *dev = NULL;
17281892 struct neighbour *neigh;
17291893 void *dst, *lladdr;
1894
+ u8 protocol = 0;
17301895 int err;
17311896
17321897 ASSERT_RTNL();
1733
- err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL, extack);
1898
+ err = nlmsg_parse_deprecated(nlh, sizeof(*ndm), tb, NDA_MAX,
1899
+ nda_policy, extack);
17341900 if (err < 0)
17351901 goto out;
17361902
17371903 err = -EINVAL;
1738
- if (tb[NDA_DST] == NULL)
1904
+ if (!tb[NDA_DST]) {
1905
+ NL_SET_ERR_MSG(extack, "Network address not specified");
17391906 goto out;
1907
+ }
17401908
17411909 ndm = nlmsg_data(nlh);
17421910 if (ndm->ndm_ifindex) {
....@@ -1746,18 +1914,26 @@
17461914 goto out;
17471915 }
17481916
1749
- if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len)
1917
+ if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) {
1918
+ NL_SET_ERR_MSG(extack, "Invalid link address");
17501919 goto out;
1920
+ }
17511921 }
17521922
17531923 tbl = neigh_find_table(ndm->ndm_family);
17541924 if (tbl == NULL)
17551925 return -EAFNOSUPPORT;
17561926
1757
- if (nla_len(tb[NDA_DST]) < (int)tbl->key_len)
1927
+ if (nla_len(tb[NDA_DST]) < (int)tbl->key_len) {
1928
+ NL_SET_ERR_MSG(extack, "Invalid network address");
17581929 goto out;
1930
+ }
1931
+
17591932 dst = nla_data(tb[NDA_DST]);
17601933 lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL;
1934
+
1935
+ if (tb[NDA_PROTOCOL])
1936
+ protocol = nla_get_u8(tb[NDA_PROTOCOL]);
17611937
17621938 if (ndm->ndm_flags & NTF_PROXY) {
17631939 struct pneigh_entry *pn;
....@@ -1766,22 +1942,37 @@
17661942 pn = pneigh_lookup(tbl, net, dst, dev, 1);
17671943 if (pn) {
17681944 pn->flags = ndm->ndm_flags;
1945
+ if (protocol)
1946
+ pn->protocol = protocol;
17691947 err = 0;
17701948 }
17711949 goto out;
17721950 }
17731951
1774
- if (dev == NULL)
1952
+ if (!dev) {
1953
+ NL_SET_ERR_MSG(extack, "Device not specified");
17751954 goto out;
1955
+ }
1956
+
1957
+ if (tbl->allow_add && !tbl->allow_add(dev, extack)) {
1958
+ err = -EINVAL;
1959
+ goto out;
1960
+ }
17761961
17771962 neigh = neigh_lookup(tbl, dst, dev);
17781963 if (neigh == NULL) {
1964
+ bool exempt_from_gc;
1965
+
17791966 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
17801967 err = -ENOENT;
17811968 goto out;
17821969 }
17831970
1784
- neigh = __neigh_lookup_errno(tbl, dst, dev);
1971
+ exempt_from_gc = ndm->ndm_state & NUD_PERMANENT ||
1972
+ ndm->ndm_flags & NTF_EXT_LEARNED;
1973
+ neigh = ___neigh_create(tbl, dst, dev,
1974
+ ndm->ndm_flags & NTF_EXT_LEARNED,
1975
+ exempt_from_gc, true);
17851976 if (IS_ERR(neigh)) {
17861977 err = PTR_ERR(neigh);
17871978 goto out;
....@@ -1794,20 +1985,26 @@
17941985 }
17951986
17961987 if (!(nlh->nlmsg_flags & NLM_F_REPLACE))
1797
- flags &= ~NEIGH_UPDATE_F_OVERRIDE;
1988
+ flags &= ~(NEIGH_UPDATE_F_OVERRIDE |
1989
+ NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
17981990 }
17991991
1992
+ if (protocol)
1993
+ neigh->protocol = protocol;
18001994 if (ndm->ndm_flags & NTF_EXT_LEARNED)
18011995 flags |= NEIGH_UPDATE_F_EXT_LEARNED;
1996
+ if (ndm->ndm_flags & NTF_ROUTER)
1997
+ flags |= NEIGH_UPDATE_F_ISROUTER;
1998
+ if (ndm->ndm_flags & NTF_USE)
1999
+ flags |= NEIGH_UPDATE_F_USE;
18022000
1803
- if (ndm->ndm_flags & NTF_USE) {
2001
+ err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
2002
+ NETLINK_CB(skb).portid, extack);
2003
+ if (!err && ndm->ndm_flags & NTF_USE) {
18042004 neigh_event_send(neigh, NULL);
18052005 err = 0;
1806
- } else
1807
- err = neigh_update(neigh, lladdr, ndm->ndm_state, flags,
1808
- NETLINK_CB(skb).portid);
2006
+ }
18092007 neigh_release(neigh);
1810
-
18112008 out:
18122009 return err;
18132010 }
....@@ -1816,7 +2013,7 @@
18162013 {
18172014 struct nlattr *nest;
18182015
1819
- nest = nla_nest_start(skb, NDTA_PARMS);
2016
+ nest = nla_nest_start_noflag(skb, NDTA_PARMS);
18202017 if (nest == NULL)
18212018 return -ENOBUFS;
18222019
....@@ -2018,8 +2215,8 @@
20182215 bool found = false;
20192216 int err, tidx;
20202217
2021
- err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
2022
- nl_neightbl_policy, extack);
2218
+ err = nlmsg_parse_deprecated(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
2219
+ nl_neightbl_policy, extack);
20232220 if (err < 0)
20242221 goto errout;
20252222
....@@ -2056,8 +2253,9 @@
20562253 struct neigh_parms *p;
20572254 int i, ifindex = 0;
20582255
2059
- err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS],
2060
- nl_ntbl_parm_policy, extack);
2256
+ err = nla_parse_nested_deprecated(tbp, NDTPA_MAX,
2257
+ tb[NDTA_PARMS],
2258
+ nl_ntbl_parm_policy, extack);
20612259 if (err < 0)
20622260 goto errout_tbl_lock;
20632261
....@@ -2169,15 +2367,47 @@
21692367 return err;
21702368 }
21712369
2370
+static int neightbl_valid_dump_info(const struct nlmsghdr *nlh,
2371
+ struct netlink_ext_ack *extack)
2372
+{
2373
+ struct ndtmsg *ndtm;
2374
+
2375
+ if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndtm))) {
2376
+ NL_SET_ERR_MSG(extack, "Invalid header for neighbor table dump request");
2377
+ return -EINVAL;
2378
+ }
2379
+
2380
+ ndtm = nlmsg_data(nlh);
2381
+ if (ndtm->ndtm_pad1 || ndtm->ndtm_pad2) {
2382
+ NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor table dump request");
2383
+ return -EINVAL;
2384
+ }
2385
+
2386
+ if (nlmsg_attrlen(nlh, sizeof(*ndtm))) {
2387
+ NL_SET_ERR_MSG(extack, "Invalid data after header in neighbor table dump request");
2388
+ return -EINVAL;
2389
+ }
2390
+
2391
+ return 0;
2392
+}
2393
+
21722394 static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
21732395 {
2396
+ const struct nlmsghdr *nlh = cb->nlh;
21742397 struct net *net = sock_net(skb->sk);
21752398 int family, tidx, nidx = 0;
21762399 int tbl_skip = cb->args[0];
21772400 int neigh_skip = cb->args[1];
21782401 struct neigh_table *tbl;
21792402
2180
- family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
2403
+ if (cb->strict_check) {
2404
+ int err = neightbl_valid_dump_info(nlh, cb->extack);
2405
+
2406
+ if (err < 0)
2407
+ return err;
2408
+ }
2409
+
2410
+ family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
21812411
21822412 for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
21832413 struct neigh_parms *p;
....@@ -2190,7 +2420,7 @@
21902420 continue;
21912421
21922422 if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid,
2193
- cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
2423
+ nlh->nlmsg_seq, RTM_NEWNEIGHTBL,
21942424 NLM_F_MULTI) < 0)
21952425 break;
21962426
....@@ -2205,7 +2435,7 @@
22052435
22062436 if (neightbl_fill_param_info(skb, tbl, p,
22072437 NETLINK_CB(cb->skb).portid,
2208
- cb->nlh->nlmsg_seq,
2438
+ nlh->nlmsg_seq,
22092439 RTM_NEWNEIGHTBL,
22102440 NLM_F_MULTI) < 0)
22112441 goto out;
....@@ -2267,6 +2497,9 @@
22672497 nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
22682498 goto nla_put_failure;
22692499
2500
+ if (neigh->protocol && nla_put_u8(skb, NDA_PROTOCOL, neigh->protocol))
2501
+ goto nla_put_failure;
2502
+
22702503 nlmsg_end(skb, nlh);
22712504 return 0;
22722505
....@@ -2298,6 +2531,9 @@
22982531 if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
22992532 goto nla_put_failure;
23002533
2534
+ if (pn->protocol && nla_put_u8(skb, NDA_PROTOCOL, pn->protocol))
2535
+ goto nla_put_failure;
2536
+
23012537 nlmsg_end(skb, nlh);
23022538 return 0;
23032539
....@@ -2319,7 +2555,7 @@
23192555 if (!master_idx)
23202556 return false;
23212557
2322
- master = netdev_master_upper_dev_get(dev);
2558
+ master = dev ? netdev_master_upper_dev_get(dev) : NULL;
23232559 if (!master || master->ifindex != master_idx)
23242560 return true;
23252561
....@@ -2328,41 +2564,30 @@
23282564
23292565 static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx)
23302566 {
2331
- if (filter_idx && dev->ifindex != filter_idx)
2567
+ if (filter_idx && (!dev || dev->ifindex != filter_idx))
23322568 return true;
23332569
23342570 return false;
23352571 }
23362572
2573
+struct neigh_dump_filter {
2574
+ int master_idx;
2575
+ int dev_idx;
2576
+};
2577
+
23372578 static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2338
- struct netlink_callback *cb)
2579
+ struct netlink_callback *cb,
2580
+ struct neigh_dump_filter *filter)
23392581 {
23402582 struct net *net = sock_net(skb->sk);
2341
- const struct nlmsghdr *nlh = cb->nlh;
2342
- struct nlattr *tb[NDA_MAX + 1];
23432583 struct neighbour *n;
23442584 int rc, h, s_h = cb->args[1];
23452585 int idx, s_idx = idx = cb->args[2];
23462586 struct neigh_hash_table *nht;
2347
- int filter_master_idx = 0, filter_idx = 0;
23482587 unsigned int flags = NLM_F_MULTI;
2349
- int err;
23502588
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
- }
2589
+ if (filter->dev_idx || filter->master_idx)
2590
+ flags |= NLM_F_DUMP_FILTERED;
23662591
23672592 rcu_read_lock_bh();
23682593 nht = rcu_dereference_bh(tbl->nht);
....@@ -2375,8 +2600,8 @@
23752600 n = rcu_dereference_bh(n->next)) {
23762601 if (idx < s_idx || !net_eq(dev_net(n->dev), net))
23772602 goto next;
2378
- if (neigh_ifindex_filtered(n->dev, filter_idx) ||
2379
- neigh_master_filtered(n->dev, filter_master_idx))
2603
+ if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
2604
+ neigh_master_filtered(n->dev, filter->master_idx))
23802605 goto next;
23812606 if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
23822607 cb->nlh->nlmsg_seq,
....@@ -2398,12 +2623,17 @@
23982623 }
23992624
24002625 static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2401
- struct netlink_callback *cb)
2626
+ struct netlink_callback *cb,
2627
+ struct neigh_dump_filter *filter)
24022628 {
24032629 struct pneigh_entry *n;
24042630 struct net *net = sock_net(skb->sk);
24052631 int rc, h, s_h = cb->args[3];
24062632 int idx, s_idx = idx = cb->args[4];
2633
+ unsigned int flags = NLM_F_MULTI;
2634
+
2635
+ if (filter->dev_idx || filter->master_idx)
2636
+ flags |= NLM_F_DUMP_FILTERED;
24072637
24082638 read_lock_bh(&tbl->lock);
24092639
....@@ -2413,10 +2643,12 @@
24132643 for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
24142644 if (idx < s_idx || pneigh_net(n) != net)
24152645 goto next;
2646
+ if (neigh_ifindex_filtered(n->dev, filter->dev_idx) ||
2647
+ neigh_master_filtered(n->dev, filter->master_idx))
2648
+ goto next;
24162649 if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid,
24172650 cb->nlh->nlmsg_seq,
2418
- RTM_NEWNEIGH,
2419
- NLM_F_MULTI, tbl) < 0) {
2651
+ RTM_NEWNEIGH, flags, tbl) < 0) {
24202652 read_unlock_bh(&tbl->lock);
24212653 rc = -1;
24222654 goto out;
....@@ -2435,21 +2667,88 @@
24352667
24362668 }
24372669
2670
+static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
2671
+ bool strict_check,
2672
+ struct neigh_dump_filter *filter,
2673
+ struct netlink_ext_ack *extack)
2674
+{
2675
+ struct nlattr *tb[NDA_MAX + 1];
2676
+ int err, i;
2677
+
2678
+ if (strict_check) {
2679
+ struct ndmsg *ndm;
2680
+
2681
+ if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
2682
+ NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request");
2683
+ return -EINVAL;
2684
+ }
2685
+
2686
+ ndm = nlmsg_data(nlh);
2687
+ if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_ifindex ||
2688
+ ndm->ndm_state || ndm->ndm_type) {
2689
+ NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request");
2690
+ return -EINVAL;
2691
+ }
2692
+
2693
+ if (ndm->ndm_flags & ~NTF_PROXY) {
2694
+ NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor dump request");
2695
+ return -EINVAL;
2696
+ }
2697
+
2698
+ err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg),
2699
+ tb, NDA_MAX, nda_policy,
2700
+ extack);
2701
+ } else {
2702
+ err = nlmsg_parse_deprecated(nlh, sizeof(struct ndmsg), tb,
2703
+ NDA_MAX, nda_policy, extack);
2704
+ }
2705
+ if (err < 0)
2706
+ return err;
2707
+
2708
+ for (i = 0; i <= NDA_MAX; ++i) {
2709
+ if (!tb[i])
2710
+ continue;
2711
+
2712
+ /* all new attributes should require strict_check */
2713
+ switch (i) {
2714
+ case NDA_IFINDEX:
2715
+ filter->dev_idx = nla_get_u32(tb[i]);
2716
+ break;
2717
+ case NDA_MASTER:
2718
+ filter->master_idx = nla_get_u32(tb[i]);
2719
+ break;
2720
+ default:
2721
+ if (strict_check) {
2722
+ NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request");
2723
+ return -EINVAL;
2724
+ }
2725
+ }
2726
+ }
2727
+
2728
+ return 0;
2729
+}
2730
+
24382731 static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
24392732 {
2733
+ const struct nlmsghdr *nlh = cb->nlh;
2734
+ struct neigh_dump_filter filter = {};
24402735 struct neigh_table *tbl;
24412736 int t, family, s_t;
24422737 int proxy = 0;
24432738 int err;
24442739
2445
- family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
2740
+ family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
24462741
24472742 /* check for full ndmsg structure presence, family member is
24482743 * the same for both structures
24492744 */
2450
- if (nlmsg_len(cb->nlh) >= sizeof(struct ndmsg) &&
2451
- ((struct ndmsg *) nlmsg_data(cb->nlh))->ndm_flags == NTF_PROXY)
2745
+ if (nlmsg_len(nlh) >= sizeof(struct ndmsg) &&
2746
+ ((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY)
24522747 proxy = 1;
2748
+
2749
+ err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack);
2750
+ if (err < 0 && cb->strict_check)
2751
+ return err;
24532752
24542753 s_t = cb->args[0];
24552754
....@@ -2464,15 +2763,195 @@
24642763 memset(&cb->args[1], 0, sizeof(cb->args) -
24652764 sizeof(cb->args[0]));
24662765 if (proxy)
2467
- err = pneigh_dump_table(tbl, skb, cb);
2766
+ err = pneigh_dump_table(tbl, skb, cb, &filter);
24682767 else
2469
- err = neigh_dump_table(tbl, skb, cb);
2768
+ err = neigh_dump_table(tbl, skb, cb, &filter);
24702769 if (err < 0)
24712770 break;
24722771 }
24732772
24742773 cb->args[0] = t;
24752774 return skb->len;
2775
+}
2776
+
2777
+static int neigh_valid_get_req(const struct nlmsghdr *nlh,
2778
+ struct neigh_table **tbl,
2779
+ void **dst, int *dev_idx, u8 *ndm_flags,
2780
+ struct netlink_ext_ack *extack)
2781
+{
2782
+ struct nlattr *tb[NDA_MAX + 1];
2783
+ struct ndmsg *ndm;
2784
+ int err, i;
2785
+
2786
+ if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
2787
+ NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request");
2788
+ return -EINVAL;
2789
+ }
2790
+
2791
+ ndm = nlmsg_data(nlh);
2792
+ if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_state ||
2793
+ ndm->ndm_type) {
2794
+ NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request");
2795
+ return -EINVAL;
2796
+ }
2797
+
2798
+ if (ndm->ndm_flags & ~NTF_PROXY) {
2799
+ NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request");
2800
+ return -EINVAL;
2801
+ }
2802
+
2803
+ err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb,
2804
+ NDA_MAX, nda_policy, extack);
2805
+ if (err < 0)
2806
+ return err;
2807
+
2808
+ *ndm_flags = ndm->ndm_flags;
2809
+ *dev_idx = ndm->ndm_ifindex;
2810
+ *tbl = neigh_find_table(ndm->ndm_family);
2811
+ if (*tbl == NULL) {
2812
+ NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
2813
+ return -EAFNOSUPPORT;
2814
+ }
2815
+
2816
+ for (i = 0; i <= NDA_MAX; ++i) {
2817
+ if (!tb[i])
2818
+ continue;
2819
+
2820
+ switch (i) {
2821
+ case NDA_DST:
2822
+ if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
2823
+ NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
2824
+ return -EINVAL;
2825
+ }
2826
+ *dst = nla_data(tb[i]);
2827
+ break;
2828
+ default:
2829
+ NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
2830
+ return -EINVAL;
2831
+ }
2832
+ }
2833
+
2834
+ return 0;
2835
+}
2836
+
2837
+static inline size_t neigh_nlmsg_size(void)
2838
+{
2839
+ return NLMSG_ALIGN(sizeof(struct ndmsg))
2840
+ + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2841
+ + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2842
+ + nla_total_size(sizeof(struct nda_cacheinfo))
2843
+ + nla_total_size(4) /* NDA_PROBES */
2844
+ + nla_total_size(1); /* NDA_PROTOCOL */
2845
+}
2846
+
2847
+static int neigh_get_reply(struct net *net, struct neighbour *neigh,
2848
+ u32 pid, u32 seq)
2849
+{
2850
+ struct sk_buff *skb;
2851
+ int err = 0;
2852
+
2853
+ skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL);
2854
+ if (!skb)
2855
+ return -ENOBUFS;
2856
+
2857
+ err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0);
2858
+ if (err) {
2859
+ kfree_skb(skb);
2860
+ goto errout;
2861
+ }
2862
+
2863
+ err = rtnl_unicast(skb, net, pid);
2864
+errout:
2865
+ return err;
2866
+}
2867
+
2868
+static inline size_t pneigh_nlmsg_size(void)
2869
+{
2870
+ return NLMSG_ALIGN(sizeof(struct ndmsg))
2871
+ + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2872
+ + nla_total_size(1); /* NDA_PROTOCOL */
2873
+}
2874
+
2875
+static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh,
2876
+ u32 pid, u32 seq, struct neigh_table *tbl)
2877
+{
2878
+ struct sk_buff *skb;
2879
+ int err = 0;
2880
+
2881
+ skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL);
2882
+ if (!skb)
2883
+ return -ENOBUFS;
2884
+
2885
+ err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl);
2886
+ if (err) {
2887
+ kfree_skb(skb);
2888
+ goto errout;
2889
+ }
2890
+
2891
+ err = rtnl_unicast(skb, net, pid);
2892
+errout:
2893
+ return err;
2894
+}
2895
+
2896
+static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
2897
+ struct netlink_ext_ack *extack)
2898
+{
2899
+ struct net *net = sock_net(in_skb->sk);
2900
+ struct net_device *dev = NULL;
2901
+ struct neigh_table *tbl = NULL;
2902
+ struct neighbour *neigh;
2903
+ void *dst = NULL;
2904
+ u8 ndm_flags = 0;
2905
+ int dev_idx = 0;
2906
+ int err;
2907
+
2908
+ err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags,
2909
+ extack);
2910
+ if (err < 0)
2911
+ return err;
2912
+
2913
+ if (dev_idx) {
2914
+ dev = __dev_get_by_index(net, dev_idx);
2915
+ if (!dev) {
2916
+ NL_SET_ERR_MSG(extack, "Unknown device ifindex");
2917
+ return -ENODEV;
2918
+ }
2919
+ }
2920
+
2921
+ if (!dst) {
2922
+ NL_SET_ERR_MSG(extack, "Network address not specified");
2923
+ return -EINVAL;
2924
+ }
2925
+
2926
+ if (ndm_flags & NTF_PROXY) {
2927
+ struct pneigh_entry *pn;
2928
+
2929
+ pn = pneigh_lookup(tbl, net, dst, dev, 0);
2930
+ if (!pn) {
2931
+ NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found");
2932
+ return -ENOENT;
2933
+ }
2934
+ return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid,
2935
+ nlh->nlmsg_seq, tbl);
2936
+ }
2937
+
2938
+ if (!dev) {
2939
+ NL_SET_ERR_MSG(extack, "No device specified");
2940
+ return -EINVAL;
2941
+ }
2942
+
2943
+ neigh = neigh_lookup(tbl, dst, dev);
2944
+ if (!neigh) {
2945
+ NL_SET_ERR_MSG(extack, "Neighbour entry not found");
2946
+ return -ENOENT;
2947
+ }
2948
+
2949
+ err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid,
2950
+ nlh->nlmsg_seq);
2951
+
2952
+ neigh_release(neigh);
2953
+
2954
+ return err;
24762955 }
24772956
24782957 void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
....@@ -2521,7 +3000,7 @@
25213000 rcu_assign_pointer(*np,
25223001 rcu_dereference_protected(n->next,
25233002 lockdep_is_held(&tbl->lock)));
2524
- n->dead = 1;
3003
+ neigh_mark_dead(n);
25253004 } else
25263005 np = &n->next;
25273006 write_unlock(&n->lock);
....@@ -2584,7 +3063,7 @@
25843063 struct net *net = seq_file_net(seq);
25853064 struct neigh_hash_table *nht = state->nht;
25863065 struct neighbour *n = NULL;
2587
- int bucket = state->bucket;
3066
+ int bucket;
25883067
25893068 state->flags &= ~NEIGH_SEQ_IS_PNEIGH;
25903069 for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) {
....@@ -2896,15 +3375,6 @@
28963375 };
28973376 #endif /* CONFIG_PROC_FS */
28983377
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
-
29083378 static void __neigh_notify(struct neighbour *n, int type, int flags,
29093379 u32 pid)
29103380 {
....@@ -2937,17 +3407,15 @@
29373407 EXPORT_SYMBOL(neigh_app_ns);
29383408
29393409 #ifdef CONFIG_SYSCTL
2940
-static int zero;
2941
-static int int_max = INT_MAX;
29423410 static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
29433411
29443412 static int proc_unres_qlen(struct ctl_table *ctl, int write,
2945
- void __user *buffer, size_t *lenp, loff_t *ppos)
3413
+ void *buffer, size_t *lenp, loff_t *ppos)
29463414 {
29473415 int size, ret;
29483416 struct ctl_table tmp = *ctl;
29493417
2950
- tmp.extra1 = &zero;
3418
+ tmp.extra1 = SYSCTL_ZERO;
29513419 tmp.extra2 = &unres_qlen_max;
29523420 tmp.data = &size;
29533421
....@@ -3006,22 +3474,22 @@
30063474 }
30073475
30083476 static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
3009
- void __user *buffer,
3010
- size_t *lenp, loff_t *ppos)
3477
+ void *buffer, size_t *lenp,
3478
+ loff_t *ppos)
30113479 {
30123480 struct ctl_table tmp = *ctl;
30133481 int ret;
30143482
3015
- tmp.extra1 = &zero;
3016
- tmp.extra2 = &int_max;
3483
+ tmp.extra1 = SYSCTL_ZERO;
3484
+ tmp.extra2 = SYSCTL_INT_MAX;
30173485
30183486 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
30193487 neigh_proc_update(ctl, write);
30203488 return ret;
30213489 }
30223490
3023
-int neigh_proc_dointvec(struct ctl_table *ctl, int write,
3024
- void __user *buffer, size_t *lenp, loff_t *ppos)
3491
+int neigh_proc_dointvec(struct ctl_table *ctl, int write, void *buffer,
3492
+ size_t *lenp, loff_t *ppos)
30253493 {
30263494 int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
30273495
....@@ -3030,8 +3498,7 @@
30303498 }
30313499 EXPORT_SYMBOL(neigh_proc_dointvec);
30323500
3033
-int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write,
3034
- void __user *buffer,
3501
+int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, void *buffer,
30353502 size_t *lenp, loff_t *ppos)
30363503 {
30373504 int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
....@@ -3042,8 +3509,8 @@
30423509 EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
30433510
30443511 static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write,
3045
- void __user *buffer,
3046
- size_t *lenp, loff_t *ppos)
3512
+ void *buffer, size_t *lenp,
3513
+ loff_t *ppos)
30473514 {
30483515 int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
30493516
....@@ -3052,8 +3519,7 @@
30523519 }
30533520
30543521 int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
3055
- void __user *buffer,
3056
- size_t *lenp, loff_t *ppos)
3522
+ void *buffer, size_t *lenp, loff_t *ppos)
30573523 {
30583524 int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
30593525
....@@ -3063,8 +3529,8 @@
30633529 EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
30643530
30653531 static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
3066
- void __user *buffer,
3067
- size_t *lenp, loff_t *ppos)
3532
+ void *buffer, size_t *lenp,
3533
+ loff_t *ppos)
30683534 {
30693535 int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
30703536
....@@ -3073,8 +3539,8 @@
30733539 }
30743540
30753541 static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
3076
- void __user *buffer,
3077
- size_t *lenp, loff_t *ppos)
3542
+ void *buffer, size_t *lenp,
3543
+ loff_t *ppos)
30783544 {
30793545 struct neigh_parms *p = ctl->extra2;
30803546 int ret;
....@@ -3118,9 +3584,6 @@
31183584 #define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \
31193585 NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies)
31203586
3121
-#define NEIGH_SYSCTL_MS_JIFFIES_ENTRY(attr, name) \
3122
- NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
3123
-
31243587 #define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \
31253588 NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies)
31263589
....@@ -3158,24 +3621,24 @@
31583621 .procname = "gc_thresh1",
31593622 .maxlen = sizeof(int),
31603623 .mode = 0644,
3161
- .extra1 = &zero,
3162
- .extra2 = &int_max,
3624
+ .extra1 = SYSCTL_ZERO,
3625
+ .extra2 = SYSCTL_INT_MAX,
31633626 .proc_handler = proc_dointvec_minmax,
31643627 },
31653628 [NEIGH_VAR_GC_THRESH2] = {
31663629 .procname = "gc_thresh2",
31673630 .maxlen = sizeof(int),
31683631 .mode = 0644,
3169
- .extra1 = &zero,
3170
- .extra2 = &int_max,
3632
+ .extra1 = SYSCTL_ZERO,
3633
+ .extra2 = SYSCTL_INT_MAX,
31713634 .proc_handler = proc_dointvec_minmax,
31723635 },
31733636 [NEIGH_VAR_GC_THRESH3] = {
31743637 .procname = "gc_thresh3",
31753638 .maxlen = sizeof(int),
31763639 .mode = 0644,
3177
- .extra1 = &zero,
3178
- .extra2 = &int_max,
3640
+ .extra1 = SYSCTL_ZERO,
3641
+ .extra2 = SYSCTL_INT_MAX,
31793642 .proc_handler = proc_dointvec_minmax,
31803643 },
31813644 {},
....@@ -3288,7 +3751,7 @@
32883751 {
32893752 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
32903753 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
3291
- rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, 0);
3754
+ rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0);
32923755
32933756 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
32943757 0);