| 
					
				 | 
			
			
				@@ -0,0 +1,391 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+From: Pablo Neira Ayuso <[email protected]> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Date: Sat, 9 Dec 2017 15:40:25 +0100 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Subject: [PATCH] netfilter: nf_tables: remove multihook chains and families 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Since NFPROTO_INET is handled from the core, we don't need to maintain 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+extra infrastructure in nf_tables to handle the double hook 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+registration, one for IPv4 and another for IPv6. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+Signed-off-by: Pablo Neira Ayuso <[email protected]> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+--- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+--- a/include/net/netfilter/nf_tables.h 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++++ b/include/net/netfilter/nf_tables.h 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -892,8 +892,6 @@ struct nft_stats { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	struct u64_stats_sync	syncp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-#define NFT_HOOK_OPS_MAX		2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  *	struct nft_base_chain - nf_tables base chain 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -905,7 +903,7 @@ struct nft_stats { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  *	@dev_name: device name that this base chain is attached to (if any) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ struct nft_base_chain { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	struct nf_hook_ops		ops[NFT_HOOK_OPS_MAX]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++	struct nf_hook_ops		ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	const struct nf_chain_type	*type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	u8				policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	u8				flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -966,8 +964,6 @@ enum nft_af_flags { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  *	@owner: module owner 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  *	@tables: used internally 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  *	@flags: family flags 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+- *	@nops: number of hook ops in this family 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+- *	@hook_ops_init: initialization function for chain hook ops 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  *	@hooks: hookfn overrides for packet validation 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ struct nft_af_info { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -977,9 +973,6 @@ struct nft_af_info { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	struct module			*owner; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	struct list_head		tables; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	u32				flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	unsigned int			nops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	void				(*hook_ops_init)(struct nf_hook_ops *, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-							 unsigned int); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	nf_hookfn			*hooks[NF_MAX_HOOKS]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+--- a/net/bridge/netfilter/nf_tables_bridge.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++++ b/net/bridge/netfilter/nf_tables_bridge.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -46,7 +46,6 @@ static struct nft_af_info nft_af_bridge 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.family		= NFPROTO_BRIDGE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.nhooks		= NF_BR_NUMHOOKS, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.owner		= THIS_MODULE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	.nops		= 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.hooks		= { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		[NF_BR_PRE_ROUTING]	= nft_do_chain_bridge, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		[NF_BR_LOCAL_IN]	= nft_do_chain_bridge, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+--- a/net/ipv4/netfilter/nf_tables_arp.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++++ b/net/ipv4/netfilter/nf_tables_arp.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -31,7 +31,6 @@ static struct nft_af_info nft_af_arp __r 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.family		= NFPROTO_ARP, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.nhooks		= NF_ARP_NUMHOOKS, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.owner		= THIS_MODULE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	.nops		= 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.hooks		= { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		[NF_ARP_IN]		= nft_do_chain_arp, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		[NF_ARP_OUT]		= nft_do_chain_arp, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+--- a/net/ipv4/netfilter/nf_tables_ipv4.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++++ b/net/ipv4/netfilter/nf_tables_ipv4.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -49,7 +49,6 @@ static struct nft_af_info nft_af_ipv4 __ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.family		= NFPROTO_IPV4, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.nhooks		= NF_INET_NUMHOOKS, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.owner		= THIS_MODULE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	.nops		= 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.hooks		= { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		[NF_INET_LOCAL_IN]	= nft_do_chain_ipv4, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		[NF_INET_LOCAL_OUT]	= nft_ipv4_output, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+--- a/net/ipv6/netfilter/nf_tables_ipv6.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++++ b/net/ipv6/netfilter/nf_tables_ipv6.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -46,7 +46,6 @@ static struct nft_af_info nft_af_ipv6 __ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.family		= NFPROTO_IPV6, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.nhooks		= NF_INET_NUMHOOKS, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.owner		= THIS_MODULE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	.nops		= 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.hooks		= { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		[NF_INET_LOCAL_IN]	= nft_do_chain_ipv6, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		[NF_INET_LOCAL_OUT]	= nft_ipv6_output, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+--- a/net/netfilter/nf_tables_api.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++++ b/net/netfilter/nf_tables_api.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -139,29 +139,26 @@ static void nft_trans_destroy(struct nft 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	kfree(trans); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-static int nf_tables_register_hooks(struct net *net, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-				    const struct nft_table *table, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-				    struct nft_chain *chain, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-				    unsigned int hook_nops) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++static int nf_tables_register_hook(struct net *net, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++				   const struct nft_table *table, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++				   struct nft_chain *chain) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	if (table->flags & NFT_TABLE_F_DORMANT || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	    !nft_is_base_chain(chain)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	return nf_register_net_hooks(net, nft_base_chain(chain)->ops, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-				     hook_nops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++	return nf_register_net_hook(net, &nft_base_chain(chain)->ops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-static void nf_tables_unregister_hooks(struct net *net, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-				       const struct nft_table *table, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-				       struct nft_chain *chain, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-				       unsigned int hook_nops) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++static void nf_tables_unregister_hook(struct net *net, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++				      const struct nft_table *table, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++				      struct nft_chain *chain) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	if (table->flags & NFT_TABLE_F_DORMANT || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	    !nft_is_base_chain(chain)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	nf_unregister_net_hooks(net, nft_base_chain(chain)->ops, hook_nops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++	nf_unregister_net_hook(net, &nft_base_chain(chain)->ops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -595,8 +592,7 @@ static void _nf_tables_table_disable(str 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		if (cnt && i++ == cnt) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 			break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-		nf_unregister_net_hooks(net, nft_base_chain(chain)->ops, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-					afi->nops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		nf_unregister_net_hook(net, &nft_base_chain(chain)->ops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -613,8 +609,7 @@ static int nf_tables_table_enable(struct 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		if (!nft_is_base_chain(chain)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 			continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-		err = nf_register_net_hooks(net, nft_base_chain(chain)->ops, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-					    afi->nops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		err = nf_register_net_hook(net, &nft_base_chain(chain)->ops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		if (err < 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 			goto err; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -1026,7 +1021,7 @@ static int nf_tables_fill_chain_info(str 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	if (nft_is_base_chain(chain)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		const struct nft_base_chain *basechain = nft_base_chain(chain); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-		const struct nf_hook_ops *ops = &basechain->ops[0]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		const struct nf_hook_ops *ops = &basechain->ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		struct nlattr *nest; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		nest = nla_nest_start(skb, NFTA_CHAIN_HOOK); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -1252,8 +1247,8 @@ static void nf_tables_chain_destroy(stru 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		free_percpu(basechain->stats); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		if (basechain->stats) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 			static_branch_dec(&nft_counters_enabled); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-		if (basechain->ops[0].dev != NULL) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			dev_put(basechain->ops[0].dev); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		if (basechain->ops.dev != NULL) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++			dev_put(basechain->ops.dev); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		kfree(chain->name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		kfree(basechain); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -1349,7 +1344,6 @@ static int nf_tables_addchain(struct nft 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	struct nft_stats __percpu *stats; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	struct net *net = ctx->net; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	struct nft_chain *chain; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	unsigned int i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	int err; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	if (table->use == UINT_MAX) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -1388,21 +1382,18 @@ static int nf_tables_addchain(struct nft 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		basechain->type = hook.type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		chain = &basechain->chain; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-		for (i = 0; i < afi->nops; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			ops = &basechain->ops[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			ops->pf		= family; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			ops->hooknum	= hook.num; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			ops->priority	= hook.priority; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			ops->priv	= chain; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			ops->hook	= afi->hooks[ops->hooknum]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			ops->dev	= hook.dev; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			if (hookfn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-				ops->hook = hookfn; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			if (afi->hook_ops_init) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-				afi->hook_ops_init(ops, i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			if (basechain->type->type == NFT_CHAIN_T_NAT) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-				ops->nat_hook = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		ops		= &basechain->ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		ops->pf		= family; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		ops->hooknum	= hook.num; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		ops->priority	= hook.priority; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		ops->priv	= chain; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		ops->hook	= afi->hooks[ops->hooknum]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		ops->dev	= hook.dev; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		if (hookfn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++			ops->hook = hookfn; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		if (basechain->type->type == NFT_CHAIN_T_NAT) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++			ops->nat_hook = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		chain->flags |= NFT_BASE_CHAIN; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		basechain->policy = policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -1420,7 +1411,7 @@ static int nf_tables_addchain(struct nft 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		goto err1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	err = nf_tables_register_hooks(net, table, chain, afi->nops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++	err = nf_tables_register_hook(net, table, chain); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	if (err < 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		goto err1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -1434,7 +1425,7 @@ static int nf_tables_addchain(struct nft 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ err2: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	nf_tables_unregister_hooks(net, table, chain, afi->nops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++	nf_tables_unregister_hook(net, table, chain); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ err1: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	nf_tables_chain_destroy(chain); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -1447,14 +1438,13 @@ static int nf_tables_updchain(struct nft 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	const struct nlattr * const *nla = ctx->nla; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	struct nft_table *table = ctx->table; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	struct nft_chain *chain = ctx->chain; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	struct nft_af_info *afi = ctx->afi; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	struct nft_base_chain *basechain; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	struct nft_stats *stats = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	struct nft_chain_hook hook; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	const struct nlattr *name; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	struct nf_hook_ops *ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	struct nft_trans *trans; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	int err, i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++	int err; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	if (nla[NFTA_CHAIN_HOOK]) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		if (!nft_is_base_chain(chain)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -1471,14 +1461,12 @@ static int nf_tables_updchain(struct nft 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 			return -EBUSY; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-		for (i = 0; i < afi->nops; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			ops = &basechain->ops[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			if (ops->hooknum != hook.num || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			    ops->priority != hook.priority || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			    ops->dev != hook.dev) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-				nft_chain_release_hook(&hook); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-				return -EBUSY; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		ops = &basechain->ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		if (ops->hooknum != hook.num || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		    ops->priority != hook.priority || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		    ops->dev != hook.dev) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++			nft_chain_release_hook(&hook); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++			return -EBUSY; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		nft_chain_release_hook(&hook); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -5060,10 +5048,9 @@ static int nf_tables_commit(struct net * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		case NFT_MSG_DELCHAIN: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 			list_del_rcu(&trans->ctx.chain->list); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 			nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			nf_tables_unregister_hooks(trans->ctx.net, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-						   trans->ctx.table, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-						   trans->ctx.chain, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-						   trans->ctx.afi->nops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++			nf_tables_unregister_hook(trans->ctx.net, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++						  trans->ctx.table, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++						  trans->ctx.chain); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 			break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		case NFT_MSG_NEWRULE: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 			nft_clear(trans->ctx.net, nft_trans_rule(trans)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -5200,10 +5187,9 @@ static int nf_tables_abort(struct net *n 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 			} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 				trans->ctx.table->use--; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 				list_del_rcu(&trans->ctx.chain->list); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-				nf_tables_unregister_hooks(trans->ctx.net, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-							   trans->ctx.table, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-							   trans->ctx.chain, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-							   trans->ctx.afi->nops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++				nf_tables_unregister_hook(trans->ctx.net, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++							  trans->ctx.table, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++							  trans->ctx.chain); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 			break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		case NFT_MSG_DELCHAIN: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -5304,7 +5290,7 @@ int nft_chain_validate_hooks(const struc 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	if (nft_is_base_chain(chain)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		basechain = nft_base_chain(chain); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-		if ((1 << basechain->ops[0].hooknum) & hook_flags) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		if ((1 << basechain->ops.hooknum) & hook_flags) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 			return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		return -EOPNOTSUPP; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -5786,8 +5772,7 @@ int __nft_release_basechain(struct nft_c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	BUG_ON(!nft_is_base_chain(ctx->chain)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	nf_tables_unregister_hooks(ctx->net, ctx->chain->table, ctx->chain, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-				   ctx->afi->nops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++	nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		list_del(&rule->list); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		ctx->chain->use--; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -5816,8 +5801,7 @@ static void __nft_release_afinfo(struct 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	list_for_each_entry_safe(table, nt, &afi->tables, list) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		list_for_each_entry(chain, &table->chains, list) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-			nf_tables_unregister_hooks(net, table, chain, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-						   afi->nops); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++			nf_tables_unregister_hook(net, table, chain); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		/* No packets are walking on these chains anymore. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		ctx.table = table; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		list_for_each_entry(chain, &table->chains, list) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+--- a/net/netfilter/nf_tables_inet.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++++ b/net/netfilter/nf_tables_inet.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -74,7 +74,6 @@ static struct nft_af_info nft_af_inet __ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.family		= NFPROTO_INET, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.nhooks		= NF_INET_NUMHOOKS, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.owner		= THIS_MODULE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	.nops		= 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.hooks		= { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		[NF_INET_LOCAL_IN]	= nft_do_chain_inet, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		[NF_INET_LOCAL_OUT]	= nft_inet_output, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+--- a/net/netfilter/nf_tables_netdev.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++++ b/net/netfilter/nf_tables_netdev.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -43,7 +43,6 @@ static struct nft_af_info nft_af_netdev 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.nhooks		= NF_NETDEV_NUMHOOKS, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.owner		= THIS_MODULE, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.flags		= NFT_AF_NEEDS_DEV, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-	.nops		= 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	.hooks		= { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		[NF_NETDEV_INGRESS]	= nft_do_chain_netdev, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -98,7 +97,7 @@ static void nft_netdev_event(unsigned lo 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		__nft_release_basechain(ctx); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	case NETDEV_CHANGENAME: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-		if (dev->ifindex != basechain->ops[0].dev->ifindex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		if (dev->ifindex != basechain->ops.dev->ifindex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 			return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		strncpy(basechain->dev_name, dev->name, IFNAMSIZ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+--- a/net/netfilter/nft_compat.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++++ b/net/netfilter/nft_compat.c 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -169,7 +169,7 @@ nft_target_set_tgchk_param(struct xt_tgc 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	if (nft_is_base_chain(ctx->chain)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		const struct nft_base_chain *basechain = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 						nft_base_chain(ctx->chain); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-		const struct nf_hook_ops *ops = &basechain->ops[0]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		const struct nf_hook_ops *ops = &basechain->ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		par->hook_mask = 1 << ops->hooknum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -302,7 +302,7 @@ static int nft_target_validate(const str 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	if (nft_is_base_chain(ctx->chain)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		const struct nft_base_chain *basechain = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 						nft_base_chain(ctx->chain); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-		const struct nf_hook_ops *ops = &basechain->ops[0]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		const struct nf_hook_ops *ops = &basechain->ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		hook_mask = 1 << ops->hooknum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		if (target->hooks && !(hook_mask & target->hooks)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -383,7 +383,7 @@ nft_match_set_mtchk_param(struct xt_mtch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	if (nft_is_base_chain(ctx->chain)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		const struct nft_base_chain *basechain = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 						nft_base_chain(ctx->chain); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-		const struct nf_hook_ops *ops = &basechain->ops[0]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		const struct nf_hook_ops *ops = &basechain->ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		par->hook_mask = 1 << ops->hooknum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@@ -481,7 +481,7 @@ static int nft_match_validate(const stru 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 	if (nft_is_base_chain(ctx->chain)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		const struct nft_base_chain *basechain = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 						nft_base_chain(ctx->chain); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+-		const struct nf_hook_ops *ops = &basechain->ops[0]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				++		const struct nf_hook_ops *ops = &basechain->ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		hook_mask = 1 << ops->hooknum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 		if (match->hooks && !(hook_mask & match->hooks)) 
			 |