#define _NF_DEFRAG_IPV4_H
 
 struct net;
-int nf_defrag_ipv4_enable(struct net *);
+int nf_defrag_ipv4_enable(struct net *net);
+void nf_defrag_ipv4_disable(struct net *net);
 
 #endif /* _NF_DEFRAG_IPV4_H */
 
 #include <linux/skbuff.h>
 #include <linux/types.h>
 
-int nf_defrag_ipv6_enable(struct net *);
+int nf_defrag_ipv6_enable(struct net *net);
+void nf_defrag_ipv6_disable(struct net *net);
 
 int nf_ct_frag6_init(void);
 void nf_ct_frag6_cleanup(void);
 
        struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id);
        int err = 0;
 
-       might_sleep();
-
-       if (nf_defrag->users)
-               return 0;
-
        mutex_lock(&defrag4_mutex);
-       if (nf_defrag->users)
+       if (nf_defrag->users == UINT_MAX) {
+               err = -EOVERFLOW;
                goto out_unlock;
+       }
+
+       if (nf_defrag->users) {
+               nf_defrag->users++;
+               goto out_unlock;
+       }
 
        err = nf_register_net_hooks(net, ipv4_defrag_ops,
                                    ARRAY_SIZE(ipv4_defrag_ops));
 }
 EXPORT_SYMBOL_GPL(nf_defrag_ipv4_enable);
 
+void nf_defrag_ipv4_disable(struct net *net)
+{
+       struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id);
+
+       mutex_lock(&defrag4_mutex);
+       if (nf_defrag->users) {
+               nf_defrag->users--;
+               if (nf_defrag->users == 0)
+                       nf_unregister_net_hooks(net, ipv4_defrag_ops,
+                                               ARRAY_SIZE(ipv4_defrag_ops));
+       }
+
+       mutex_unlock(&defrag4_mutex);
+}
+EXPORT_SYMBOL_GPL(nf_defrag_ipv4_disable);
+
 module_init(nf_defrag_init);
 module_exit(nf_defrag_fini);
 
 
        struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id);
        int err = 0;
 
-       might_sleep();
-
-       if (nf_frag->users)
-               return 0;
-
        mutex_lock(&defrag6_mutex);
-       if (nf_frag->users)
+       if (nf_frag->users == UINT_MAX) {
+               err = -EOVERFLOW;
+               goto out_unlock;
+       }
+
+       if (nf_frag->users) {
+               nf_frag->users++;
                goto out_unlock;
+       }
 
        err = nf_register_net_hooks(net, ipv6_defrag_ops,
                                    ARRAY_SIZE(ipv6_defrag_ops));
 }
 EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable);
 
+void nf_defrag_ipv6_disable(struct net *net)
+{
+       struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id);
+
+       mutex_lock(&defrag6_mutex);
+       if (nf_frag->users) {
+               nf_frag->users--;
+               if (nf_frag->users == 0)
+                       nf_unregister_net_hooks(net, ipv6_defrag_ops,
+                                               ARRAY_SIZE(ipv6_defrag_ops));
+       }
+       mutex_unlock(&defrag6_mutex);
+}
+EXPORT_SYMBOL_GPL(nf_defrag_ipv6_disable);
+
 module_init(nf_defrag_init);
 module_exit(nf_defrag_fini);
 
 
        mutex_lock(&nf_ct_proto_mutex);
        switch (nfproto) {
        case NFPROTO_IPV4:
-               if (cnet->users4 && (--cnet->users4 == 0))
+               if (cnet->users4 && (--cnet->users4 == 0)) {
                        nf_unregister_net_hooks(net, ipv4_conntrack_ops,
                                                ARRAY_SIZE(ipv4_conntrack_ops));
+                       nf_defrag_ipv4_disable(net);
+               }
                break;
 #if IS_ENABLED(CONFIG_IPV6)
        case NFPROTO_IPV6:
-               if (cnet->users6 && (--cnet->users6 == 0))
+               if (cnet->users6 && (--cnet->users6 == 0)) {
                        nf_unregister_net_hooks(net, ipv6_conntrack_ops,
                                                ARRAY_SIZE(ipv6_conntrack_ops));
+                       nf_defrag_ipv6_disable(net);
+               }
                break;
 #endif
        case NFPROTO_BRIDGE:
 
        return 0;
 }
 
+static void nft_tproxy_destroy(const struct nft_ctx *ctx,
+                              const struct nft_expr *expr)
+{
+       const struct nft_tproxy *priv = nft_expr_priv(expr);
+
+       switch (priv->family) {
+       case NFPROTO_IPV4:
+               nf_defrag_ipv4_disable(ctx->net);
+               break;
+#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
+       case NFPROTO_IPV6:
+               nf_defrag_ipv6_disable(ctx->net);
+               break;
+#endif
+       case NFPROTO_UNSPEC:
+               nf_defrag_ipv4_disable(ctx->net);
+#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
+               nf_defrag_ipv6_disable(ctx->net);
+#endif
+               break;
+       }
+}
+
 static int nft_tproxy_dump(struct sk_buff *skb,
                           const struct nft_expr *expr)
 {
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_tproxy)),
        .eval           = nft_tproxy_eval,
        .init           = nft_tproxy_init,
