|
|
@@ -126,14 +126,15 @@ int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)
|
|
|
}
|
|
|
EXPORT_SYMBOL(nf_register_net_hook);
|
|
|
|
|
|
-void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
|
|
|
+static struct nf_hook_entry *
|
|
|
+__nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
|
|
|
{
|
|
|
struct nf_hook_entry __rcu **pp;
|
|
|
struct nf_hook_entry *p;
|
|
|
|
|
|
pp = nf_hook_entry_head(net, reg);
|
|
|
if (WARN_ON_ONCE(!pp))
|
|
|
- return;
|
|
|
+ return NULL;
|
|
|
|
|
|
mutex_lock(&nf_hook_mutex);
|
|
|
for (; (p = nf_entry_dereference(*pp)) != NULL; pp = &p->next) {
|
|
|
@@ -145,7 +146,7 @@ void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
|
|
|
mutex_unlock(&nf_hook_mutex);
|
|
|
if (!p) {
|
|
|
WARN(1, "nf_unregister_net_hook: hook not found!\n");
|
|
|
- return;
|
|
|
+ return NULL;
|
|
|
}
|
|
|
#ifdef CONFIG_NETFILTER_INGRESS
|
|
|
if (reg->pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS)
|
|
|
@@ -154,6 +155,17 @@ void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
|
|
|
#ifdef HAVE_JUMP_LABEL
|
|
|
static_key_slow_dec(&nf_hooks_needed[reg->pf][reg->hooknum]);
|
|
|
#endif
|
|
|
+
|
|
|
+ return p;
|
|
|
+}
|
|
|
+
|
|
|
+void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg)
|
|
|
+{
|
|
|
+ struct nf_hook_entry *p = __nf_unregister_net_hook(net, reg);
|
|
|
+
|
|
|
+ if (!p)
|
|
|
+ return;
|
|
|
+
|
|
|
synchronize_net();
|
|
|
nf_queue_nf_hook_drop(net, p);
|
|
|
/* other cpu might still process nfqueue verdict that used reg */
|
|
|
@@ -183,10 +195,32 @@ err:
|
|
|
EXPORT_SYMBOL(nf_register_net_hooks);
|
|
|
|
|
|
void nf_unregister_net_hooks(struct net *net, const struct nf_hook_ops *reg,
|
|
|
- unsigned int n)
|
|
|
+ unsigned int hookcount)
|
|
|
{
|
|
|
- while (n-- > 0)
|
|
|
- nf_unregister_net_hook(net, ®[n]);
|
|
|
+ struct nf_hook_entry *to_free[16];
|
|
|
+ unsigned int i, n;
|
|
|
+
|
|
|
+ do {
|
|
|
+ n = min_t(unsigned int, hookcount, ARRAY_SIZE(to_free));
|
|
|
+
|
|
|
+ for (i = 0; i < n; i++)
|
|
|
+ to_free[i] = __nf_unregister_net_hook(net, ®[i]);
|
|
|
+
|
|
|
+ synchronize_net();
|
|
|
+
|
|
|
+ for (i = 0; i < n; i++) {
|
|
|
+ if (to_free[i])
|
|
|
+ nf_queue_nf_hook_drop(net, to_free[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ synchronize_net();
|
|
|
+
|
|
|
+ for (i = 0; i < n; i++)
|
|
|
+ kfree(to_free[i]);
|
|
|
+
|
|
|
+ reg += n;
|
|
|
+ hookcount -= n;
|
|
|
+ } while (hookcount > 0);
|
|
|
}
|
|
|
EXPORT_SYMBOL(nf_unregister_net_hooks);
|
|
|
|