@@ -186,9 +186,31 @@ static void hooks_validate(const struct nf_hook_entries *hooks)
186
186
#endif
187
187
}
188
188
189
+ int nf_hook_entries_insert_raw (struct nf_hook_entries __rcu * * pp ,
190
+ const struct nf_hook_ops * reg )
191
+ {
192
+ struct nf_hook_entries * new_hooks ;
193
+ struct nf_hook_entries * p ;
194
+
195
+ p = rcu_dereference_raw (* pp );
196
+ new_hooks = nf_hook_entries_grow (p , reg );
197
+ if (IS_ERR (new_hooks ))
198
+ return PTR_ERR (new_hooks );
199
+
200
+ hooks_validate (new_hooks );
201
+
202
+ rcu_assign_pointer (* pp , new_hooks );
203
+
204
+ BUG_ON (p == new_hooks );
205
+ nf_hook_entries_free (p );
206
+ return 0 ;
207
+ }
208
+ EXPORT_SYMBOL_GPL (nf_hook_entries_insert_raw );
209
+
189
210
/*
190
211
* __nf_hook_entries_try_shrink - try to shrink hook array
191
212
*
213
+ * @old -- current hook blob at @pp
192
214
* @pp -- location of hook blob
193
215
*
194
216
* Hook unregistration must always succeed, so to-be-removed hooks
@@ -201,14 +223,14 @@ static void hooks_validate(const struct nf_hook_entries *hooks)
201
223
*
202
224
* Returns address to free, or NULL.
203
225
*/
204
- static void * __nf_hook_entries_try_shrink (struct nf_hook_entries __rcu * * pp )
226
+ static void * __nf_hook_entries_try_shrink (struct nf_hook_entries * old ,
227
+ struct nf_hook_entries __rcu * * pp )
205
228
{
206
- struct nf_hook_entries * old , * new = NULL ;
207
229
unsigned int i , j , skip = 0 , hook_entries ;
230
+ struct nf_hook_entries * new = NULL ;
208
231
struct nf_hook_ops * * orig_ops ;
209
232
struct nf_hook_ops * * new_ops ;
210
233
211
- old = nf_entry_dereference (* pp );
212
234
if (WARN_ON_ONCE (!old ))
213
235
return NULL ;
214
236
@@ -347,11 +369,10 @@ static int __nf_register_net_hook(struct net *net, int pf,
347
369
* This cannot fail, hook unregistration must always succeed.
348
370
* Therefore replace the to-be-removed hook with a dummy hook.
349
371
*/
350
- static void nf_remove_net_hook (struct nf_hook_entries * old ,
351
- const struct nf_hook_ops * unreg , int pf )
372
+ static bool nf_remove_net_hook (struct nf_hook_entries * old ,
373
+ const struct nf_hook_ops * unreg )
352
374
{
353
375
struct nf_hook_ops * * orig_ops ;
354
- bool found = false;
355
376
unsigned int i ;
356
377
357
378
orig_ops = nf_hook_entries_get_hook_ops (old );
@@ -360,21 +381,10 @@ static void nf_remove_net_hook(struct nf_hook_entries *old,
360
381
continue ;
361
382
WRITE_ONCE (old -> hooks [i ].hook , accept_all );
362
383
WRITE_ONCE (orig_ops [i ], & dummy_ops );
363
- found = true;
364
- break ;
384
+ return true;
365
385
}
366
386
367
- if (found ) {
368
- #ifdef CONFIG_NETFILTER_INGRESS
369
- if (pf == NFPROTO_NETDEV && unreg -> hooknum == NF_NETDEV_INGRESS )
370
- net_dec_ingress_queue ();
371
- #endif
372
- #ifdef HAVE_JUMP_LABEL
373
- static_key_slow_dec (& nf_hooks_needed [pf ][unreg -> hooknum ]);
374
- #endif
375
- } else {
376
- WARN_ONCE (1 , "hook not found, pf %d num %d" , pf , unreg -> hooknum );
377
- }
387
+ return false;
378
388
}
379
389
380
390
static void __nf_unregister_net_hook (struct net * net , int pf ,
@@ -395,9 +405,19 @@ static void __nf_unregister_net_hook(struct net *net, int pf,
395
405
return ;
396
406
}
397
407
398
- nf_remove_net_hook (p , reg , pf );
408
+ if (nf_remove_net_hook (p , reg )) {
409
+ #ifdef CONFIG_NETFILTER_INGRESS
410
+ if (pf == NFPROTO_NETDEV && reg -> hooknum == NF_NETDEV_INGRESS )
411
+ net_dec_ingress_queue ();
412
+ #endif
413
+ #ifdef HAVE_JUMP_LABEL
414
+ static_key_slow_dec (& nf_hooks_needed [pf ][reg -> hooknum ]);
415
+ #endif
416
+ } else {
417
+ WARN_ONCE (1 , "hook not found, pf %d num %d" , pf , reg -> hooknum );
418
+ }
399
419
400
- p = __nf_hook_entries_try_shrink (pp );
420
+ p = __nf_hook_entries_try_shrink (p , pp );
401
421
mutex_unlock (& nf_hook_mutex );
402
422
if (!p )
403
423
return ;
@@ -417,6 +437,19 @@ void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
417
437
}
418
438
EXPORT_SYMBOL (nf_unregister_net_hook );
419
439
440
+ void nf_hook_entries_delete_raw (struct nf_hook_entries __rcu * * pp ,
441
+ const struct nf_hook_ops * reg )
442
+ {
443
+ struct nf_hook_entries * p ;
444
+
445
+ p = rcu_dereference_raw (* pp );
446
+ if (nf_remove_net_hook (p , reg )) {
447
+ p = __nf_hook_entries_try_shrink (p , pp );
448
+ nf_hook_entries_free (p );
449
+ }
450
+ }
451
+ EXPORT_SYMBOL_GPL (nf_hook_entries_delete_raw );
452
+
420
453
int nf_register_net_hook (struct net * net , const struct nf_hook_ops * reg )
421
454
{
422
455
int err ;
0 commit comments