+       .destroy        = nft_tproxy_destroy,
        .dump           = nft_tproxy_dump,
 };
 
 
        pr_info_ratelimited("Can be used only with -p tcp or -p udp\n");
        return -EINVAL;
 }
+
+static void tproxy_tg6_destroy(const struct xt_tgdtor_param *par)
+{
+       nf_defrag_ipv6_disable(par->net);
+}
 #endif
 
 static int tproxy_tg4_check(const struct xt_tgchk_param *par)
        return -EINVAL;
 }
 
+static void tproxy_tg4_destroy(const struct xt_tgdtor_param *par)
+{
+       nf_defrag_ipv4_disable(par->net);
+}
+
 static struct xt_target tproxy_tg_reg[] __read_mostly = {
        {
                .name           = "TPROXY",
                .revision       = 0,
                .targetsize     = sizeof(struct xt_tproxy_target_info),
                .checkentry     = tproxy_tg4_check,
+               .destroy        = tproxy_tg4_destroy,
                .hooks          = 1 << NF_INET_PRE_ROUTING,
                .me             = THIS_MODULE,
        },
                .revision       = 1,
                .targetsize     = sizeof(struct xt_tproxy_target_info_v1),
                .checkentry     = tproxy_tg4_check,
+               .destroy        = tproxy_tg4_destroy,
                .hooks          = 1 << NF_INET_PRE_ROUTING,
                .me             = THIS_MODULE,
        },
                .revision       = 1,
                .targetsize     = sizeof(struct xt_tproxy_target_info_v1),
                .checkentry     = tproxy_tg6_check,
+               .destroy        = tproxy_tg6_destroy,
                .hooks          = 1 << NF_INET_PRE_ROUTING,
                .me             = THIS_MODULE,
        },
 
        return 0;
 }
 
+static void socket_mt_destroy(const struct xt_mtdtor_param *par)
+{
+       if (par->family == NFPROTO_IPV4)
+               nf_defrag_ipv4_disable(par->net);
+       else if (par->family == NFPROTO_IPV6)
+               nf_defrag_ipv4_disable(par->net);
+}
+
 static struct xt_match socket_mt_reg[] __read_mostly = {
        {
                .name           = "socket",
                .revision       = 1,
                .family         = NFPROTO_IPV4,
                .match          = socket_mt4_v1_v2_v3,
+               .destroy        = socket_mt_destroy,
                .checkentry     = socket_mt_v1_check,
                .matchsize      = sizeof(struct xt_socket_mtinfo1),
                .hooks          = (1 << NF_INET_PRE_ROUTING) |
                .match          = socket_mt6_v1_v2_v3,
                .checkentry     = socket_mt_v1_check,
                .matchsize      = sizeof(struct xt_socket_mtinfo1),
+               .destroy        = socket_mt_destroy,
                .hooks          = (1 << NF_INET_PRE_ROUTING) |
                                  (1 << NF_INET_LOCAL_IN),
                .me             = THIS_MODULE,
                .family         = NFPROTO_IPV4,
                .match          = socket_mt4_v1_v2_v3,
                .checkentry     = socket_mt_v2_check,
+               .destroy        = socket_mt_destroy,
                .matchsize      = sizeof(struct xt_socket_mtinfo1),
                .hooks          = (1 << NF_INET_PRE_ROUTING) |
                                  (1 << NF_INET_LOCAL_IN),
                .family         = NFPROTO_IPV6,
                .match          = socket_mt6_v1_v2_v3,
                .checkentry     = socket_mt_v2_check,
+               .destroy        = socket_mt_destroy,
                .matchsize      = sizeof(struct xt_socket_mtinfo1),
                .hooks          = (1 << NF_INET_PRE_ROUTING) |
                                  (1 << NF_INET_LOCAL_IN),
                .family         = NFPROTO_IPV4,
                .match          = socket_mt4_v1_v2_v3,
                .checkentry     = socket_mt_v3_check,
+               .destroy        = socket_mt_destroy,
                .matchsize      = sizeof(struct xt_socket_mtinfo1),
                .hooks          = (1 << NF_INET_PRE_ROUTING) |
                                  (1 << NF_INET_LOCAL_IN),
                .family         = NFPROTO_IPV6,
                .match          = socket_mt6_v1_v2_v3,
                .checkentry     = socket_mt_v3_check,
+               .destroy        = socket_mt_destroy,
                .matchsize      = sizeof(struct xt_socket_mtinfo1),
                .hooks          = (1 << NF_INET_PRE_ROUTING) |
                                  (1 << NF_INET_LOCAL_IN),