Commit eb43c081 authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next

Pablo Neira Ayuso says:

====================
Netfilter updates for net-next

The following patchset contains Netfilter updates for net-next:

1) The various ip(6)table_foo incarnations are updated to expect
   that the table is passed as 'void *priv' argument that netfilter core
   passes to the hook functions. This reduces the struct net size by 2
   cachelines on x86_64. From Florian Westphal.

2) Add cgroupsv2 support for nftables.

3) Fix bridge log family merge into nf_log_syslog: Missing
   unregistration from netns exit path, from Phil Sutter.

4) Add nft_pernet() helper to access nftables pernet area.

5) Add struct nfnl_info to reduce nfnetlink callback footprint and
   to facilite future updates. Consolidate nfnetlink callbacks.

6) Add CONFIG_NETFILTER_XTABLES_COMPAT Kconfig knob, also from Florian.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6876a18d 47a6959f
...@@ -7,21 +7,26 @@ ...@@ -7,21 +7,26 @@
#include <net/netlink.h> #include <net/netlink.h>
#include <uapi/linux/netfilter/nfnetlink.h> #include <uapi/linux/netfilter/nfnetlink.h>
struct nfnl_info {
struct net *net;
struct sock *sk;
const struct nlmsghdr *nlh;
struct netlink_ext_ack *extack;
};
enum nfnl_callback_type {
NFNL_CB_UNSPEC = 0,
NFNL_CB_MUTEX,
NFNL_CB_RCU,
NFNL_CB_BATCH,
};
struct nfnl_callback { struct nfnl_callback {
int (*call)(struct net *net, struct sock *nl, struct sk_buff *skb, int (*call)(struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const cda[]);
const struct nlattr * const cda[], const struct nla_policy *policy;
struct netlink_ext_ack *extack); enum nfnl_callback_type type;
int (*call_rcu)(struct net *net, struct sock *nl, struct sk_buff *skb, __u16 attr_count;
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack);
int (*call_batch)(struct net *net, struct sock *nl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[],
struct netlink_ext_ack *extack);
const struct nla_policy *policy; /* netlink attribute policy */
const u_int16_t attr_count; /* number of nlattr's */
}; };
enum nfnl_abort_action { enum nfnl_abort_action {
......
...@@ -158,7 +158,7 @@ struct xt_match { ...@@ -158,7 +158,7 @@ struct xt_match {
/* Called when entry of this type deleted. */ /* Called when entry of this type deleted. */
void (*destroy)(const struct xt_mtdtor_param *); void (*destroy)(const struct xt_mtdtor_param *);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* Called when userspace align differs from kernel space one */ /* Called when userspace align differs from kernel space one */
void (*compat_from_user)(void *dst, const void *src); void (*compat_from_user)(void *dst, const void *src);
int (*compat_to_user)(void __user *dst, const void *src); int (*compat_to_user)(void __user *dst, const void *src);
...@@ -169,7 +169,7 @@ struct xt_match { ...@@ -169,7 +169,7 @@ struct xt_match {
const char *table; const char *table;
unsigned int matchsize; unsigned int matchsize;
unsigned int usersize; unsigned int usersize;
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
unsigned int compatsize; unsigned int compatsize;
#endif #endif
unsigned int hooks; unsigned int hooks;
...@@ -199,7 +199,7 @@ struct xt_target { ...@@ -199,7 +199,7 @@ struct xt_target {
/* Called when entry of this type deleted. */ /* Called when entry of this type deleted. */
void (*destroy)(const struct xt_tgdtor_param *); void (*destroy)(const struct xt_tgdtor_param *);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* Called when userspace align differs from kernel space one */ /* Called when userspace align differs from kernel space one */
void (*compat_from_user)(void *dst, const void *src); void (*compat_from_user)(void *dst, const void *src);
int (*compat_to_user)(void __user *dst, const void *src); int (*compat_to_user)(void __user *dst, const void *src);
...@@ -210,7 +210,7 @@ struct xt_target { ...@@ -210,7 +210,7 @@ struct xt_target {
const char *table; const char *table;
unsigned int targetsize; unsigned int targetsize;
unsigned int usersize; unsigned int usersize;
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
unsigned int compatsize; unsigned int compatsize;
#endif #endif
unsigned int hooks; unsigned int hooks;
...@@ -229,6 +229,9 @@ struct xt_table { ...@@ -229,6 +229,9 @@ struct xt_table {
/* Man behind the curtain... */ /* Man behind the curtain... */
struct xt_table_info *private; struct xt_table_info *private;
/* hook ops that register the table with the netfilter core */
struct nf_hook_ops *ops;
/* Set this to THIS_MODULE if you are a module, otherwise NULL */ /* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me; struct module *me;
...@@ -322,6 +325,7 @@ struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision); ...@@ -322,6 +325,7 @@ struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision);
int xt_find_revision(u8 af, const char *name, u8 revision, int target, int xt_find_revision(u8 af, const char *name, u8 revision, int target,
int *err); int *err);
struct xt_table *xt_find_table(struct net *net, u8 af, const char *name);
struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
const char *name); const char *name);
struct xt_table *xt_request_find_table_lock(struct net *net, u_int8_t af, struct xt_table *xt_request_find_table_lock(struct net *net, u_int8_t af,
...@@ -448,7 +452,7 @@ xt_get_per_cpu_counter(struct xt_counters *cnt, unsigned int cpu) ...@@ -448,7 +452,7 @@ xt_get_per_cpu_counter(struct xt_counters *cnt, unsigned int cpu)
struct nf_hook_ops *xt_hook_ops_alloc(const struct xt_table *, nf_hookfn *); struct nf_hook_ops *xt_hook_ops_alloc(const struct xt_table *, nf_hookfn *);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h> #include <net/compat.h>
struct compat_xt_entry_match { struct compat_xt_entry_match {
...@@ -529,5 +533,5 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems, ...@@ -529,5 +533,5 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems,
unsigned int target_offset, unsigned int target_offset,
unsigned int next_offset); unsigned int next_offset);
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
#endif /* _X_TABLES_H */ #endif /* _X_TABLES_H */
...@@ -51,15 +51,15 @@ struct arpt_error { ...@@ -51,15 +51,15 @@ struct arpt_error {
extern void *arpt_alloc_initial_table(const struct xt_table *); extern void *arpt_alloc_initial_table(const struct xt_table *);
int arpt_register_table(struct net *net, const struct xt_table *table, int arpt_register_table(struct net *net, const struct xt_table *table,
const struct arpt_replace *repl, const struct arpt_replace *repl,
const struct nf_hook_ops *ops, struct xt_table **res); const struct nf_hook_ops *ops);
void arpt_unregister_table(struct net *net, struct xt_table *table); void arpt_unregister_table(struct net *net, const char *name);
void arpt_unregister_table_pre_exit(struct net *net, struct xt_table *table, void arpt_unregister_table_pre_exit(struct net *net, const char *name,
const struct nf_hook_ops *ops); const struct nf_hook_ops *ops);
extern unsigned int arpt_do_table(struct sk_buff *skb, extern unsigned int arpt_do_table(struct sk_buff *skb,
const struct nf_hook_state *state, const struct nf_hook_state *state,
struct xt_table *table); struct xt_table *table);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h> #include <net/compat.h>
struct compat_arpt_entry { struct compat_arpt_entry {
......
...@@ -100,6 +100,7 @@ struct ebt_table { ...@@ -100,6 +100,7 @@ struct ebt_table {
unsigned int valid_hooks); unsigned int valid_hooks);
/* the data used by the kernel */ /* the data used by the kernel */
struct ebt_table_info *private; struct ebt_table_info *private;
struct nf_hook_ops *ops;
struct module *me; struct module *me;
}; };
...@@ -108,11 +109,9 @@ struct ebt_table { ...@@ -108,11 +109,9 @@ struct ebt_table {
extern int ebt_register_table(struct net *net, extern int ebt_register_table(struct net *net,
const struct ebt_table *table, const struct ebt_table *table,
const struct nf_hook_ops *ops, const struct nf_hook_ops *ops);
struct ebt_table **res); extern void ebt_unregister_table(struct net *net, const char *tablename);
extern void ebt_unregister_table(struct net *net, struct ebt_table *table); void ebt_unregister_table_pre_exit(struct net *net, const char *tablename);
void ebt_unregister_table_pre_exit(struct net *net, const char *tablename,
const struct nf_hook_ops *ops);
extern unsigned int ebt_do_table(struct sk_buff *skb, extern unsigned int ebt_do_table(struct sk_buff *skb,
const struct nf_hook_state *state, const struct nf_hook_state *state,
struct ebt_table *table); struct ebt_table *table);
......
...@@ -24,15 +24,10 @@ ...@@ -24,15 +24,10 @@
int ipt_register_table(struct net *net, const struct xt_table *table, int ipt_register_table(struct net *net, const struct xt_table *table,
const struct ipt_replace *repl, const struct ipt_replace *repl,
const struct nf_hook_ops *ops, struct xt_table **res);
void ipt_unregister_table_pre_exit(struct net *net, struct xt_table *table,
const struct nf_hook_ops *ops); const struct nf_hook_ops *ops);
void ipt_unregister_table_exit(struct net *net, struct xt_table *table); void ipt_unregister_table_pre_exit(struct net *net, const char *name);
void ipt_unregister_table_exit(struct net *net, const char *name);
void ipt_unregister_table(struct net *net, struct xt_table *table,
const struct nf_hook_ops *ops);
/* Standard entry. */ /* Standard entry. */
struct ipt_standard { struct ipt_standard {
...@@ -72,7 +67,7 @@ extern unsigned int ipt_do_table(struct sk_buff *skb, ...@@ -72,7 +67,7 @@ extern unsigned int ipt_do_table(struct sk_buff *skb,
const struct nf_hook_state *state, const struct nf_hook_state *state,
struct xt_table *table); struct xt_table *table);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h> #include <net/compat.h>
struct compat_ipt_entry { struct compat_ipt_entry {
......
...@@ -26,17 +26,14 @@ extern void *ip6t_alloc_initial_table(const struct xt_table *); ...@@ -26,17 +26,14 @@ extern void *ip6t_alloc_initial_table(const struct xt_table *);
int ip6t_register_table(struct net *net, const struct xt_table *table, int ip6t_register_table(struct net *net, const struct xt_table *table,
const struct ip6t_replace *repl, const struct ip6t_replace *repl,
const struct nf_hook_ops *ops, struct xt_table **res); const struct nf_hook_ops *ops);
void ip6t_unregister_table(struct net *net, struct xt_table *table, void ip6t_unregister_table_pre_exit(struct net *net, const char *name);
const struct nf_hook_ops *ops); void ip6t_unregister_table_exit(struct net *net, const char *name);
void ip6t_unregister_table_pre_exit(struct net *net, struct xt_table *table,
const struct nf_hook_ops *ops);
void ip6t_unregister_table_exit(struct net *net, struct xt_table *table);
extern unsigned int ip6t_do_table(struct sk_buff *skb, extern unsigned int ip6t_do_table(struct sk_buff *skb,
const struct nf_hook_state *state, const struct nf_hook_state *state,
struct xt_table *table); struct xt_table *table);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
#include <net/compat.h> #include <net/compat.h>
struct compat_ip6t_entry { struct compat_ip6t_entry {
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#define _NF_DEFRAG_IPV4_H #define _NF_DEFRAG_IPV4_H
struct net; 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 */ #endif /* _NF_DEFRAG_IPV4_H */
...@@ -5,7 +5,8 @@ ...@@ -5,7 +5,8 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/types.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); int nf_ct_frag6_init(void);
void nf_ct_frag6_cleanup(void); void nf_ct_frag6_cleanup(void);
......
...@@ -104,8 +104,6 @@ unsigned int ...@@ -104,8 +104,6 @@ unsigned int
nf_nat_inet_fn(void *priv, struct sk_buff *skb, nf_nat_inet_fn(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state); const struct nf_hook_state *state);
int nf_xfrm_me_harder(struct net *n, struct sk_buff *s, unsigned int family);
static inline int nf_nat_initialized(struct nf_conn *ct, static inline int nf_nat_initialized(struct nf_conn *ct,
enum nf_nat_manip_type manip) enum nf_nat_manip_type manip)
{ {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <net/netfilter/nf_flow_table.h> #include <net/netfilter/nf_flow_table.h>
#include <net/netlink.h> #include <net/netlink.h>
#include <net/flow_offload.h> #include <net/flow_offload.h>
#include <net/netns/generic.h>
#define NFT_MAX_HOOKS (NF_INET_INGRESS + 1) #define NFT_MAX_HOOKS (NF_INET_INGRESS + 1)
...@@ -1580,4 +1581,11 @@ struct nftables_pernet { ...@@ -1580,4 +1581,11 @@ struct nftables_pernet {
u8 validate_state; u8 validate_state;
}; };
extern unsigned int nf_tables_net_id;
static inline struct nftables_pernet *nft_pernet(const struct net *net)
{
return net_generic(net, nf_tables_net_id);
}
#endif /* _NET_NF_TABLES_H */ #endif /* _NET_NF_TABLES_H */
...@@ -76,16 +76,6 @@ struct netns_ipv4 { ...@@ -76,16 +76,6 @@ struct netns_ipv4 {
struct inet_peer_base *peers; struct inet_peer_base *peers;
struct sock * __percpu *tcp_sk; struct sock * __percpu *tcp_sk;
struct fqdir *fqdir; struct fqdir *fqdir;
#ifdef CONFIG_NETFILTER
struct xt_table *iptable_filter;
struct xt_table *iptable_mangle;
struct xt_table *iptable_raw;
struct xt_table *arptable_filter;
#ifdef CONFIG_SECURITY
struct xt_table *iptable_security;
#endif
struct xt_table *nat_table;
#endif
u8 sysctl_icmp_echo_ignore_all; u8 sysctl_icmp_echo_ignore_all;
u8 sysctl_icmp_echo_enable_probe; u8 sysctl_icmp_echo_enable_probe;
......
...@@ -63,15 +63,6 @@ struct netns_ipv6 { ...@@ -63,15 +63,6 @@ struct netns_ipv6 {
struct ipv6_devconf *devconf_dflt; struct ipv6_devconf *devconf_dflt;
struct inet_peer_base *peers; struct inet_peer_base *peers;
struct fqdir *fqdir; struct fqdir *fqdir;
#ifdef CONFIG_NETFILTER
struct xt_table *ip6table_filter;
struct xt_table *ip6table_mangle;
struct xt_table *ip6table_raw;
#ifdef CONFIG_SECURITY
struct xt_table *ip6table_security;
#endif
struct xt_table *ip6table_nat;
#endif
struct fib6_info *fib6_null_entry; struct fib6_info *fib6_null_entry;
struct rt6_info *ip6_null_entry; struct rt6_info *ip6_null_entry;
struct rt6_statistics *rt6_stats; struct rt6_statistics *rt6_stats;
......
...@@ -5,16 +5,8 @@ ...@@ -5,16 +5,8 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/netfilter_defs.h> #include <linux/netfilter_defs.h>
struct ebt_table;
struct netns_xt { struct netns_xt {
bool notrack_deprecated_warning; bool notrack_deprecated_warning;
bool clusterip_deprecated_warning; bool clusterip_deprecated_warning;
#if defined(CONFIG_BRIDGE_NF_EBTABLES) || \
defined(CONFIG_BRIDGE_NF_EBTABLES_MODULE)
struct ebt_table *broute_table;
struct ebt_table *frame_filter;
struct ebt_table *frame_nat;
#endif
}; };
#endif #endif
...@@ -1014,11 +1014,13 @@ enum nft_rt_attributes { ...@@ -1014,11 +1014,13 @@ enum nft_rt_attributes {
* *
* @NFTA_SOCKET_KEY: socket key to match * @NFTA_SOCKET_KEY: socket key to match
* @NFTA_SOCKET_DREG: destination register * @NFTA_SOCKET_DREG: destination register
* @NFTA_SOCKET_LEVEL: cgroups2 ancestor level (only for cgroupsv2)
*/ */
enum nft_socket_attributes { enum nft_socket_attributes {
NFTA_SOCKET_UNSPEC, NFTA_SOCKET_UNSPEC,
NFTA_SOCKET_KEY, NFTA_SOCKET_KEY,
NFTA_SOCKET_DREG, NFTA_SOCKET_DREG,
NFTA_SOCKET_LEVEL,
__NFTA_SOCKET_MAX __NFTA_SOCKET_MAX
}; };
#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1) #define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1)
...@@ -1029,11 +1031,13 @@ enum nft_socket_attributes { ...@@ -1029,11 +1031,13 @@ enum nft_socket_attributes {
* @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option
* @NFT_SOCKET_MARK: Value of the socket mark * @NFT_SOCKET_MARK: Value of the socket mark
* @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0) * @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0)
* @NFT_SOCKET_CGROUPV2: Match on cgroups version 2
*/ */
enum nft_socket_keys { enum nft_socket_keys {
NFT_SOCKET_TRANSPARENT, NFT_SOCKET_TRANSPARENT,
NFT_SOCKET_MARK, NFT_SOCKET_MARK,
NFT_SOCKET_WILDCARD, NFT_SOCKET_WILDCARD,
NFT_SOCKET_CGROUPV2,
__NFT_SOCKET_MAX __NFT_SOCKET_MAX
}; };
#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1) #define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1)
......
...@@ -87,7 +87,7 @@ static int ebt_limit_mt_check(const struct xt_mtchk_param *par) ...@@ -87,7 +87,7 @@ static int ebt_limit_mt_check(const struct xt_mtchk_param *par)
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* /*
* no conversion function needed -- * no conversion function needed --
* only avg/burst have meaningful values in userspace. * only avg/burst have meaningful values in userspace.
...@@ -107,7 +107,7 @@ static struct xt_match ebt_limit_mt_reg __read_mostly = { ...@@ -107,7 +107,7 @@ static struct xt_match ebt_limit_mt_reg __read_mostly = {
.checkentry = ebt_limit_mt_check, .checkentry = ebt_limit_mt_check,
.matchsize = sizeof(struct ebt_limit_info), .matchsize = sizeof(struct ebt_limit_info),
.usersize = offsetof(struct ebt_limit_info, prev), .usersize = offsetof(struct ebt_limit_info, prev),
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct ebt_compat_limit_info), .compatsize = sizeof(struct ebt_compat_limit_info),
#endif #endif
.me = THIS_MODULE, .me = THIS_MODULE,
......
...@@ -53,7 +53,7 @@ static int ebt_mark_tg_check(const struct xt_tgchk_param *par) ...@@ -53,7 +53,7 @@ static int ebt_mark_tg_check(const struct xt_tgchk_param *par)
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ebt_mark_t_info { struct compat_ebt_mark_t_info {
compat_ulong_t mark; compat_ulong_t mark;
compat_uint_t target; compat_uint_t target;
...@@ -87,7 +87,7 @@ static struct xt_target ebt_mark_tg_reg __read_mostly = { ...@@ -87,7 +87,7 @@ static struct xt_target ebt_mark_tg_reg __read_mostly = {
.target = ebt_mark_tg, .target = ebt_mark_tg,
.checkentry = ebt_mark_tg_check, .checkentry = ebt_mark_tg_check,
.targetsize = sizeof(struct ebt_mark_t_info), .targetsize = sizeof(struct ebt_mark_t_info),
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ebt_mark_t_info), .compatsize = sizeof(struct compat_ebt_mark_t_info),
.compat_from_user = mark_tg_compat_from_user, .compat_from_user = mark_tg_compat_from_user,
.compat_to_user = mark_tg_compat_to_user, .compat_to_user = mark_tg_compat_to_user,
......
...@@ -37,7 +37,7 @@ static int ebt_mark_mt_check(const struct xt_mtchk_param *par) ...@@ -37,7 +37,7 @@ static int ebt_mark_mt_check(const struct xt_mtchk_param *par)
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ebt_mark_m_info { struct compat_ebt_mark_m_info {
compat_ulong_t mark, mask; compat_ulong_t mark, mask;
uint8_t invert, bitmask; uint8_t invert, bitmask;
...@@ -75,7 +75,7 @@ static struct xt_match ebt_mark_mt_reg __read_mostly = { ...@@ -75,7 +75,7 @@ static struct xt_match ebt_mark_mt_reg __read_mostly = {
.match = ebt_mark_mt, .match = ebt_mark_mt,
.checkentry = ebt_mark_mt_check, .checkentry = ebt_mark_mt_check,
.matchsize = sizeof(struct ebt_mark_m_info), .matchsize = sizeof(struct ebt_mark_m_info),
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ebt_mark_m_info), .compatsize = sizeof(struct compat_ebt_mark_m_info),
.compat_from_user = mark_mt_compat_from_user, .compat_from_user = mark_mt_compat_from_user,
.compat_to_user = mark_mt_compat_to_user, .compat_to_user = mark_mt_compat_to_user,
......
...@@ -66,8 +66,7 @@ static unsigned int ebt_broute(void *priv, struct sk_buff *skb, ...@@ -66,8 +66,7 @@ static unsigned int ebt_broute(void *priv, struct sk_buff *skb,
NFPROTO_BRIDGE, s->in, NULL, NULL, NFPROTO_BRIDGE, s->in, NULL, NULL,
s->net, NULL); s->net, NULL);
ret = ebt_do_table(skb, &state, state.net->xt.broute_table); ret = ebt_do_table(skb, &state, priv);
if (ret != NF_DROP) if (ret != NF_DROP)
return ret; return ret;
...@@ -101,18 +100,17 @@ static const struct nf_hook_ops ebt_ops_broute = { ...@@ -101,18 +100,17 @@ static const struct nf_hook_ops ebt_ops_broute = {
static int __net_init broute_net_init(struct net *net) static int __net_init broute_net_init(struct net *net)
{ {
return ebt_register_table(net, &broute_table, &ebt_ops_broute, return ebt_register_table(net, &broute_table, &ebt_ops_broute);
&net->xt.broute_table);
} }
static void __net_exit broute_net_pre_exit(struct net *net) static void __net_exit broute_net_pre_exit(struct net *net)
{ {
ebt_unregister_table_pre_exit(net, "broute", &ebt_ops_broute); ebt_unregister_table_pre_exit(net, "broute");
} }
static void __net_exit broute_net_exit(struct net *net) static void __net_exit broute_net_exit(struct net *net)
{ {
ebt_unregister_table(net, net->xt.broute_table); ebt_unregister_table(net, "broute");
} }
static struct pernet_operations broute_net_ops = { static struct pernet_operations broute_net_ops = {
......
...@@ -59,34 +59,27 @@ static const struct ebt_table frame_filter = { ...@@ -59,34 +59,27 @@ static const struct ebt_table frame_filter = {
}; };
static unsigned int static unsigned int
ebt_in_hook(void *priv, struct sk_buff *skb, ebt_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ebt_do_table(skb, state, state->net->xt.frame_filter); return ebt_do_table(skb, state, priv);
}
static unsigned int
ebt_out_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
return ebt_do_table(skb, state, state->net->xt.frame_filter);
} }
static const struct nf_hook_ops ebt_ops_filter[] = { static const struct nf_hook_ops ebt_ops_filter[] = {
{ {
.hook = ebt_in_hook, .hook = ebt_filter_hook,
.pf = NFPROTO_BRIDGE, .pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_LOCAL_IN, .hooknum = NF_BR_LOCAL_IN,
.priority = NF_BR_PRI_FILTER_BRIDGED, .priority = NF_BR_PRI_FILTER_BRIDGED,
}, },
{ {
.hook = ebt_in_hook, .hook = ebt_filter_hook,
.pf = NFPROTO_BRIDGE, .pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_FORWARD, .hooknum = NF_BR_FORWARD,
.priority = NF_BR_PRI_FILTER_BRIDGED, .priority = NF_BR_PRI_FILTER_BRIDGED,
}, },
{ {
.hook = ebt_out_hook, .hook = ebt_filter_hook,
.pf = NFPROTO_BRIDGE, .pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_LOCAL_OUT, .hooknum = NF_BR_LOCAL_OUT,
.priority = NF_BR_PRI_FILTER_OTHER, .priority = NF_BR_PRI_FILTER_OTHER,
...@@ -95,18 +88,17 @@ static const struct nf_hook_ops ebt_ops_filter[] = { ...@@ -95,18 +88,17 @@ static const struct nf_hook_ops ebt_ops_filter[] = {
static int __net_init frame_filter_net_init(struct net *net) static int __net_init frame_filter_net_init(struct net *net)
{ {
return ebt_register_table(net, &frame_filter, ebt_ops_filter, return ebt_register_table(net, &frame_filter, ebt_ops_filter);
&net->xt.frame_filter);
} }
static void __net_exit frame_filter_net_pre_exit(struct net *net) static void __net_exit frame_filter_net_pre_exit(struct net *net)
{ {
ebt_unregister_table_pre_exit(net, "filter", ebt_ops_filter); ebt_unregister_table_pre_exit(net, "filter");
} }
static void __net_exit frame_filter_net_exit(struct net *net) static void __net_exit frame_filter_net_exit(struct net *net)
{ {
ebt_unregister_table(net, net->xt.frame_filter); ebt_unregister_table(net, "filter");
} }
static struct pernet_operations frame_filter_net_ops = { static struct pernet_operations frame_filter_net_ops = {
......
...@@ -58,35 +58,27 @@ static const struct ebt_table frame_nat = { ...@@ -58,35 +58,27 @@ static const struct ebt_table frame_nat = {
.me = THIS_MODULE, .me = THIS_MODULE,
}; };
static unsigned int static unsigned int ebt_nat_hook(void *priv, struct sk_buff *skb,
ebt_nat_in(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
const struct nf_hook_state *state)
{ {
return ebt_do_table(skb, state, state->net->xt.frame_nat); return ebt_do_table(skb, state, priv);
}
static unsigned int
ebt_nat_out(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
return ebt_do_table(skb, state, state->net->xt.frame_nat);
} }
static const struct nf_hook_ops ebt_ops_nat[] = { static const struct nf_hook_ops ebt_ops_nat[] = {
{ {
.hook = ebt_nat_out, .hook = ebt_nat_hook,
.pf = NFPROTO_BRIDGE, .pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_LOCAL_OUT, .hooknum = NF_BR_LOCAL_OUT,
.priority = NF_BR_PRI_NAT_DST_OTHER, .priority = NF_BR_PRI_NAT_DST_OTHER,
}, },
{ {
.hook = ebt_nat_out, .hook = ebt_nat_hook,
.pf = NFPROTO_BRIDGE, .pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_POST_ROUTING, .hooknum = NF_BR_POST_ROUTING,
.priority = NF_BR_PRI_NAT_SRC, .priority = NF_BR_PRI_NAT_SRC,
}, },
{ {
.hook = ebt_nat_in, .hook = ebt_nat_hook,
.pf = NFPROTO_BRIDGE, .pf = NFPROTO_BRIDGE,
.hooknum = NF_BR_PRE_ROUTING, .hooknum = NF_BR_PRE_ROUTING,
.priority = NF_BR_PRI_NAT_DST_BRIDGED, .priority = NF_BR_PRI_NAT_DST_BRIDGED,
...@@ -95,18 +87,17 @@ static const struct nf_hook_ops ebt_ops_nat[] = { ...@@ -95,18 +87,17 @@ static const struct nf_hook_ops ebt_ops_nat[] = {
static int __net_init frame_nat_net_init(struct net *net) static int __net_init frame_nat_net_init(struct net *net)
{ {
return ebt_register_table(net, &frame_nat, ebt_ops_nat, return ebt_register_table(net, &frame_nat, ebt_ops_nat);
&net->xt.frame_nat);
} }
static void __net_exit frame_nat_net_pre_exit(struct net *net) static void __net_exit frame_nat_net_pre_exit(struct net *net)
{ {
ebt_unregister_table_pre_exit(net, "nat", ebt_ops_nat); ebt_unregister_table_pre_exit(net, "nat");
} }
static void __net_exit frame_nat_net_exit(struct net *net) static void __net_exit frame_nat_net_exit(struct net *net)
{ {
ebt_unregister_table(net, net->xt.frame_nat); ebt_unregister_table(net, "nat");
} }
static struct pernet_operations frame_nat_net_ops = { static struct pernet_operations frame_nat_net_ops = {
......
...@@ -47,7 +47,7 @@ struct ebt_pernet { ...@@ -47,7 +47,7 @@ struct ebt_pernet {
static unsigned int ebt_pernet_id __read_mostly; static unsigned int ebt_pernet_id __read_mostly;
static DEFINE_MUTEX(ebt_mutex); static DEFINE_MUTEX(ebt_mutex);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void ebt_standard_compat_from_user(void *dst, const void *src) static void ebt_standard_compat_from_user(void *dst, const void *src)
{ {
int v = *(compat_int_t *)src; int v = *(compat_int_t *)src;
...@@ -73,7 +73,7 @@ static struct xt_target ebt_standard_target = { ...@@ -73,7 +73,7 @@ static struct xt_target ebt_standard_target = {
.revision = 0, .revision = 0,
.family = NFPROTO_BRIDGE, .family = NFPROTO_BRIDGE,
.targetsize = sizeof(int), .targetsize = sizeof(int),
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t), .compatsize = sizeof(compat_int_t),
.compat_from_user = ebt_standard_compat_from_user, .compat_from_user = ebt_standard_compat_from_user,
.compat_to_user = ebt_standard_compat_to_user, .compat_to_user = ebt_standard_compat_to_user,
...@@ -1136,15 +1136,18 @@ static void __ebt_unregister_table(struct net *net, struct ebt_table *table) ...@@ -1136,15 +1136,18 @@ static void __ebt_unregister_table(struct net *net, struct ebt_table *table)
vfree(table->private->entries); vfree(table->private->entries);
ebt_free_table_info(table->private); ebt_free_table_info(table->private);
vfree(table->private); vfree(table->private);
kfree(table->ops);
kfree(table); kfree(table);
} }
int ebt_register_table(struct net *net, const struct ebt_table *input_table, int ebt_register_table(struct net *net, const struct ebt_table *input_table,
const struct nf_hook_ops *ops, struct ebt_table **res) const struct nf_hook_ops *template_ops)
{ {
struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id); struct ebt_pernet *ebt_net = net_generic(net, ebt_pernet_id);
struct ebt_table_info *newinfo; struct ebt_table_info *newinfo;
struct ebt_table *t, *table; struct ebt_table *t, *table;
struct nf_hook_ops *ops;
unsigned int num_ops;
struct ebt_replace_kernel *repl; struct ebt_replace_kernel *repl;
int ret, i, countersize; int ret, i, countersize;
void *p; void *p;
...@@ -1213,15 +1216,31 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table, ...@@ -1213,15 +1216,31 @@ int ebt_register_table(struct net *net, const struct ebt_table *input_table,
ret = -ENOENT; ret = -ENOENT;
goto free_unlock; goto free_unlock;
} }
num_ops = hweight32(table->valid_hooks);
if (num_ops == 0) {
ret = -EINVAL;
goto free_unlock;
}
ops = kmemdup(template_ops, sizeof(*ops) * num_ops, GFP_KERNEL);
if (!ops) {
ret = -ENOMEM;
if (newinfo->nentries)
module_put(table->me);
goto free_unlock;
}
for (i = 0; i < num_ops; i++)
ops[i].priv = table;
list_add(&table->list, &ebt_net->tables); list_add(&table->list, &ebt_net->tables);
mutex_unlock(&ebt_mutex); mutex_unlock(&ebt_mutex);
WRITE_ONCE(*res, table); table->ops = ops;
ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks)); ret = nf_register_net_hooks(net, ops, num_ops);
if (ret) { if (ret)
__ebt_unregister_table(net, table); __ebt_unregister_table(net, table);
*res = NULL;
}
audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries, audit_log_nfcfg(repl->name, AF_BRIDGE, repl->nentries,
AUDIT_XT_OP_REGISTER, GFP_KERNEL); AUDIT_XT_OP_REGISTER, GFP_KERNEL);
...@@ -1257,18 +1276,21 @@ static struct ebt_table *__ebt_find_table(struct net *net, const char *name) ...@@ -1257,18 +1276,21 @@ static struct ebt_table *__ebt_find_table(struct net *net, const char *name)
return NULL; return NULL;
} }
void ebt_unregister_table_pre_exit(struct net *net, const char *name, const struct nf_hook_ops *ops) void ebt_unregister_table_pre_exit(struct net *net, const char *name)
{ {
struct ebt_table *table = __ebt_find_table(net, name); struct ebt_table *table = __ebt_find_table(net, name);
if (table) if (table)
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
} }
EXPORT_SYMBOL(ebt_unregister_table_pre_exit); EXPORT_SYMBOL(ebt_unregister_table_pre_exit);
void ebt_unregister_table(struct net *net, struct ebt_table *table) void ebt_unregister_table(struct net *net, const char *name)
{ {
__ebt_unregister_table(net, table); struct ebt_table *table = __ebt_find_table(net, name);
if (table)
__ebt_unregister_table(net, table);
} }
/* userspace just supplied us with counters */ /* userspace just supplied us with counters */
...@@ -1480,7 +1502,7 @@ static int copy_everything_to_user(struct ebt_table *t, void __user *user, ...@@ -1480,7 +1502,7 @@ static int copy_everything_to_user(struct ebt_table *t, void __user *user,
ebt_entry_to_user, entries, tmp.entries); ebt_entry_to_user, entries, tmp.entries);
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* 32 bit-userspace compatibility definitions. */ /* 32 bit-userspace compatibility definitions. */
struct compat_ebt_replace { struct compat_ebt_replace {
char name[EBT_TABLE_MAXNAMELEN]; char name[EBT_TABLE_MAXNAMELEN];
...@@ -2345,7 +2367,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) ...@@ -2345,7 +2367,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM; return -EPERM;
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
/* try real handler in case userland supplied needed padding */ /* try real handler in case userland supplied needed padding */
if (in_compat_syscall() && if (in_compat_syscall() &&
((cmd != EBT_SO_GET_INFO && cmd != EBT_SO_GET_INIT_INFO) || ((cmd != EBT_SO_GET_INFO && cmd != EBT_SO_GET_INIT_INFO) ||
...@@ -2412,7 +2434,7 @@ static int do_ebt_set_ctl(struct sock *sk, int cmd, sockptr_t arg, ...@@ -2412,7 +2434,7 @@ static int do_ebt_set_ctl(struct sock *sk, int cmd, sockptr_t arg,
switch (cmd) { switch (cmd) {
case EBT_SO_SET_ENTRIES: case EBT_SO_SET_ENTRIES:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_do_replace(net, arg, len); ret = compat_do_replace(net, arg, len);
else else
...@@ -2420,7 +2442,7 @@ static int do_ebt_set_ctl(struct sock *sk, int cmd, sockptr_t arg, ...@@ -2420,7 +2442,7 @@ static int do_ebt_set_ctl(struct sock *sk, int cmd, sockptr_t arg,
ret = do_replace(net, arg, len); ret = do_replace(net, arg, len);
break; break;
case EBT_SO_SET_COUNTERS: case EBT_SO_SET_COUNTERS:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_update_counters(net, arg, len); ret = compat_update_counters(net, arg, len);
else else
......
...@@ -713,7 +713,7 @@ static int copy_entries_to_user(unsigned int total_size, ...@@ -713,7 +713,7 @@ static int copy_entries_to_user(unsigned int total_size,
return ret; return ret;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void compat_standard_from_user(void *dst, const void *src) static void compat_standard_from_user(void *dst, const void *src)
{ {
int v = *(compat_int_t *)src; int v = *(compat_int_t *)src;
...@@ -800,7 +800,7 @@ static int get_info(struct net *net, void __user *user, const int *len) ...@@ -800,7 +800,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
return -EFAULT; return -EFAULT;
name[XT_TABLE_MAXNAMELEN-1] = '\0'; name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
xt_compat_lock(NFPROTO_ARP); xt_compat_lock(NFPROTO_ARP);
#endif #endif
...@@ -808,7 +808,7 @@ static int get_info(struct net *net, void __user *user, const int *len) ...@@ -808,7 +808,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
if (!IS_ERR(t)) { if (!IS_ERR(t)) {
struct arpt_getinfo info; struct arpt_getinfo info;
const struct xt_table_info *private = t->private; const struct xt_table_info *private = t->private;
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct xt_table_info tmp; struct xt_table_info tmp;
if (in_compat_syscall()) { if (in_compat_syscall()) {
...@@ -835,7 +835,7 @@ static int get_info(struct net *net, void __user *user, const int *len) ...@@ -835,7 +835,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
module_put(t->me); module_put(t->me);
} else } else
ret = PTR_ERR(t); ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
xt_compat_unlock(NFPROTO_ARP); xt_compat_unlock(NFPROTO_ARP);
#endif #endif
...@@ -1044,7 +1044,7 @@ static int do_add_counters(struct net *net, sockptr_t arg, unsigned int len) ...@@ -1044,7 +1044,7 @@ static int do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
return ret; return ret;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_arpt_replace { struct compat_arpt_replace {
char name[XT_TABLE_MAXNAMELEN]; char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks; u32 valid_hooks;
...@@ -1412,7 +1412,7 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, sockptr_t arg, ...@@ -1412,7 +1412,7 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, sockptr_t arg,
switch (cmd) { switch (cmd) {
case ARPT_SO_SET_REPLACE: case ARPT_SO_SET_REPLACE:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), arg, len); ret = compat_do_replace(sock_net(sk), arg, len);
else else
...@@ -1444,7 +1444,7 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len ...@@ -1444,7 +1444,7 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
break; break;
case ARPT_SO_GET_ENTRIES: case ARPT_SO_GET_ENTRIES:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_get_entries(sock_net(sk), user, len); ret = compat_get_entries(sock_net(sk), user, len);
else else
...@@ -1499,10 +1499,11 @@ static void __arpt_unregister_table(struct net *net, struct xt_table *table) ...@@ -1499,10 +1499,11 @@ static void __arpt_unregister_table(struct net *net, struct xt_table *table)
int arpt_register_table(struct net *net, int arpt_register_table(struct net *net,
const struct xt_table *table, const struct xt_table *table,
const struct arpt_replace *repl, const struct arpt_replace *repl,
const struct nf_hook_ops *ops, const struct nf_hook_ops *template_ops)
struct xt_table **res)
{ {
int ret; struct nf_hook_ops *ops;
unsigned int num_ops;
int ret, i;
struct xt_table_info *newinfo; struct xt_table_info *newinfo;
struct xt_table_info bootstrap = {0}; struct xt_table_info bootstrap = {0};
void *loc_cpu_entry; void *loc_cpu_entry;
...@@ -1516,41 +1517,61 @@ int arpt_register_table(struct net *net, ...@@ -1516,41 +1517,61 @@ int arpt_register_table(struct net *net,
memcpy(loc_cpu_entry, repl->entries, repl->size); memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(net, newinfo, loc_cpu_entry, repl); ret = translate_table(net, newinfo, loc_cpu_entry, repl);
if (ret != 0) if (ret != 0) {
goto out_free; xt_free_table_info(newinfo);
return ret;
}
new_table = xt_register_table(net, table, &bootstrap, newinfo); new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) { if (IS_ERR(new_table)) {
ret = PTR_ERR(new_table); xt_free_table_info(newinfo);
goto out_free; return PTR_ERR(new_table);
} }
/* set res now, will see skbs right after nf_register_net_hooks */ num_ops = hweight32(table->valid_hooks);
WRITE_ONCE(*res, new_table); if (num_ops == 0) {
ret = -EINVAL;
goto out_free;
}
ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks)); ops = kmemdup(template_ops, sizeof(*ops) * num_ops, GFP_KERNEL);
if (ret != 0) { if (!ops) {
__arpt_unregister_table(net, new_table); ret = -ENOMEM;
*res = NULL; goto out_free;
} }
for (i = 0; i < num_ops; i++)
ops[i].priv = new_table;
new_table->ops = ops;
ret = nf_register_net_hooks(net, ops, num_ops);
if (ret != 0)
goto out_free;
return ret; return ret;
out_free: out_free:
xt_free_table_info(newinfo); __arpt_unregister_table(net, new_table);
return ret; return ret;
} }
void arpt_unregister_table_pre_exit(struct net *net, struct xt_table *table, void arpt_unregister_table_pre_exit(struct net *net, const char *name,
const struct nf_hook_ops *ops) const struct nf_hook_ops *ops)
{ {
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name);
if (table)
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
} }
EXPORT_SYMBOL(arpt_unregister_table_pre_exit); EXPORT_SYMBOL(arpt_unregister_table_pre_exit);
void arpt_unregister_table(struct net *net, struct xt_table *table) void arpt_unregister_table(struct net *net, const char *name)
{ {
__arpt_unregister_table(net, table); struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name);
if (table)
__arpt_unregister_table(net, table);
} }
/* The built-in targets: standard (NULL) and error. */ /* The built-in targets: standard (NULL) and error. */
...@@ -1559,7 +1580,7 @@ static struct xt_target arpt_builtin_tg[] __read_mostly = { ...@@ -1559,7 +1580,7 @@ static struct xt_target arpt_builtin_tg[] __read_mostly = {
.name = XT_STANDARD_TARGET, .name = XT_STANDARD_TARGET,
.targetsize = sizeof(int), .targetsize = sizeof(int),
.family = NFPROTO_ARP, .family = NFPROTO_ARP,
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t), .compatsize = sizeof(compat_int_t),
.compat_from_user = compat_standard_from_user, .compat_from_user = compat_standard_from_user,
.compat_to_user = compat_standard_to_user, .compat_to_user = compat_standard_to_user,
......
...@@ -34,7 +34,7 @@ static unsigned int ...@@ -34,7 +34,7 @@ static unsigned int
arptable_filter_hook(void *priv, struct sk_buff *skb, arptable_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return arpt_do_table(skb, state, state->net->ipv4.arptable_filter); return arpt_do_table(skb, state, priv);
} }
static struct nf_hook_ops *arpfilter_ops __read_mostly; static struct nf_hook_ops *arpfilter_ops __read_mostly;
...@@ -44,31 +44,22 @@ static int __net_init arptable_filter_table_init(struct net *net) ...@@ -44,31 +44,22 @@ static int __net_init arptable_filter_table_init(struct net *net)
struct arpt_replace *repl; struct arpt_replace *repl;
int err; int err;
if (net->ipv4.arptable_filter)
return 0;
repl = arpt_alloc_initial_table(&packet_filter); repl = arpt_alloc_initial_table(&packet_filter);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
err = arpt_register_table(net, &packet_filter, repl, arpfilter_ops, err = arpt_register_table(net, &packet_filter, repl, arpfilter_ops);
&net->ipv4.arptable_filter);
kfree(repl); kfree(repl);
return err; return err;
} }
static void __net_exit arptable_filter_net_pre_exit(struct net *net) static void __net_exit arptable_filter_net_pre_exit(struct net *net)
{ {
if (net->ipv4.arptable_filter) arpt_unregister_table_pre_exit(net, "filter", arpfilter_ops);
arpt_unregister_table_pre_exit(net, net->ipv4.arptable_filter,
arpfilter_ops);
} }
static void __net_exit arptable_filter_net_exit(struct net *net) static void __net_exit arptable_filter_net_exit(struct net *net)
{ {
if (!net->ipv4.arptable_filter) arpt_unregister_table(net, "filter");
return;
arpt_unregister_table(net, net->ipv4.arptable_filter);
net->ipv4.arptable_filter = NULL;
} }
static struct pernet_operations arptable_filter_net_ops = { static struct pernet_operations arptable_filter_net_ops = {
......
...@@ -868,7 +868,7 @@ copy_entries_to_user(unsigned int total_size, ...@@ -868,7 +868,7 @@ copy_entries_to_user(unsigned int total_size,
return ret; return ret;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void compat_standard_from_user(void *dst, const void *src) static void compat_standard_from_user(void *dst, const void *src)
{ {
int v = *(compat_int_t *)src; int v = *(compat_int_t *)src;
...@@ -957,7 +957,7 @@ static int get_info(struct net *net, void __user *user, const int *len) ...@@ -957,7 +957,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
return -EFAULT; return -EFAULT;
name[XT_TABLE_MAXNAMELEN-1] = '\0'; name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
xt_compat_lock(AF_INET); xt_compat_lock(AF_INET);
#endif #endif
...@@ -965,7 +965,7 @@ static int get_info(struct net *net, void __user *user, const int *len) ...@@ -965,7 +965,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
if (!IS_ERR(t)) { if (!IS_ERR(t)) {
struct ipt_getinfo info; struct ipt_getinfo info;
const struct xt_table_info *private = t->private; const struct xt_table_info *private = t->private;
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct xt_table_info tmp; struct xt_table_info tmp;
if (in_compat_syscall()) { if (in_compat_syscall()) {
...@@ -993,7 +993,7 @@ static int get_info(struct net *net, void __user *user, const int *len) ...@@ -993,7 +993,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
module_put(t->me); module_put(t->me);
} else } else
ret = PTR_ERR(t); ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
xt_compat_unlock(AF_INET); xt_compat_unlock(AF_INET);
#endif #endif
...@@ -1199,7 +1199,7 @@ do_add_counters(struct net *net, sockptr_t arg, unsigned int len) ...@@ -1199,7 +1199,7 @@ do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
return ret; return ret;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ipt_replace { struct compat_ipt_replace {
char name[XT_TABLE_MAXNAMELEN]; char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks; u32 valid_hooks;
...@@ -1621,7 +1621,7 @@ do_ipt_set_ctl(struct sock *sk, int cmd, sockptr_t arg, unsigned int len) ...@@ -1621,7 +1621,7 @@ do_ipt_set_ctl(struct sock *sk, int cmd, sockptr_t arg, unsigned int len)
switch (cmd) { switch (cmd) {
case IPT_SO_SET_REPLACE: case IPT_SO_SET_REPLACE:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), arg, len); ret = compat_do_replace(sock_net(sk), arg, len);
else else
...@@ -1654,7 +1654,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) ...@@ -1654,7 +1654,7 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
break; break;
case IPT_SO_GET_ENTRIES: case IPT_SO_GET_ENTRIES:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_get_entries(sock_net(sk), user, len); ret = compat_get_entries(sock_net(sk), user, len);
else else
...@@ -1716,9 +1716,11 @@ static void __ipt_unregister_table(struct net *net, struct xt_table *table) ...@@ -1716,9 +1716,11 @@ static void __ipt_unregister_table(struct net *net, struct xt_table *table)
int ipt_register_table(struct net *net, const struct xt_table *table, int ipt_register_table(struct net *net, const struct xt_table *table,
const struct ipt_replace *repl, const struct ipt_replace *repl,
const struct nf_hook_ops *ops, struct xt_table **res) const struct nf_hook_ops *template_ops)
{ {
int ret; struct nf_hook_ops *ops;
unsigned int num_ops;
int ret, i;
struct xt_table_info *newinfo; struct xt_table_info *newinfo;
struct xt_table_info bootstrap = {0}; struct xt_table_info bootstrap = {0};
void *loc_cpu_entry; void *loc_cpu_entry;
...@@ -1732,50 +1734,65 @@ int ipt_register_table(struct net *net, const struct xt_table *table, ...@@ -1732,50 +1734,65 @@ int ipt_register_table(struct net *net, const struct xt_table *table,
memcpy(loc_cpu_entry, repl->entries, repl->size); memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(net, newinfo, loc_cpu_entry, repl); ret = translate_table(net, newinfo, loc_cpu_entry, repl);
if (ret != 0) if (ret != 0) {
goto out_free; xt_free_table_info(newinfo);
return ret;
}
new_table = xt_register_table(net, table, &bootstrap, newinfo); new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) { if (IS_ERR(new_table)) {
ret = PTR_ERR(new_table); xt_free_table_info(newinfo);
goto out_free; return PTR_ERR(new_table);
} }
/* set res now, will see skbs right after nf_register_net_hooks */ /* No template? No need to do anything. This is used by 'nat' table, it registers
WRITE_ONCE(*res, new_table); * with the nat core instead of the netfilter core.
if (!ops) */
if (!template_ops)
return 0; return 0;
ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks)); num_ops = hweight32(table->valid_hooks);
if (ret != 0) { if (num_ops == 0) {
__ipt_unregister_table(net, new_table); ret = -EINVAL;
*res = NULL; goto out_free;
}
ops = kmemdup(template_ops, sizeof(*ops) * num_ops, GFP_KERNEL);
if (!ops) {
ret = -ENOMEM;
goto out_free;
} }
for (i = 0; i < num_ops; i++)
ops[i].priv = new_table;
new_table->ops = ops;
ret = nf_register_net_hooks(net, ops, num_ops);
if (ret != 0)
goto out_free;
return ret; return ret;
out_free: out_free:
xt_free_table_info(newinfo); __ipt_unregister_table(net, new_table);
return ret; return ret;
} }
void ipt_unregister_table_pre_exit(struct net *net, struct xt_table *table, void ipt_unregister_table_pre_exit(struct net *net, const char *name)
const struct nf_hook_ops *ops)
{ {
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name);
}
void ipt_unregister_table_exit(struct net *net, struct xt_table *table) if (table)
{ nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
__ipt_unregister_table(net, table);
} }
void ipt_unregister_table(struct net *net, struct xt_table *table, void ipt_unregister_table_exit(struct net *net, const char *name)
const struct nf_hook_ops *ops)
{ {
if (ops) struct xt_table *table = xt_find_table(net, NFPROTO_IPV4, name);
ipt_unregister_table_pre_exit(net, table, ops);
__ipt_unregister_table(net, table); if (table)
__ipt_unregister_table(net, table);
} }
/* Returns 1 if the type and code is matched by the range, 0 otherwise */ /* Returns 1 if the type and code is matched by the range, 0 otherwise */
...@@ -1829,7 +1846,7 @@ static struct xt_target ipt_builtin_tg[] __read_mostly = { ...@@ -1829,7 +1846,7 @@ static struct xt_target ipt_builtin_tg[] __read_mostly = {
.name = XT_STANDARD_TARGET, .name = XT_STANDARD_TARGET,
.targetsize = sizeof(int), .targetsize = sizeof(int),
.family = NFPROTO_IPV4, .family = NFPROTO_IPV4,
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t), .compatsize = sizeof(compat_int_t),
.compat_from_user = compat_standard_from_user, .compat_from_user = compat_standard_from_user,
.compat_to_user = compat_standard_to_user, .compat_to_user = compat_standard_to_user,
...@@ -1924,7 +1941,6 @@ static void __exit ip_tables_fini(void) ...@@ -1924,7 +1941,6 @@ static void __exit ip_tables_fini(void)
} }
EXPORT_SYMBOL(ipt_register_table); EXPORT_SYMBOL(ipt_register_table);
EXPORT_SYMBOL(ipt_unregister_table);
EXPORT_SYMBOL(ipt_unregister_table_pre_exit); EXPORT_SYMBOL(ipt_unregister_table_pre_exit);
EXPORT_SYMBOL(ipt_unregister_table_exit); EXPORT_SYMBOL(ipt_unregister_table_exit);
EXPORT_SYMBOL(ipt_do_table); EXPORT_SYMBOL(ipt_do_table);
......
...@@ -541,7 +541,7 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par) ...@@ -541,7 +541,7 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
nf_ct_netns_put(par->net, par->family); nf_ct_netns_put(par->net, par->family);
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ipt_clusterip_tgt_info struct compat_ipt_clusterip_tgt_info
{ {
u_int32_t flags; u_int32_t flags;
...@@ -553,7 +553,7 @@ struct compat_ipt_clusterip_tgt_info ...@@ -553,7 +553,7 @@ struct compat_ipt_clusterip_tgt_info
u_int32_t hash_initval; u_int32_t hash_initval;
compat_uptr_t config; compat_uptr_t config;
}; };
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
static struct xt_target clusterip_tg_reg __read_mostly = { static struct xt_target clusterip_tg_reg __read_mostly = {
.name = "CLUSTERIP", .name = "CLUSTERIP",
...@@ -563,9 +563,9 @@ static struct xt_target clusterip_tg_reg __read_mostly = { ...@@ -563,9 +563,9 @@ static struct xt_target clusterip_tg_reg __read_mostly = {
.destroy = clusterip_tg_destroy, .destroy = clusterip_tg_destroy,
.targetsize = sizeof(struct ipt_clusterip_tgt_info), .targetsize = sizeof(struct ipt_clusterip_tgt_info),
.usersize = offsetof(struct ipt_clusterip_tgt_info, config), .usersize = offsetof(struct ipt_clusterip_tgt_info, config),
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(struct compat_ipt_clusterip_tgt_info), .compatsize = sizeof(struct compat_ipt_clusterip_tgt_info),
#endif /* CONFIG_COMPAT */ #endif /* CONFIG_NETFILTER_XTABLES_COMPAT */
.me = THIS_MODULE .me = THIS_MODULE
}; };
......
...@@ -34,7 +34,7 @@ static unsigned int ...@@ -34,7 +34,7 @@ static unsigned int
iptable_filter_hook(void *priv, struct sk_buff *skb, iptable_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ipt_do_table(skb, state, state->net->ipv4.iptable_filter); return ipt_do_table(skb, state, priv);
} }
static struct nf_hook_ops *filter_ops __read_mostly; static struct nf_hook_ops *filter_ops __read_mostly;
...@@ -48,9 +48,6 @@ static int __net_init iptable_filter_table_init(struct net *net) ...@@ -48,9 +48,6 @@ static int __net_init iptable_filter_table_init(struct net *net)
struct ipt_replace *repl; struct ipt_replace *repl;
int err; int err;
if (net->ipv4.iptable_filter)
return 0;
repl = ipt_alloc_initial_table(&packet_filter); repl = ipt_alloc_initial_table(&packet_filter);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -58,8 +55,7 @@ static int __net_init iptable_filter_table_init(struct net *net) ...@@ -58,8 +55,7 @@ static int __net_init iptable_filter_table_init(struct net *net)
((struct ipt_standard *)repl->entries)[1].target.verdict = ((struct ipt_standard *)repl->entries)[1].target.verdict =
forward ? -NF_ACCEPT - 1 : -NF_DROP - 1; forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
err = ipt_register_table(net, &packet_filter, repl, filter_ops, err = ipt_register_table(net, &packet_filter, repl, filter_ops);
&net->ipv4.iptable_filter);
kfree(repl); kfree(repl);
return err; return err;
} }
...@@ -74,17 +70,12 @@ static int __net_init iptable_filter_net_init(struct net *net) ...@@ -74,17 +70,12 @@ static int __net_init iptable_filter_net_init(struct net *net)
static void __net_exit iptable_filter_net_pre_exit(struct net *net) static void __net_exit iptable_filter_net_pre_exit(struct net *net)
{ {
if (net->ipv4.iptable_filter) ipt_unregister_table_pre_exit(net, "filter");
ipt_unregister_table_pre_exit(net, net->ipv4.iptable_filter,
filter_ops);
} }
static void __net_exit iptable_filter_net_exit(struct net *net) static void __net_exit iptable_filter_net_exit(struct net *net)
{ {
if (!net->ipv4.iptable_filter) ipt_unregister_table_exit(net, "filter");
return;
ipt_unregister_table_exit(net, net->ipv4.iptable_filter);
net->ipv4.iptable_filter = NULL;
} }
static struct pernet_operations iptable_filter_net_ops = { static struct pernet_operations iptable_filter_net_ops = {
......
...@@ -37,7 +37,7 @@ static const struct xt_table packet_mangler = { ...@@ -37,7 +37,7 @@ static const struct xt_table packet_mangler = {
}; };
static unsigned int static unsigned int
ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state, void *priv)
{ {
unsigned int ret; unsigned int ret;
const struct iphdr *iph; const struct iphdr *iph;
...@@ -53,7 +53,7 @@ ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) ...@@ -53,7 +53,7 @@ ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
daddr = iph->daddr; daddr = iph->daddr;
tos = iph->tos; tos = iph->tos;
ret = ipt_do_table(skb, state, state->net->ipv4.iptable_mangle); ret = ipt_do_table(skb, state, priv);
/* Reroute for ANY change. */ /* Reroute for ANY change. */
if (ret != NF_DROP && ret != NF_STOLEN) { if (ret != NF_DROP && ret != NF_STOLEN) {
iph = ip_hdr(skb); iph = ip_hdr(skb);
...@@ -78,8 +78,8 @@ iptable_mangle_hook(void *priv, ...@@ -78,8 +78,8 @@ iptable_mangle_hook(void *priv,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
if (state->hook == NF_INET_LOCAL_OUT) if (state->hook == NF_INET_LOCAL_OUT)
return ipt_mangle_out(skb, state); return ipt_mangle_out(skb, state, priv);
return ipt_do_table(skb, state, state->net->ipv4.iptable_mangle); return ipt_do_table(skb, state, priv);
} }
static struct nf_hook_ops *mangle_ops __read_mostly; static struct nf_hook_ops *mangle_ops __read_mostly;
...@@ -88,31 +88,22 @@ static int __net_init iptable_mangle_table_init(struct net *net) ...@@ -88,31 +88,22 @@ static int __net_init iptable_mangle_table_init(struct net *net)
struct ipt_replace *repl; struct ipt_replace *repl;
int ret; int ret;
if (net->ipv4.iptable_mangle)
return 0;
repl = ipt_alloc_initial_table(&packet_mangler); repl = ipt_alloc_initial_table(&packet_mangler);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ipt_register_table(net, &packet_mangler, repl, mangle_ops, ret = ipt_register_table(net, &packet_mangler, repl, mangle_ops);
&net->ipv4.iptable_mangle);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit iptable_mangle_net_pre_exit(struct net *net) static void __net_exit iptable_mangle_net_pre_exit(struct net *net)
{ {
if (net->ipv4.iptable_mangle) ipt_unregister_table_pre_exit(net, "mangle");
ipt_unregister_table_pre_exit(net, net->ipv4.iptable_mangle,
mangle_ops);
} }
static void __net_exit iptable_mangle_net_exit(struct net *net) static void __net_exit iptable_mangle_net_exit(struct net *net)
{ {
if (!net->ipv4.iptable_mangle) ipt_unregister_table_exit(net, "mangle");
return;
ipt_unregister_table_exit(net, net->ipv4.iptable_mangle);
net->ipv4.iptable_mangle = NULL;
} }
static struct pernet_operations iptable_mangle_net_ops = { static struct pernet_operations iptable_mangle_net_ops = {
......
...@@ -13,8 +13,14 @@ ...@@ -13,8 +13,14 @@
#include <net/netfilter/nf_nat.h> #include <net/netfilter/nf_nat.h>
struct iptable_nat_pernet {
struct nf_hook_ops *nf_nat_ops;
};
static int __net_init iptable_nat_table_init(struct net *net); static int __net_init iptable_nat_table_init(struct net *net);
static unsigned int iptable_nat_net_id __read_mostly;
static const struct xt_table nf_nat_ipv4_table = { static const struct xt_table nf_nat_ipv4_table = {
.name = "nat", .name = "nat",
.valid_hooks = (1 << NF_INET_PRE_ROUTING) | .valid_hooks = (1 << NF_INET_PRE_ROUTING) |
...@@ -30,7 +36,7 @@ static unsigned int iptable_nat_do_chain(void *priv, ...@@ -30,7 +36,7 @@ static unsigned int iptable_nat_do_chain(void *priv,
struct sk_buff *skb, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ipt_do_table(skb, state, state->net->ipv4.nat_table); return ipt_do_table(skb, state, priv);
} }
static const struct nf_hook_ops nf_nat_ipv4_ops[] = { static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
...@@ -62,27 +68,49 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = { ...@@ -62,27 +68,49 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = {
static int ipt_nat_register_lookups(struct net *net) static int ipt_nat_register_lookups(struct net *net)
{ {
struct iptable_nat_pernet *xt_nat_net;
struct nf_hook_ops *ops;
struct xt_table *table;
int i, ret; int i, ret;
xt_nat_net = net_generic(net, iptable_nat_net_id);
table = xt_find_table(net, NFPROTO_IPV4, "nat");
if (WARN_ON_ONCE(!table))
return -ENOENT;
ops = kmemdup(nf_nat_ipv4_ops, sizeof(nf_nat_ipv4_ops), GFP_KERNEL);
if (!ops)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) { for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) {
ret = nf_nat_ipv4_register_fn(net, &nf_nat_ipv4_ops[i]); ops[i].priv = table;
ret = nf_nat_ipv4_register_fn(net, &ops[i]);
if (ret) { if (ret) {
while (i) while (i)
nf_nat_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[--i]); nf_nat_ipv4_unregister_fn(net, &ops[--i]);
kfree(ops);
return ret; return ret;
} }
} }
xt_nat_net->nf_nat_ops = ops;
return 0; return 0;
} }
static void ipt_nat_unregister_lookups(struct net *net) static void ipt_nat_unregister_lookups(struct net *net)
{ {
struct iptable_nat_pernet *xt_nat_net = net_generic(net, iptable_nat_net_id);
struct nf_hook_ops *ops = xt_nat_net->nf_nat_ops;
int i; int i;
if (!ops)
return;
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++)
nf_nat_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[i]); nf_nat_ipv4_unregister_fn(net, &ops[i]);
kfree(ops);
} }
static int __net_init iptable_nat_table_init(struct net *net) static int __net_init iptable_nat_table_init(struct net *net)
...@@ -90,24 +118,19 @@ static int __net_init iptable_nat_table_init(struct net *net) ...@@ -90,24 +118,19 @@ static int __net_init iptable_nat_table_init(struct net *net)
struct ipt_replace *repl; struct ipt_replace *repl;
int ret; int ret;
if (net->ipv4.nat_table)
return 0;
repl = ipt_alloc_initial_table(&nf_nat_ipv4_table); repl = ipt_alloc_initial_table(&nf_nat_ipv4_table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ipt_register_table(net, &nf_nat_ipv4_table, repl,
NULL, &net->ipv4.nat_table); ret = ipt_register_table(net, &nf_nat_ipv4_table, repl, NULL);
if (ret < 0) { if (ret < 0) {
kfree(repl); kfree(repl);
return ret; return ret;
} }
ret = ipt_nat_register_lookups(net); ret = ipt_nat_register_lookups(net);
if (ret < 0) { if (ret < 0)
ipt_unregister_table(net, net->ipv4.nat_table, NULL); ipt_unregister_table_exit(net, "nat");
net->ipv4.nat_table = NULL;
}
kfree(repl); kfree(repl);
return ret; return ret;
...@@ -115,21 +138,19 @@ static int __net_init iptable_nat_table_init(struct net *net) ...@@ -115,21 +138,19 @@ static int __net_init iptable_nat_table_init(struct net *net)
static void __net_exit iptable_nat_net_pre_exit(struct net *net) static void __net_exit iptable_nat_net_pre_exit(struct net *net)
{ {
if (net->ipv4.nat_table) ipt_nat_unregister_lookups(net);
ipt_nat_unregister_lookups(net);
} }
static void __net_exit iptable_nat_net_exit(struct net *net) static void __net_exit iptable_nat_net_exit(struct net *net)
{ {
if (!net->ipv4.nat_table) ipt_unregister_table_exit(net, "nat");
return;
ipt_unregister_table_exit(net, net->ipv4.nat_table);
net->ipv4.nat_table = NULL;
} }
static struct pernet_operations iptable_nat_net_ops = { static struct pernet_operations iptable_nat_net_ops = {
.pre_exit = iptable_nat_net_pre_exit, .pre_exit = iptable_nat_net_pre_exit,
.exit = iptable_nat_net_exit, .exit = iptable_nat_net_exit,
.id = &iptable_nat_net_id,
.size = sizeof(struct iptable_nat_pernet),
}; };
static int __init iptable_nat_init(void) static int __init iptable_nat_init(void)
......
...@@ -41,7 +41,7 @@ static unsigned int ...@@ -41,7 +41,7 @@ static unsigned int
iptable_raw_hook(void *priv, struct sk_buff *skb, iptable_raw_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ipt_do_table(skb, state, state->net->ipv4.iptable_raw); return ipt_do_table(skb, state, priv);
} }
static struct nf_hook_ops *rawtable_ops __read_mostly; static struct nf_hook_ops *rawtable_ops __read_mostly;
...@@ -55,31 +55,22 @@ static int __net_init iptable_raw_table_init(struct net *net) ...@@ -55,31 +55,22 @@ static int __net_init iptable_raw_table_init(struct net *net)
if (raw_before_defrag) if (raw_before_defrag)
table = &packet_raw_before_defrag; table = &packet_raw_before_defrag;
if (net->ipv4.iptable_raw)
return 0;
repl = ipt_alloc_initial_table(table); repl = ipt_alloc_initial_table(table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ipt_register_table(net, table, repl, rawtable_ops, ret = ipt_register_table(net, table, repl, rawtable_ops);
&net->ipv4.iptable_raw);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit iptable_raw_net_pre_exit(struct net *net) static void __net_exit iptable_raw_net_pre_exit(struct net *net)
{ {
if (net->ipv4.iptable_raw) ipt_unregister_table_pre_exit(net, "raw");
ipt_unregister_table_pre_exit(net, net->ipv4.iptable_raw,
rawtable_ops);
} }
static void __net_exit iptable_raw_net_exit(struct net *net) static void __net_exit iptable_raw_net_exit(struct net *net)
{ {
if (!net->ipv4.iptable_raw) ipt_unregister_table_exit(net, "raw");
return;
ipt_unregister_table_exit(net, net->ipv4.iptable_raw);
net->ipv4.iptable_raw = NULL;
} }
static struct pernet_operations iptable_raw_net_ops = { static struct pernet_operations iptable_raw_net_ops = {
......
...@@ -40,7 +40,7 @@ static unsigned int ...@@ -40,7 +40,7 @@ static unsigned int
iptable_security_hook(void *priv, struct sk_buff *skb, iptable_security_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ipt_do_table(skb, state, state->net->ipv4.iptable_security); return ipt_do_table(skb, state, priv);
} }
static struct nf_hook_ops *sectbl_ops __read_mostly; static struct nf_hook_ops *sectbl_ops __read_mostly;
...@@ -50,31 +50,22 @@ static int __net_init iptable_security_table_init(struct net *net) ...@@ -50,31 +50,22 @@ static int __net_init iptable_security_table_init(struct net *net)
struct ipt_replace *repl; struct ipt_replace *repl;
int ret; int ret;
if (net->ipv4.iptable_security)
return 0;
repl = ipt_alloc_initial_table(&security_table); repl = ipt_alloc_initial_table(&security_table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ipt_register_table(net, &security_table, repl, sectbl_ops, ret = ipt_register_table(net, &security_table, repl, sectbl_ops);
&net->ipv4.iptable_security);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit iptable_security_net_pre_exit(struct net *net) static void __net_exit iptable_security_net_pre_exit(struct net *net)
{ {
if (net->ipv4.iptable_security) ipt_unregister_table_pre_exit(net, "security");
ipt_unregister_table_pre_exit(net, net->ipv4.iptable_security,
sectbl_ops);
} }
static void __net_exit iptable_security_net_exit(struct net *net) static void __net_exit iptable_security_net_exit(struct net *net)
{ {
if (!net->ipv4.iptable_security) ipt_unregister_table_exit(net, "security");
return;
ipt_unregister_table_exit(net, net->ipv4.iptable_security);
net->ipv4.iptable_security = NULL;
} }
static struct pernet_operations iptable_security_net_ops = { static struct pernet_operations iptable_security_net_ops = {
......
...@@ -141,14 +141,16 @@ int nf_defrag_ipv4_enable(struct net *net) ...@@ -141,14 +141,16 @@ int nf_defrag_ipv4_enable(struct net *net)
struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id); struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id);
int err = 0; int err = 0;
might_sleep();
if (nf_defrag->users)
return 0;
mutex_lock(&defrag4_mutex); mutex_lock(&defrag4_mutex);
if (nf_defrag->users) if (nf_defrag->users == UINT_MAX) {
err = -EOVERFLOW;
goto out_unlock; goto out_unlock;
}
if (nf_defrag->users) {
nf_defrag->users++;
goto out_unlock;
}
err = nf_register_net_hooks(net, ipv4_defrag_ops, err = nf_register_net_hooks(net, ipv4_defrag_ops,
ARRAY_SIZE(ipv4_defrag_ops)); ARRAY_SIZE(ipv4_defrag_ops));
...@@ -161,6 +163,22 @@ int nf_defrag_ipv4_enable(struct net *net) ...@@ -161,6 +163,22 @@ int nf_defrag_ipv4_enable(struct net *net)
} }
EXPORT_SYMBOL_GPL(nf_defrag_ipv4_enable); 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_init(nf_defrag_init);
module_exit(nf_defrag_fini); module_exit(nf_defrag_fini);
......
...@@ -884,7 +884,7 @@ copy_entries_to_user(unsigned int total_size, ...@@ -884,7 +884,7 @@ copy_entries_to_user(unsigned int total_size,
return ret; return ret;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
static void compat_standard_from_user(void *dst, const void *src) static void compat_standard_from_user(void *dst, const void *src)
{ {
int v = *(compat_int_t *)src; int v = *(compat_int_t *)src;
...@@ -973,7 +973,7 @@ static int get_info(struct net *net, void __user *user, const int *len) ...@@ -973,7 +973,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
return -EFAULT; return -EFAULT;
name[XT_TABLE_MAXNAMELEN-1] = '\0'; name[XT_TABLE_MAXNAMELEN-1] = '\0';
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
xt_compat_lock(AF_INET6); xt_compat_lock(AF_INET6);
#endif #endif
...@@ -981,7 +981,7 @@ static int get_info(struct net *net, void __user *user, const int *len) ...@@ -981,7 +981,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
if (!IS_ERR(t)) { if (!IS_ERR(t)) {
struct ip6t_getinfo info; struct ip6t_getinfo info;
const struct xt_table_info *private = t->private; const struct xt_table_info *private = t->private;
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct xt_table_info tmp; struct xt_table_info tmp;
if (in_compat_syscall()) { if (in_compat_syscall()) {
...@@ -1009,7 +1009,7 @@ static int get_info(struct net *net, void __user *user, const int *len) ...@@ -1009,7 +1009,7 @@ static int get_info(struct net *net, void __user *user, const int *len)
module_put(t->me); module_put(t->me);
} else } else
ret = PTR_ERR(t); ret = PTR_ERR(t);
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
xt_compat_unlock(AF_INET6); xt_compat_unlock(AF_INET6);
#endif #endif
...@@ -1215,7 +1215,7 @@ do_add_counters(struct net *net, sockptr_t arg, unsigned int len) ...@@ -1215,7 +1215,7 @@ do_add_counters(struct net *net, sockptr_t arg, unsigned int len)
return ret; return ret;
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
struct compat_ip6t_replace { struct compat_ip6t_replace {
char name[XT_TABLE_MAXNAMELEN]; char name[XT_TABLE_MAXNAMELEN];
u32 valid_hooks; u32 valid_hooks;
...@@ -1630,7 +1630,7 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, sockptr_t arg, unsigned int len) ...@@ -1630,7 +1630,7 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, sockptr_t arg, unsigned int len)
switch (cmd) { switch (cmd) {
case IP6T_SO_SET_REPLACE: case IP6T_SO_SET_REPLACE:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_do_replace(sock_net(sk), arg, len); ret = compat_do_replace(sock_net(sk), arg, len);
else else
...@@ -1663,7 +1663,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) ...@@ -1663,7 +1663,7 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
break; break;
case IP6T_SO_GET_ENTRIES: case IP6T_SO_GET_ENTRIES:
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
if (in_compat_syscall()) if (in_compat_syscall())
ret = compat_get_entries(sock_net(sk), user, len); ret = compat_get_entries(sock_net(sk), user, len);
else else
...@@ -1725,10 +1725,11 @@ static void __ip6t_unregister_table(struct net *net, struct xt_table *table) ...@@ -1725,10 +1725,11 @@ static void __ip6t_unregister_table(struct net *net, struct xt_table *table)
int ip6t_register_table(struct net *net, const struct xt_table *table, int ip6t_register_table(struct net *net, const struct xt_table *table,
const struct ip6t_replace *repl, const struct ip6t_replace *repl,
const struct nf_hook_ops *ops, const struct nf_hook_ops *template_ops)
struct xt_table **res)
{ {
int ret; struct nf_hook_ops *ops;
unsigned int num_ops;
int ret, i;
struct xt_table_info *newinfo; struct xt_table_info *newinfo;
struct xt_table_info bootstrap = {0}; struct xt_table_info bootstrap = {0};
void *loc_cpu_entry; void *loc_cpu_entry;
...@@ -1742,50 +1743,62 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, ...@@ -1742,50 +1743,62 @@ int ip6t_register_table(struct net *net, const struct xt_table *table,
memcpy(loc_cpu_entry, repl->entries, repl->size); memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(net, newinfo, loc_cpu_entry, repl); ret = translate_table(net, newinfo, loc_cpu_entry, repl);
if (ret != 0) if (ret != 0) {
goto out_free; xt_free_table_info(newinfo);
return ret;
}
new_table = xt_register_table(net, table, &bootstrap, newinfo); new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) { if (IS_ERR(new_table)) {
ret = PTR_ERR(new_table); xt_free_table_info(newinfo);
goto out_free; return PTR_ERR(new_table);
} }
/* set res now, will see skbs right after nf_register_net_hooks */ if (!template_ops)
WRITE_ONCE(*res, new_table);
if (!ops)
return 0; return 0;
ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks)); num_ops = hweight32(table->valid_hooks);
if (ret != 0) { if (num_ops == 0) {
__ip6t_unregister_table(net, new_table); ret = -EINVAL;
*res = NULL; goto out_free;
} }
ops = kmemdup(template_ops, sizeof(*ops) * num_ops, GFP_KERNEL);
if (!ops) {
ret = -ENOMEM;
goto out_free;
}
for (i = 0; i < num_ops; i++)
ops[i].priv = new_table;
new_table->ops = ops;
ret = nf_register_net_hooks(net, ops, num_ops);
if (ret != 0)
goto out_free;
return ret; return ret;
out_free: out_free:
xt_free_table_info(newinfo); __ip6t_unregister_table(net, new_table);
return ret; return ret;
} }
void ip6t_unregister_table_pre_exit(struct net *net, struct xt_table *table, void ip6t_unregister_table_pre_exit(struct net *net, const char *name)
const struct nf_hook_ops *ops)
{ {
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name);
}
void ip6t_unregister_table_exit(struct net *net, struct xt_table *table) if (table)
{ nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
__ip6t_unregister_table(net, table);
} }
void ip6t_unregister_table(struct net *net, struct xt_table *table, void ip6t_unregister_table_exit(struct net *net, const char *name)
const struct nf_hook_ops *ops)
{ {
if (ops) struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name);
ip6t_unregister_table_pre_exit(net, table, ops);
__ip6t_unregister_table(net, table); if (table)
__ip6t_unregister_table(net, table);
} }
/* Returns 1 if the type and code is matched by the range, 0 otherwise */ /* Returns 1 if the type and code is matched by the range, 0 otherwise */
...@@ -1840,7 +1853,7 @@ static struct xt_target ip6t_builtin_tg[] __read_mostly = { ...@@ -1840,7 +1853,7 @@ static struct xt_target ip6t_builtin_tg[] __read_mostly = {
.name = XT_STANDARD_TARGET, .name = XT_STANDARD_TARGET,
.targetsize = sizeof(int), .targetsize = sizeof(int),
.family = NFPROTO_IPV6, .family = NFPROTO_IPV6,
#ifdef CONFIG_COMPAT #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
.compatsize = sizeof(compat_int_t), .compatsize = sizeof(compat_int_t),
.compat_from_user = compat_standard_from_user, .compat_from_user = compat_standard_from_user,
.compat_to_user = compat_standard_to_user, .compat_to_user = compat_standard_to_user,
...@@ -1935,7 +1948,6 @@ static void __exit ip6_tables_fini(void) ...@@ -1935,7 +1948,6 @@ static void __exit ip6_tables_fini(void)
} }
EXPORT_SYMBOL(ip6t_register_table); EXPORT_SYMBOL(ip6t_register_table);
EXPORT_SYMBOL(ip6t_unregister_table);
EXPORT_SYMBOL(ip6t_unregister_table_pre_exit); EXPORT_SYMBOL(ip6t_unregister_table_pre_exit);
EXPORT_SYMBOL(ip6t_unregister_table_exit); EXPORT_SYMBOL(ip6t_unregister_table_exit);
EXPORT_SYMBOL(ip6t_do_table); EXPORT_SYMBOL(ip6t_do_table);
......
...@@ -35,7 +35,7 @@ static unsigned int ...@@ -35,7 +35,7 @@ static unsigned int
ip6table_filter_hook(void *priv, struct sk_buff *skb, ip6table_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_filter); return ip6t_do_table(skb, state, priv);
} }
static struct nf_hook_ops *filter_ops __read_mostly; static struct nf_hook_ops *filter_ops __read_mostly;
...@@ -49,9 +49,6 @@ static int __net_init ip6table_filter_table_init(struct net *net) ...@@ -49,9 +49,6 @@ static int __net_init ip6table_filter_table_init(struct net *net)
struct ip6t_replace *repl; struct ip6t_replace *repl;
int err; int err;
if (net->ipv6.ip6table_filter)
return 0;
repl = ip6t_alloc_initial_table(&packet_filter); repl = ip6t_alloc_initial_table(&packet_filter);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -59,8 +56,7 @@ static int __net_init ip6table_filter_table_init(struct net *net) ...@@ -59,8 +56,7 @@ static int __net_init ip6table_filter_table_init(struct net *net)
((struct ip6t_standard *)repl->entries)[1].target.verdict = ((struct ip6t_standard *)repl->entries)[1].target.verdict =
forward ? -NF_ACCEPT - 1 : -NF_DROP - 1; forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
err = ip6t_register_table(net, &packet_filter, repl, filter_ops, err = ip6t_register_table(net, &packet_filter, repl, filter_ops);
&net->ipv6.ip6table_filter);
kfree(repl); kfree(repl);
return err; return err;
} }
...@@ -75,17 +71,12 @@ static int __net_init ip6table_filter_net_init(struct net *net) ...@@ -75,17 +71,12 @@ static int __net_init ip6table_filter_net_init(struct net *net)
static void __net_exit ip6table_filter_net_pre_exit(struct net *net) static void __net_exit ip6table_filter_net_pre_exit(struct net *net)
{ {
if (net->ipv6.ip6table_filter) ip6t_unregister_table_pre_exit(net, "filter");
ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_filter,
filter_ops);
} }
static void __net_exit ip6table_filter_net_exit(struct net *net) static void __net_exit ip6table_filter_net_exit(struct net *net)
{ {
if (!net->ipv6.ip6table_filter) ip6t_unregister_table_exit(net, "filter");
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_filter);
net->ipv6.ip6table_filter = NULL;
} }
static struct pernet_operations ip6table_filter_net_ops = { static struct pernet_operations ip6table_filter_net_ops = {
......
...@@ -32,7 +32,7 @@ static const struct xt_table packet_mangler = { ...@@ -32,7 +32,7 @@ static const struct xt_table packet_mangler = {
}; };
static unsigned int static unsigned int
ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state, void *priv)
{ {
unsigned int ret; unsigned int ret;
struct in6_addr saddr, daddr; struct in6_addr saddr, daddr;
...@@ -49,7 +49,7 @@ ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) ...@@ -49,7 +49,7 @@ ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
/* flowlabel and prio (includes version, which shouldn't change either */ /* flowlabel and prio (includes version, which shouldn't change either */
flowlabel = *((u_int32_t *)ipv6_hdr(skb)); flowlabel = *((u_int32_t *)ipv6_hdr(skb));
ret = ip6t_do_table(skb, state, state->net->ipv6.ip6table_mangle); ret = ip6t_do_table(skb, state, priv);
if (ret != NF_DROP && ret != NF_STOLEN && if (ret != NF_DROP && ret != NF_STOLEN &&
(!ipv6_addr_equal(&ipv6_hdr(skb)->saddr, &saddr) || (!ipv6_addr_equal(&ipv6_hdr(skb)->saddr, &saddr) ||
...@@ -71,8 +71,8 @@ ip6table_mangle_hook(void *priv, struct sk_buff *skb, ...@@ -71,8 +71,8 @@ ip6table_mangle_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
if (state->hook == NF_INET_LOCAL_OUT) if (state->hook == NF_INET_LOCAL_OUT)
return ip6t_mangle_out(skb, state); return ip6t_mangle_out(skb, state, priv);
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_mangle); return ip6t_do_table(skb, state, priv);
} }
static struct nf_hook_ops *mangle_ops __read_mostly; static struct nf_hook_ops *mangle_ops __read_mostly;
...@@ -81,32 +81,22 @@ static int __net_init ip6table_mangle_table_init(struct net *net) ...@@ -81,32 +81,22 @@ static int __net_init ip6table_mangle_table_init(struct net *net)
struct ip6t_replace *repl; struct ip6t_replace *repl;
int ret; int ret;
if (net->ipv6.ip6table_mangle)
return 0;
repl = ip6t_alloc_initial_table(&packet_mangler); repl = ip6t_alloc_initial_table(&packet_mangler);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops, ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops);
&net->ipv6.ip6table_mangle);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit ip6table_mangle_net_pre_exit(struct net *net) static void __net_exit ip6table_mangle_net_pre_exit(struct net *net)
{ {
if (net->ipv6.ip6table_mangle) ip6t_unregister_table_pre_exit(net, "mangle");
ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_mangle,
mangle_ops);
} }
static void __net_exit ip6table_mangle_net_exit(struct net *net) static void __net_exit ip6table_mangle_net_exit(struct net *net)
{ {
if (!net->ipv6.ip6table_mangle) ip6t_unregister_table_exit(net, "mangle");
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_mangle);
net->ipv6.ip6table_mangle = NULL;
} }
static struct pernet_operations ip6table_mangle_net_ops = { static struct pernet_operations ip6table_mangle_net_ops = {
......
...@@ -15,8 +15,14 @@ ...@@ -15,8 +15,14 @@
#include <net/netfilter/nf_nat.h> #include <net/netfilter/nf_nat.h>
struct ip6table_nat_pernet {
struct nf_hook_ops *nf_nat_ops;
};
static int __net_init ip6table_nat_table_init(struct net *net); static int __net_init ip6table_nat_table_init(struct net *net);
static unsigned int ip6table_nat_net_id __read_mostly;
static const struct xt_table nf_nat_ipv6_table = { static const struct xt_table nf_nat_ipv6_table = {
.name = "nat", .name = "nat",
.valid_hooks = (1 << NF_INET_PRE_ROUTING) | .valid_hooks = (1 << NF_INET_PRE_ROUTING) |
...@@ -32,7 +38,7 @@ static unsigned int ip6table_nat_do_chain(void *priv, ...@@ -32,7 +38,7 @@ static unsigned int ip6table_nat_do_chain(void *priv,
struct sk_buff *skb, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_nat); return ip6t_do_table(skb, state, priv);
} }
static const struct nf_hook_ops nf_nat_ipv6_ops[] = { static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
...@@ -64,27 +70,49 @@ static const struct nf_hook_ops nf_nat_ipv6_ops[] = { ...@@ -64,27 +70,49 @@ static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
static int ip6t_nat_register_lookups(struct net *net) static int ip6t_nat_register_lookups(struct net *net)
{ {
struct ip6table_nat_pernet *xt_nat_net;
struct nf_hook_ops *ops;
struct xt_table *table;
int i, ret; int i, ret;
table = xt_find_table(net, NFPROTO_IPV6, "nat");
if (WARN_ON_ONCE(!table))
return -ENOENT;
xt_nat_net = net_generic(net, ip6table_nat_net_id);
ops = kmemdup(nf_nat_ipv6_ops, sizeof(nf_nat_ipv6_ops), GFP_KERNEL);
if (!ops)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++) { for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++) {
ret = nf_nat_ipv6_register_fn(net, &nf_nat_ipv6_ops[i]); ops[i].priv = table;
ret = nf_nat_ipv6_register_fn(net, &ops[i]);
if (ret) { if (ret) {
while (i) while (i)
nf_nat_ipv6_unregister_fn(net, &nf_nat_ipv6_ops[--i]); nf_nat_ipv6_unregister_fn(net, &ops[--i]);
kfree(ops);
return ret; return ret;
} }
} }
xt_nat_net->nf_nat_ops = ops;
return 0; return 0;
} }
static void ip6t_nat_unregister_lookups(struct net *net) static void ip6t_nat_unregister_lookups(struct net *net)
{ {
struct ip6table_nat_pernet *xt_nat_net = net_generic(net, ip6table_nat_net_id);
struct nf_hook_ops *ops = xt_nat_net->nf_nat_ops;
int i; int i;
if (!ops)
return;
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++) for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++)
nf_nat_ipv6_unregister_fn(net, &nf_nat_ipv6_ops[i]); nf_nat_ipv6_unregister_fn(net, &ops[i]);
kfree(ops);
} }
static int __net_init ip6table_nat_table_init(struct net *net) static int __net_init ip6table_nat_table_init(struct net *net)
...@@ -92,45 +120,39 @@ static int __net_init ip6table_nat_table_init(struct net *net) ...@@ -92,45 +120,39 @@ static int __net_init ip6table_nat_table_init(struct net *net)
struct ip6t_replace *repl; struct ip6t_replace *repl;
int ret; int ret;
if (net->ipv6.ip6table_nat)
return 0;
repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table); repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl, ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl,
NULL, &net->ipv6.ip6table_nat); NULL);
if (ret < 0) { if (ret < 0) {
kfree(repl); kfree(repl);
return ret; return ret;
} }
ret = ip6t_nat_register_lookups(net); ret = ip6t_nat_register_lookups(net);
if (ret < 0) { if (ret < 0)
ip6t_unregister_table(net, net->ipv6.ip6table_nat, NULL); ip6t_unregister_table_exit(net, "nat");
net->ipv6.ip6table_nat = NULL;
}
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit ip6table_nat_net_pre_exit(struct net *net) static void __net_exit ip6table_nat_net_pre_exit(struct net *net)
{ {
if (net->ipv6.ip6table_nat) ip6t_nat_unregister_lookups(net);
ip6t_nat_unregister_lookups(net);
} }
static void __net_exit ip6table_nat_net_exit(struct net *net) static void __net_exit ip6table_nat_net_exit(struct net *net)
{ {
if (!net->ipv6.ip6table_nat) ip6t_unregister_table_exit(net, "nat");
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_nat);
net->ipv6.ip6table_nat = NULL;
} }
static struct pernet_operations ip6table_nat_net_ops = { static struct pernet_operations ip6table_nat_net_ops = {
.pre_exit = ip6table_nat_net_pre_exit, .pre_exit = ip6table_nat_net_pre_exit,
.exit = ip6table_nat_net_exit, .exit = ip6table_nat_net_exit,
.id = &ip6table_nat_net_id,
.size = sizeof(struct ip6table_nat_pernet),
}; };
static int __init ip6table_nat_init(void) static int __init ip6table_nat_init(void)
......
...@@ -40,7 +40,7 @@ static unsigned int ...@@ -40,7 +40,7 @@ static unsigned int
ip6table_raw_hook(void *priv, struct sk_buff *skb, ip6table_raw_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_raw); return ip6t_do_table(skb, state, priv);
} }
static struct nf_hook_ops *rawtable_ops __read_mostly; static struct nf_hook_ops *rawtable_ops __read_mostly;
...@@ -54,31 +54,22 @@ static int __net_init ip6table_raw_table_init(struct net *net) ...@@ -54,31 +54,22 @@ static int __net_init ip6table_raw_table_init(struct net *net)
if (raw_before_defrag) if (raw_before_defrag)
table = &packet_raw_before_defrag; table = &packet_raw_before_defrag;
if (net->ipv6.ip6table_raw)
return 0;
repl = ip6t_alloc_initial_table(table); repl = ip6t_alloc_initial_table(table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ip6t_register_table(net, table, repl, rawtable_ops, ret = ip6t_register_table(net, table, repl, rawtable_ops);
&net->ipv6.ip6table_raw);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit ip6table_raw_net_pre_exit(struct net *net) static void __net_exit ip6table_raw_net_pre_exit(struct net *net)
{ {
if (net->ipv6.ip6table_raw) ip6t_unregister_table_pre_exit(net, "raw");
ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_raw,
rawtable_ops);
} }
static void __net_exit ip6table_raw_net_exit(struct net *net) static void __net_exit ip6table_raw_net_exit(struct net *net)
{ {
if (!net->ipv6.ip6table_raw) ip6t_unregister_table_exit(net, "raw");
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_raw);
net->ipv6.ip6table_raw = NULL;
} }
static struct pernet_operations ip6table_raw_net_ops = { static struct pernet_operations ip6table_raw_net_ops = {
......
...@@ -39,7 +39,7 @@ static unsigned int ...@@ -39,7 +39,7 @@ static unsigned int
ip6table_security_hook(void *priv, struct sk_buff *skb, ip6table_security_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_security); return ip6t_do_table(skb, state, priv);
} }
static struct nf_hook_ops *sectbl_ops __read_mostly; static struct nf_hook_ops *sectbl_ops __read_mostly;
...@@ -49,31 +49,22 @@ static int __net_init ip6table_security_table_init(struct net *net) ...@@ -49,31 +49,22 @@ static int __net_init ip6table_security_table_init(struct net *net)
struct ip6t_replace *repl; struct ip6t_replace *repl;
int ret; int ret;
if (net->ipv6.ip6table_security)
return 0;
repl = ip6t_alloc_initial_table(&security_table); repl = ip6t_alloc_initial_table(&security_table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ip6t_register_table(net, &security_table, repl, sectbl_ops, ret = ip6t_register_table(net, &security_table, repl, sectbl_ops);
&net->ipv6.ip6table_security);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit ip6table_security_net_pre_exit(struct net *net) static void __net_exit ip6table_security_net_pre_exit(struct net *net)
{ {
if (net->ipv6.ip6table_security) ip6t_unregister_table_pre_exit(net, "security");
ip6t_unregister_table_pre_exit(net, net->ipv6.ip6table_security,
sectbl_ops);
} }
static void __net_exit ip6table_security_net_exit(struct net *net) static void __net_exit ip6table_security_net_exit(struct net *net)
{ {
if (!net->ipv6.ip6table_security) ip6t_unregister_table_exit(net, "security");
return;
ip6t_unregister_table_exit(net, net->ipv6.ip6table_security);
net->ipv6.ip6table_security = NULL;
} }
static struct pernet_operations ip6table_security_net_ops = { static struct pernet_operations ip6table_security_net_ops = {
......
...@@ -137,14 +137,16 @@ int nf_defrag_ipv6_enable(struct net *net) ...@@ -137,14 +137,16 @@ int nf_defrag_ipv6_enable(struct net *net)
struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id); struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id);
int err = 0; int err = 0;
might_sleep();
if (nf_frag->users)
return 0;
mutex_lock(&defrag6_mutex); 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; goto out_unlock;
}
err = nf_register_net_hooks(net, ipv6_defrag_ops, err = nf_register_net_hooks(net, ipv6_defrag_ops,
ARRAY_SIZE(ipv6_defrag_ops)); ARRAY_SIZE(ipv6_defrag_ops));
...@@ -157,6 +159,21 @@ int nf_defrag_ipv6_enable(struct net *net) ...@@ -157,6 +159,21 @@ int nf_defrag_ipv6_enable(struct net *net)
} }
EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable); 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_init(nf_defrag_init);
module_exit(nf_defrag_fini); module_exit(nf_defrag_fini);
......
...@@ -728,6 +728,16 @@ config NETFILTER_XTABLES ...@@ -728,6 +728,16 @@ config NETFILTER_XTABLES
if NETFILTER_XTABLES if NETFILTER_XTABLES
config NETFILTER_XTABLES_COMPAT
bool "Netfilter Xtables 32bit support"
depends on COMPAT
default y
help
This option provides a translation layer to run 32bit arp,ip(6),ebtables
binaries on 64bit kernels.
If unsure, say N.
comment "Xtables combined modules" comment "Xtables combined modules"
config NETFILTER_XT_MARK config NETFILTER_XT_MARK
......
This diff is collapsed.
This diff is collapsed.
...@@ -536,15 +536,19 @@ static void nf_ct_netns_do_put(struct net *net, u8 nfproto) ...@@ -536,15 +536,19 @@ static void nf_ct_netns_do_put(struct net *net, u8 nfproto)
mutex_lock(&nf_ct_proto_mutex); mutex_lock(&nf_ct_proto_mutex);
switch (nfproto) { switch (nfproto) {
case NFPROTO_IPV4: case NFPROTO_IPV4:
if (cnet->users4 && (--cnet->users4 == 0)) if (cnet->users4 && (--cnet->users4 == 0)) {
nf_unregister_net_hooks(net, ipv4_conntrack_ops, nf_unregister_net_hooks(net, ipv4_conntrack_ops,
ARRAY_SIZE(ipv4_conntrack_ops)); ARRAY_SIZE(ipv4_conntrack_ops));
nf_defrag_ipv4_disable(net);
}
break; break;
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
case NFPROTO_IPV6: case NFPROTO_IPV6:
if (cnet->users6 && (--cnet->users6 == 0)) if (cnet->users6 && (--cnet->users6 == 0)) {
nf_unregister_net_hooks(net, ipv6_conntrack_ops, nf_unregister_net_hooks(net, ipv6_conntrack_ops,
ARRAY_SIZE(ipv6_conntrack_ops)); ARRAY_SIZE(ipv6_conntrack_ops));
nf_defrag_ipv6_disable(net);
}
break; break;
#endif #endif
case NFPROTO_BRIDGE: case NFPROTO_BRIDGE:
......
...@@ -1011,6 +1011,7 @@ static void __net_exit nf_log_syslog_net_exit(struct net *net) ...@@ -1011,6 +1011,7 @@ static void __net_exit nf_log_syslog_net_exit(struct net *net)
nf_log_unset(net, &nf_arp_logger); nf_log_unset(net, &nf_arp_logger);
nf_log_unset(net, &nf_ip6_logger); nf_log_unset(net, &nf_ip6_logger);
nf_log_unset(net, &nf_netdev_logger); nf_log_unset(net, &nf_netdev_logger);
nf_log_unset(net, &nf_bridge_logger);
} }
static struct pernet_operations nf_log_syslog_net_ops = { static struct pernet_operations nf_log_syslog_net_ops = {
......
...@@ -146,43 +146,6 @@ static void __nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl) ...@@ -146,43 +146,6 @@ static void __nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl)
return; return;
} }
} }
int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
{
struct flowi fl;
unsigned int hh_len;
struct dst_entry *dst;
struct sock *sk = skb->sk;
int err;
err = xfrm_decode_session(skb, &fl, family);
if (err < 0)
return err;
dst = skb_dst(skb);
if (dst->xfrm)
dst = ((struct xfrm_dst *)dst)->route;
if (!dst_hold_safe(dst))
return -EHOSTUNREACH;
if (sk && !net_eq(net, sock_net(sk)))
sk = NULL;
dst = xfrm_lookup(net, dst, &fl, sk, 0);
if (IS_ERR(dst))
return PTR_ERR(dst);
skb_dst_drop(skb);
skb_dst_set(skb, dst);
/* Change in oif may mean change in hh_len. */
hh_len = skb_dst(skb)->dev->hard_header_len;
if (skb_headroom(skb) < hh_len &&
pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
return -ENOMEM;
return 0;
}
EXPORT_SYMBOL(nf_xfrm_me_harder);
#endif /* CONFIG_XFRM */ #endif /* CONFIG_XFRM */
/* We keep an extra hash for each conntrack, for fast searching. */ /* We keep an extra hash for each conntrack, for fast searching. */
......
...@@ -659,6 +659,44 @@ nf_nat_ipv4_pre_routing(void *priv, struct sk_buff *skb, ...@@ -659,6 +659,44 @@ nf_nat_ipv4_pre_routing(void *priv, struct sk_buff *skb,
return ret; return ret;
} }
#ifdef CONFIG_XFRM
static int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
{
struct sock *sk = skb->sk;
struct dst_entry *dst;
unsigned int hh_len;
struct flowi fl;
int err;
err = xfrm_decode_session(skb, &fl, family);
if (err < 0)
return err;
dst = skb_dst(skb);
if (dst->xfrm)
dst = ((struct xfrm_dst *)dst)->route;
if (!dst_hold_safe(dst))
return -EHOSTUNREACH;
if (sk && !net_eq(net, sock_net(sk)))
sk = NULL;
dst = xfrm_lookup(net, dst, &fl, sk, 0);
if (IS_ERR(dst))
return PTR_ERR(dst);
skb_dst_drop(skb);
skb_dst_set(skb, dst);
/* Change in oif may mean change in hh_len. */
hh_len = skb_dst(skb)->dev->hard_header_len;
if (skb_headroom(skb) < hh_len &&
pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
return -ENOMEM;
return 0;
}
#endif
static unsigned int static unsigned int
nf_nat_ipv4_local_in(void *priv, struct sk_buff *skb, nf_nat_ipv4_local_in(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
......
This diff is collapsed.
...@@ -7,8 +7,6 @@ ...@@ -7,8 +7,6 @@
#include <net/netfilter/nf_tables_offload.h> #include <net/netfilter/nf_tables_offload.h>
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
extern unsigned int nf_tables_net_id;
static struct nft_flow_rule *nft_flow_rule_alloc(int num_actions) static struct nft_flow_rule *nft_flow_rule_alloc(int num_actions)
{ {
struct nft_flow_rule *flow; struct nft_flow_rule *flow;
...@@ -389,7 +387,7 @@ static void nft_indr_block_cleanup(struct flow_block_cb *block_cb) ...@@ -389,7 +387,7 @@ static void nft_indr_block_cleanup(struct flow_block_cb *block_cb)
nft_flow_block_offload_init(&bo, dev_net(dev), FLOW_BLOCK_UNBIND, nft_flow_block_offload_init(&bo, dev_net(dev), FLOW_BLOCK_UNBIND,
basechain, &extack); basechain, &extack);
nft_net = net_generic(net, nf_tables_net_id); nft_net = nft_pernet(net);
mutex_lock(&nft_net->commit_mutex); mutex_lock(&nft_net->commit_mutex);
list_del(&block_cb->driver_list); list_del(&block_cb->driver_list);
list_move(&block_cb->list, &bo.cb_list); list_move(&block_cb->list, &bo.cb_list);
...@@ -490,7 +488,7 @@ static int nft_flow_offload_chain(struct nft_chain *chain, u8 *ppolicy, ...@@ -490,7 +488,7 @@ static int nft_flow_offload_chain(struct nft_chain *chain, u8 *ppolicy,
static void nft_flow_rule_offload_abort(struct net *net, static void nft_flow_rule_offload_abort(struct net *net,
struct nft_trans *trans) struct nft_trans *trans)
{ {
struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); struct nftables_pernet *nft_net = nft_pernet(net);
int err = 0; int err = 0;
list_for_each_entry_continue_reverse(trans, &nft_net->commit_list, list) { list_for_each_entry_continue_reverse(trans, &nft_net->commit_list, list) {
...@@ -539,7 +537,7 @@ static void nft_flow_rule_offload_abort(struct net *net, ...@@ -539,7 +537,7 @@ static void nft_flow_rule_offload_abort(struct net *net,
int nft_flow_rule_offload_commit(struct net *net) int nft_flow_rule_offload_commit(struct net *net)
{ {
struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); struct nftables_pernet *nft_net = nft_pernet(net);
struct nft_trans *trans; struct nft_trans *trans;
int err = 0; int err = 0;
u8 policy; u8 policy;
...@@ -663,7 +661,7 @@ static int nft_offload_netdev_event(struct notifier_block *this, ...@@ -663,7 +661,7 @@ static int nft_offload_netdev_event(struct notifier_block *this,
if (event != NETDEV_UNREGISTER) if (event != NETDEV_UNREGISTER)
return NOTIFY_DONE; return NOTIFY_DONE;
nft_net = net_generic(net, nf_tables_net_id); nft_net = nft_pernet(net);
mutex_lock(&nft_net->commit_mutex); mutex_lock(&nft_net->commit_mutex);
chain = __nft_offload_get_chain(nft_net, dev); chain = __nft_offload_get_chain(nft_net, dev);
if (chain) if (chain)
......
...@@ -252,6 +252,12 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -252,6 +252,12 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr *attr = (void *)nlh + min_len; struct nlattr *attr = (void *)nlh + min_len;
int attrlen = nlh->nlmsg_len - min_len; int attrlen = nlh->nlmsg_len - min_len;
__u8 subsys_id = NFNL_SUBSYS_ID(type); __u8 subsys_id = NFNL_SUBSYS_ID(type);
struct nfnl_info info = {
.net = net,
.sk = nfnlnet->nfnl,
.nlh = nlh,
.extack = extack,
};
/* Sanity-check NFNL_MAX_ATTR_COUNT */ /* Sanity-check NFNL_MAX_ATTR_COUNT */
if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) { if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
...@@ -267,24 +273,30 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -267,24 +273,30 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
return err; return err;
} }
if (nc->call_rcu) { if (!nc->call) {
err = nc->call_rcu(net, nfnlnet->nfnl, skb, nlh,
(const struct nlattr **)cda,
extack);
rcu_read_unlock(); rcu_read_unlock();
} else { return -EINVAL;
}
switch (nc->type) {
case NFNL_CB_RCU:
err = nc->call(skb, &info, (const struct nlattr **)cda);
rcu_read_unlock();
break;
case NFNL_CB_MUTEX:
rcu_read_unlock(); rcu_read_unlock();
nfnl_lock(subsys_id); nfnl_lock(subsys_id);
if (nfnl_dereference_protected(subsys_id) != ss || if (nfnl_dereference_protected(subsys_id) != ss ||
nfnetlink_find_client(type, ss) != nc) nfnetlink_find_client(type, ss) != nc) {
err = -EAGAIN; err = -EAGAIN;
else if (nc->call) break;
err = nc->call(net, nfnlnet->nfnl, skb, nlh, }
(const struct nlattr **)cda, err = nc->call(skb, &info, (const struct nlattr **)cda);
extack);
else
err = -EINVAL;
nfnl_unlock(subsys_id); nfnl_unlock(subsys_id);
break;
default:
err = -EINVAL;
break;
} }
if (err == -EAGAIN) if (err == -EAGAIN)
goto replay; goto replay;
...@@ -462,12 +474,24 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -462,12 +474,24 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
goto ack; goto ack;
} }
if (nc->type != NFNL_CB_BATCH) {
err = -EINVAL;
goto ack;
}
{ {
int min_len = nlmsg_total_size(sizeof(struct nfgenmsg)); int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type); struct nfnl_net *nfnlnet = nfnl_pernet(net);
struct nlattr *cda[NFNL_MAX_ATTR_COUNT + 1]; struct nlattr *cda[NFNL_MAX_ATTR_COUNT + 1];
struct nlattr *attr = (void *)nlh + min_len; struct nlattr *attr = (void *)nlh + min_len;
u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
int attrlen = nlh->nlmsg_len - min_len; int attrlen = nlh->nlmsg_len - min_len;
struct nfnl_info info = {
.net = net,
.sk = nfnlnet->nfnl,
.nlh = nlh,
.extack = &extack,
};
/* Sanity-check NFTA_MAX_ATTR */ /* Sanity-check NFTA_MAX_ATTR */
if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) { if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
...@@ -482,13 +506,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -482,13 +506,7 @@ static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
if (err < 0) if (err < 0)
goto ack; goto ack;
if (nc->call_batch) { err = nc->call(skb, &info, (const struct nlattr **)cda);
struct nfnl_net *nfnlnet = nfnl_pernet(net);
err = nc->call_batch(net, nfnlnet->nfnl, skb, nlh,
(const struct nlattr **)cda,
&extack);
}
/* The lock was released to autoload some module, we /* The lock was released to autoload some module, we
* have to abort and start from scratch using the * have to abort and start from scratch using the
......
...@@ -56,15 +56,13 @@ static inline struct nfnl_acct_net *nfnl_acct_pernet(struct net *net) ...@@ -56,15 +56,13 @@ static inline struct nfnl_acct_net *nfnl_acct_pernet(struct net *net)
#define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES) #define NFACCT_F_QUOTA (NFACCT_F_QUOTA_PKTS | NFACCT_F_QUOTA_BYTES)
#define NFACCT_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */ #define NFACCT_OVERQUOTA_BIT 2 /* NFACCT_F_OVERQUOTA */
static int nfnl_acct_new(struct net *net, struct sock *nfnl, static int nfnl_acct_new(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const tb[])
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net); struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(info->net);
struct nf_acct *nfacct, *matching = NULL; struct nf_acct *nfacct, *matching = NULL;
char *acct_name;
unsigned int size = 0; unsigned int size = 0;
char *acct_name;
u32 flags = 0; u32 flags = 0;
if (!tb[NFACCT_NAME]) if (!tb[NFACCT_NAME])
...@@ -78,7 +76,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl, ...@@ -78,7 +76,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl,
if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0) if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0)
continue; continue;
if (nlh->nlmsg_flags & NLM_F_EXCL) if (info->nlh->nlmsg_flags & NLM_F_EXCL)
return -EEXIST; return -EEXIST;
matching = nfacct; matching = nfacct;
...@@ -86,7 +84,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl, ...@@ -86,7 +84,7 @@ static int nfnl_acct_new(struct net *net, struct sock *nfnl,
} }
if (matching) { if (matching) {
if (nlh->nlmsg_flags & NLM_F_REPLACE) { if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
/* reset counters if you request a replacement. */ /* reset counters if you request a replacement. */
atomic64_set(&matching->pkts, 0); atomic64_set(&matching->pkts, 0);
atomic64_set(&matching->bytes, 0); atomic64_set(&matching->bytes, 0);
...@@ -273,17 +271,15 @@ static int nfnl_acct_start(struct netlink_callback *cb) ...@@ -273,17 +271,15 @@ static int nfnl_acct_start(struct netlink_callback *cb)
return 0; return 0;
} }
static int nfnl_acct_get(struct net *net, struct sock *nfnl, static int nfnl_acct_get(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const tb[])
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net); struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(info->net);
int ret = -ENOENT; int ret = -ENOENT;
struct nf_acct *cur; struct nf_acct *cur;
char *acct_name; char *acct_name;
if (nlh->nlmsg_flags & NLM_F_DUMP) { if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
struct netlink_dump_control c = { struct netlink_dump_control c = {
.dump = nfnl_acct_dump, .dump = nfnl_acct_dump,
.start = nfnl_acct_start, .start = nfnl_acct_start,
...@@ -291,7 +287,7 @@ static int nfnl_acct_get(struct net *net, struct sock *nfnl, ...@@ -291,7 +287,7 @@ static int nfnl_acct_get(struct net *net, struct sock *nfnl,
.data = (void *)tb[NFACCT_FILTER], .data = (void *)tb[NFACCT_FILTER],
}; };
return netlink_dump_start(nfnl, skb, nlh, &c); return netlink_dump_start(info->sk, skb, info->nlh, &c);
} }
if (!tb[NFACCT_NAME]) if (!tb[NFACCT_NAME])
...@@ -311,15 +307,15 @@ static int nfnl_acct_get(struct net *net, struct sock *nfnl, ...@@ -311,15 +307,15 @@ static int nfnl_acct_get(struct net *net, struct sock *nfnl,
} }
ret = nfnl_acct_fill_info(skb2, NETLINK_CB(skb).portid, ret = nfnl_acct_fill_info(skb2, NETLINK_CB(skb).portid,
nlh->nlmsg_seq, info->nlh->nlmsg_seq,
NFNL_MSG_TYPE(nlh->nlmsg_type), NFNL_MSG_TYPE(info->nlh->nlmsg_type),
NFNL_MSG_ACCT_NEW, cur); NFNL_MSG_ACCT_NEW, cur);
if (ret <= 0) { if (ret <= 0) {
kfree_skb(skb2); kfree_skb(skb2);
break; break;
} }
ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid, ret = netlink_unicast(info->sk, skb2, NETLINK_CB(skb).portid,
MSG_DONTWAIT); MSG_DONTWAIT);
if (ret > 0) if (ret > 0)
ret = 0; ret = 0;
...@@ -347,12 +343,10 @@ static int nfnl_acct_try_del(struct nf_acct *cur) ...@@ -347,12 +343,10 @@ static int nfnl_acct_try_del(struct nf_acct *cur)
return ret; return ret;
} }
static int nfnl_acct_del(struct net *net, struct sock *nfnl, static int nfnl_acct_del(struct sk_buff *skb, const struct nfnl_info *info,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nlattr * const tb[])
const struct nlattr * const tb[],
struct netlink_ext_ack *extack)
{ {
struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(net); struct nfnl_acct_net *nfnl_acct_net = nfnl_acct_pernet(info->net);
struct nf_acct *cur, *tmp; struct nf_acct *cur, *tmp;
int ret = -ENOENT; int ret = -ENOENT;
char *acct_name; char *acct_name;
...@@ -388,18 +382,30 @@ static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = { ...@@ -388,18 +382,30 @@ static const struct nla_policy nfnl_acct_policy[NFACCT_MAX+1] = {
}; };
static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = { static const struct nfnl_callback nfnl_acct_cb[NFNL_MSG_ACCT_MAX] = {
[NFNL_MSG_ACCT_NEW] = { .call = nfnl_acct_new, [NFNL_MSG_ACCT_NEW] = {
.attr_count = NFACCT_MAX, .call = nfnl_acct_new,
.policy = nfnl_acct_policy }, .type = NFNL_CB_MUTEX,
[NFNL_MSG_ACCT_GET] = { .call = nfnl_acct_get, .attr_count = NFACCT_MAX,
.attr_count = NFACCT_MAX, .policy = nfnl_acct_policy
.policy = nfnl_acct_policy }, },
[NFNL_MSG_ACCT_GET_CTRZERO] = { .call = nfnl_acct_get, [NFNL_MSG_ACCT_GET] = {
.attr_count = NFACCT_MAX, .call = nfnl_acct_get,
.policy = nfnl_acct_policy }, .type = NFNL_CB_MUTEX,
[NFNL_MSG_ACCT_DEL] = { .call = nfnl_acct_del, .attr_count = NFACCT_MAX,
.attr_count = NFACCT_MAX, .policy = nfnl_acct_policy
.policy = nfnl_acct_policy }, },
[NFNL_MSG_ACCT_GET_CTRZERO] = {
.call = nfnl_acct_get,
.type = NFNL_CB_MUTEX,
.attr_count = NFACCT_MAX,
.policy = nfnl_acct_policy
},
[NFNL_MSG_ACCT_DEL] = {
.call = nfnl_acct_del,
.type = NFNL_CB_MUTEX,
.attr_count = NFACCT_MAX,
.policy = nfnl_acct_policy
},
}; };
static const struct nfnetlink_subsystem nfnl_acct_subsys = { static const struct nfnetlink_subsystem nfnl_acct_subsys = {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -292,10 +292,9 @@ static const struct nla_policy nfnl_osf_policy[OSF_ATTR_MAX + 1] = { ...@@ -292,10 +292,9 @@ static const struct nla_policy nfnl_osf_policy[OSF_ATTR_MAX + 1] = {
[OSF_ATTR_FINGER] = { .len = sizeof(struct nf_osf_user_finger) }, [OSF_ATTR_FINGER] = { .len = sizeof(struct nf_osf_user_finger) },
}; };
static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl, static int nfnl_osf_add_callback(struct sk_buff *skb,
struct sk_buff *skb, const struct nlmsghdr *nlh, const struct nfnl_info *info,
const struct nlattr * const osf_attrs[], const struct nlattr * const osf_attrs[])
struct netlink_ext_ack *extack)
{ {
struct nf_osf_user_finger *f; struct nf_osf_user_finger *f;
struct nf_osf_finger *kf = NULL, *sf; struct nf_osf_finger *kf = NULL, *sf;
...@@ -307,7 +306,7 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl, ...@@ -307,7 +306,7 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
if (!osf_attrs[OSF_ATTR_FINGER]) if (!osf_attrs[OSF_ATTR_FINGER])
return -EINVAL; return -EINVAL;
if (!(nlh->nlmsg_flags & NLM_F_CREATE)) if (!(info->nlh->nlmsg_flags & NLM_F_CREATE))
return -EINVAL; return -EINVAL;
f = nla_data(osf_attrs[OSF_ATTR_FINGER]); f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
...@@ -325,7 +324,7 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl, ...@@ -325,7 +324,7 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
kfree(kf); kfree(kf);
kf = NULL; kf = NULL;
if (nlh->nlmsg_flags & NLM_F_EXCL) if (info->nlh->nlmsg_flags & NLM_F_EXCL)
err = -EEXIST; err = -EEXIST;
break; break;
} }
...@@ -339,11 +338,9 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl, ...@@ -339,11 +338,9 @@ static int nfnl_osf_add_callback(struct net *net, struct sock *ctnl,
return err; return err;
} }
static int nfnl_osf_remove_callback(struct net *net, struct sock *ctnl, static int nfnl_osf_remove_callback(struct sk_buff *skb,
struct sk_buff *skb, const struct nfnl_info *info,
const struct nlmsghdr *nlh, const struct nlattr * const osf_attrs[])
const struct nlattr * const osf_attrs[],
struct netlink_ext_ack *extack)
{ {
struct nf_osf_user_finger *f; struct nf_osf_user_finger *f;
struct nf_osf_finger *sf; struct nf_osf_finger *sf;
...@@ -377,11 +374,13 @@ static int nfnl_osf_remove_callback(struct net *net, struct sock *ctnl, ...@@ -377,11 +374,13 @@ static int nfnl_osf_remove_callback(struct net *net, struct sock *ctnl,
static const struct nfnl_callback nfnl_osf_callbacks[OSF_MSG_MAX] = { static const struct nfnl_callback nfnl_osf_callbacks[OSF_MSG_MAX] = {
[OSF_MSG_ADD] = { [OSF_MSG_ADD] = {
.call = nfnl_osf_add_callback, .call = nfnl_osf_add_callback,
.type = NFNL_CB_MUTEX,
.attr_count = OSF_ATTR_MAX, .attr_count = OSF_ATTR_MAX,
.policy = nfnl_osf_policy, .policy = nfnl_osf_policy,
}, },
[OSF_MSG_REMOVE] = { [OSF_MSG_REMOVE] = {
.call = nfnl_osf_remove_callback, .call = nfnl_osf_remove_callback,
.type = NFNL_CB_MUTEX,
.attr_count = OSF_ATTR_MAX, .attr_count = OSF_ATTR_MAX,
.policy = nfnl_osf_policy, .policy = nfnl_osf_policy,
}, },
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -11,9 +11,6 @@ ...@@ -11,9 +11,6 @@
#include <linux/netfilter/nf_tables.h> #include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables.h> #include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_core.h> #include <net/netfilter/nf_tables_core.h>
#include <net/netns/generic.h>
extern unsigned int nf_tables_net_id;
struct nft_dynset { struct nft_dynset {
struct nft_set *set; struct nft_set *set;
...@@ -164,7 +161,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx, ...@@ -164,7 +161,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
const struct nft_expr *expr, const struct nft_expr *expr,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id); struct nftables_pernet *nft_net = nft_pernet(ctx->net);
struct nft_dynset *priv = nft_expr_priv(expr); struct nft_dynset *priv = nft_expr_priv(expr);
u8 genmask = nft_genmask_next(ctx->net); u8 genmask = nft_genmask_next(ctx->net);
struct nft_set *set; struct nft_set *set;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment