aboutsummaryrefslogtreecommitdiff
path: root/net/netfilter
diff options
context:
space:
mode:
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/Kconfig19
-rw-r--r--net/netfilter/Makefile2
-rw-r--r--net/netfilter/core.c51
-rw-r--r--net/netfilter/nf_conntrack_core.c17
-rw-r--r--net/netfilter/nf_conntrack_l3proto_generic.c1
-rw-r--r--net/netfilter/nf_conntrack_netlink.c6
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c50
-rw-r--r--net/netfilter/nf_conntrack_proto_udp.c50
-rw-r--r--net/netfilter/nf_conntrack_standalone.c115
-rw-r--r--net/netfilter/nf_queue.c49
-rw-r--r--net/netfilter/nfnetlink_log.c25
-rw-r--r--net/netfilter/nfnetlink_queue.c27
-rw-r--r--net/netfilter/x_tables.c119
-rw-r--r--net/netfilter/xt_esp.c136
-rw-r--r--net/netfilter/xt_multiport.c314
-rw-r--r--net/netfilter/xt_policy.c2
16 files changed, 743 insertions, 240 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 332acb37b38..e2893effdfa 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -231,6 +231,15 @@ config NETFILTER_XT_MATCH_DCCP
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
+config NETFILTER_XT_MATCH_ESP
+ tristate '"ESP" match support'
+ depends on NETFILTER_XTABLES
+ help
+ This match extension allows you to match a range of SPIs
+ inside ESP header of IPSec packets.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NETFILTER_XT_MATCH_HELPER
tristate '"helper" match support'
depends on NETFILTER_XTABLES
@@ -289,6 +298,16 @@ config NETFILTER_XT_MATCH_POLICY
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_MATCH_MULTIPORT
+ tristate "Multiple port match support"
+ depends on NETFILTER_XTABLES
+ help
+ Multiport matching allows you to match TCP or UDP packets based on
+ a series of source or destination ports: normally a rule can only
+ match a single range of ports.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NETFILTER_XT_MATCH_PHYSDEV
tristate '"physdev" match support'
depends on NETFILTER_XTABLES && BRIDGE_NETFILTER
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 9558727f5e7..95b7e416512 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -35,11 +35,13 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNMARK) += xt_connmark.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o
obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_MULTIPORT) += xt_multiport.o
obj-$(CONFIG_NETFILTER_XT_MATCH_POLICY) += xt_policy.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 1ceb1a6c254..8455a32ea5c 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -27,6 +27,29 @@
#include "nf_internals.h"
+static DEFINE_SPINLOCK(afinfo_lock);
+
+struct nf_afinfo *nf_afinfo[NPROTO];
+EXPORT_SYMBOL(nf_afinfo);
+
+int nf_register_afinfo(struct nf_afinfo *afinfo)
+{
+ spin_lock(&afinfo_lock);
+ rcu_assign_pointer(nf_afinfo[afinfo->family], afinfo);
+ spin_unlock(&afinfo_lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nf_register_afinfo);
+
+void nf_unregister_afinfo(struct nf_afinfo *afinfo)
+{
+ spin_lock(&afinfo_lock);
+ rcu_assign_pointer(nf_afinfo[afinfo->family], NULL);
+ spin_unlock(&afinfo_lock);
+ synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(nf_unregister_afinfo);
+
/* In this code, we can be waiting indefinitely for userspace to
* service a packet if a hook returns NF_QUEUE. We could keep a count
* of skbuffs queued for userspace, and not deregister a hook unless
@@ -63,6 +86,34 @@ void nf_unregister_hook(struct nf_hook_ops *reg)
}
EXPORT_SYMBOL(nf_unregister_hook);
+int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n)
+{
+ unsigned int i;
+ int err = 0;
+
+ for (i = 0; i < n; i++) {
+ err = nf_register_hook(&reg[i]);
+ if (err)
+ goto err;
+ }
+ return err;
+
+err:
+ if (i > 0)
+ nf_unregister_hooks(reg, i);
+ return err;
+}
+EXPORT_SYMBOL(nf_register_hooks);
+
+void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n)
+{
+ unsigned int i;
+
+ for (i = 0; i < n; i++)
+ nf_unregister_hook(&reg[i]);
+}
+EXPORT_SYMBOL(nf_unregister_hooks);
+
unsigned int nf_iterate(struct list_head *head,
struct sk_buff **skb,
int hook,
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 56389c83557..f9b83f91371 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -146,7 +146,7 @@ static void nf_ct_event_cache_flush(void)
struct nf_conntrack_ecache *ecache;
int cpu;
- for_each_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
ecache = &per_cpu(nf_conntrack_ecache, cpu);
if (ecache->ct)
nf_ct_put(ecache->ct);
@@ -178,9 +178,6 @@ static struct {
/* allocated slab cache + modules which uses this slab cache */
int use;
- /* Initialization */
- int (*init_conntrack)(struct nf_conn *, u_int32_t);
-
} nf_ct_cache[NF_CT_F_NUM];
/* protect members of nf_ct_cache except of "use" */
@@ -208,10 +205,8 @@ nf_ct_proto_find_get(u_int16_t l3proto, u_int8_t protocol)
preempt_disable();
p = __nf_ct_proto_find(l3proto, protocol);
- if (p) {
- if (!try_module_get(p->me))
- p = &nf_conntrack_generic_protocol;
- }
+ if (!try_module_get(p->me))
+ p = &nf_conntrack_generic_protocol;
preempt_enable();
return p;
@@ -229,10 +224,8 @@ nf_ct_l3proto_find_get(u_int16_t l3proto)
preempt_disable();
p = __nf_ct_l3proto_find(l3proto);
- if (p) {
- if (!try_module_get(p->me))
- p = &nf_conntrack_generic_l3proto;
- }
+ if (!try_module_get(p->me))
+ p = &nf_conntrack_generic_l3proto;
preempt_enable();
return p;
diff --git a/net/netfilter/nf_conntrack_l3proto_generic.c b/net/netfilter/nf_conntrack_l3proto_generic.c
index 7de4f06c63c..3fc58e454d4 100644
--- a/net/netfilter/nf_conntrack_l3proto_generic.c
+++ b/net/netfilter/nf_conntrack_l3proto_generic.c
@@ -94,5 +94,4 @@ struct nf_conntrack_l3proto nf_conntrack_generic_l3proto = {
.print_conntrack = generic_print_conntrack,
.prepare = generic_prepare,
.get_features = generic_get_features,
- .me = THIS_MODULE,
};
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 0e0e9d7b34c..bd10eb944b6 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1022,7 +1022,7 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[])
return err;
}
-#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
+#if defined(CONFIG_NF_CONNTRACK_MARK)
if (cda[CTA_MARK-1])
ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
#endif
@@ -1062,7 +1062,7 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
return err;
}
-#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
+#if defined(CONFIG_NF_CONNTRACK_MARK)
if (cda[CTA_MARK-1])
ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
#endif
@@ -1687,7 +1687,7 @@ static void __exit ctnetlink_exit(void)
printk("ctnetlink: unregistering from nfnetlink.\n");
#ifdef CONFIG_NF_CONNTRACK_EVENTS
- nf_conntrack_unregister_notifier(&ctnl_notifier_exp);
+ nf_conntrack_expect_unregister_notifier(&ctnl_notifier_exp);
nf_conntrack_unregister_notifier(&ctnl_notifier);
#endif
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 6492ed66fb3..69899f27d26 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -799,8 +799,7 @@ static int tcp_error(struct sk_buff *skb,
unsigned int dataoff,
enum ip_conntrack_info *ctinfo,
int pf,
- unsigned int hooknum,
- int(*csum)(const struct sk_buff *,unsigned int))
+ unsigned int hooknum)
{
struct tcphdr _tcph, *th;
unsigned int tcplen = skb->len - dataoff;
@@ -830,9 +829,8 @@ static int tcp_error(struct sk_buff *skb,
*/
/* FIXME: Source route IP option packets --RR */
if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
- (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING))
- && skb->ip_summed != CHECKSUM_UNNECESSARY
- && csum(skb, dataoff)) {
+ (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) &&
+ nf_checksum(skb, hooknum, dataoff, IPPROTO_TCP, pf)) {
if (LOG_INVALID(IPPROTO_TCP))
nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
"nf_ct_tcp: bad TCP checksum ");
@@ -851,44 +849,6 @@ static int tcp_error(struct sk_buff *skb,
return NF_ACCEPT;
}
-static int csum4(const struct sk_buff *skb, unsigned int dataoff)
-{
- return csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr,
- skb->len - dataoff, IPPROTO_TCP,
- skb->ip_summed == CHECKSUM_HW ? skb->csum
- : skb_checksum(skb, dataoff,
- skb->len - dataoff, 0));
-}
-
-static int csum6(const struct sk_buff *skb, unsigned int dataoff)
-{
- return csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
- skb->len - dataoff, IPPROTO_TCP,
- skb->ip_summed == CHECKSUM_HW
- ? csum_sub(skb->csum,
- skb_checksum(skb, 0, dataoff, 0))
- : skb_checksum(skb, dataoff, skb->len - dataoff,
- 0));
-}
-
-static int tcp_error4(struct sk_buff *skb,
- unsigned int dataoff,
- enum ip_conntrack_info *ctinfo,
- int pf,
- unsigned int hooknum)
-{
- return tcp_error(skb, dataoff, ctinfo, pf, hooknum, csum4);
-}
-
-static int tcp_error6(struct sk_buff *skb,
- unsigned int dataoff,
- enum ip_conntrack_info *ctinfo,
- int pf,
- unsigned int hooknum)
-{
- return tcp_error(skb, dataoff, ctinfo, pf, hooknum, csum6);
-}
-
/* Returns verdict for packet, or -1 for invalid. */
static int tcp_packet(struct nf_conn *conntrack,
const struct sk_buff *skb,
@@ -1218,7 +1178,7 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 =
.print_conntrack = tcp_print_conntrack,
.packet = tcp_packet,
.new = tcp_new,
- .error = tcp_error4,
+ .error = tcp_error,
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
.to_nfattr = tcp_to_nfattr,
@@ -1239,7 +1199,7 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 =
.print_conntrack = tcp_print_conntrack,
.packet = tcp_packet,
.new = tcp_new,
- .error = tcp_error6,
+ .error = tcp_error,
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
.to_nfattr = tcp_to_nfattr,
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index 831d206344e..d93edbfde9e 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -103,8 +103,7 @@ static int udp_new(struct nf_conn *conntrack, const struct sk_buff *skb,
static int udp_error(struct sk_buff *skb, unsigned int dataoff,
enum ip_conntrack_info *ctinfo,
int pf,
- unsigned int hooknum,
- int (*csum)(const struct sk_buff *, unsigned int))
+ unsigned int hooknum)
{
unsigned int udplen = skb->len - dataoff;
struct udphdr _hdr, *hdr;
@@ -136,9 +135,8 @@ static int udp_error(struct sk_buff *skb, unsigned int dataoff,
* and moreover root might send raw packets.
* FIXME: Source route IP option packets --RR */
if (((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
- (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING))
- && skb->ip_summed != CHECKSUM_UNNECESSARY
- && csum(skb, dataoff)) {
+ (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) &&
+ nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) {
if (LOG_INVALID(IPPROTO_UDP))
nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
"nf_ct_udp: bad UDP checksum ");
@@ -148,44 +146,6 @@ static int udp_error(struct sk_buff *skb, unsigned int dataoff,
return NF_ACCEPT;
}
-static int csum4(const struct sk_buff *skb, unsigned int dataoff)
-{
- return csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr,
- skb->len - dataoff, IPPROTO_UDP,
- skb->ip_summed == CHECKSUM_HW ? skb->csum
- : skb_checksum(skb, dataoff,
- skb->len - dataoff, 0));
-}
-
-static int csum6(const struct sk_buff *skb, unsigned int dataoff)
-{
- return csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
- skb->len - dataoff, IPPROTO_UDP,
- skb->ip_summed == CHECKSUM_HW
- ? csum_sub(skb->csum,
- skb_checksum(skb, 0, dataoff, 0))
- : skb_checksum(skb, dataoff, skb->len - dataoff,
- 0));
-}
-
-static int udp_error4(struct sk_buff *skb,
- unsigned int dataoff,
- enum ip_conntrack_info *ctinfo,
- int pf,
- unsigned int hooknum)
-{
- return udp_error(skb, dataoff, ctinfo, pf, hooknum, csum4);
-}
-
-static int udp_error6(struct sk_buff *skb,
- unsigned int dataoff,
- enum ip_conntrack_info *ctinfo,
- int pf,
- unsigned int hooknum)
-{
- return udp_error(skb, dataoff, ctinfo, pf, hooknum, csum6);
-}
-
struct nf_conntrack_protocol nf_conntrack_protocol_udp4 =
{
.l3proto = PF_INET,
@@ -197,7 +157,7 @@ struct nf_conntrack_protocol nf_conntrack_protocol_udp4 =
.print_conntrack = udp_print_conntrack,
.packet = udp_packet,
.new = udp_new,
- .error = udp_error4,
+ .error = udp_error,
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
@@ -216,7 +176,7 @@ struct nf_conntrack_protocol nf_conntrack_protocol_udp6 =
.print_conntrack = udp_print_conntrack,
.packet = udp_packet,
.new = udp_new,
- .error = udp_error6,
+ .error = udp_error,
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index c72aa3cd22e..408960c6a54 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -649,63 +649,6 @@ static ctl_table nf_ct_net_table[] = {
EXPORT_SYMBOL(nf_ct_log_invalid);
#endif /* CONFIG_SYSCTL */
-static int init_or_cleanup(int init)
-{
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *proc, *proc_exp, *proc_stat;
-#endif
- int ret = 0;
-
- if (!init) goto cleanup;
-
- ret = nf_conntrack_init();
- if (ret < 0)
- goto cleanup_nothing;
-
-#ifdef CONFIG_PROC_FS
- proc = proc_net_fops_create("nf_conntrack", 0440, &ct_file_ops);
- if (!proc) goto cleanup_init;
-
- proc_exp = proc_net_fops_create("nf_conntrack_expect", 0440,
- &exp_file_ops);
- if (!proc_exp) goto cleanup_proc;
-
- proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, proc_net_stat);
- if (!proc_stat)
- goto cleanup_proc_exp;
-
- proc_stat->proc_fops = &ct_cpu_seq_fops;
- proc_stat->owner = THIS_MODULE;
-#endif
-#ifdef CONFIG_SYSCTL
- nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
- if (nf_ct_sysctl_header == NULL) {
- printk("nf_conntrack: can't register to sysctl.\n");
- ret = -ENOMEM;
- goto cleanup_proc_stat;
- }
-#endif
-
- return ret;
-
- cleanup:
-#ifdef CONFIG_SYSCTL
- unregister_sysctl_table(nf_ct_sysctl_header);
- cleanup_proc_stat:
-#endif
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("nf_conntrack", proc_net_stat);
- cleanup_proc_exp:
- proc_net_remove("nf_conntrack_expect");
- cleanup_proc:
- proc_net_remove("nf_conntrack");
- cleanup_init:
-#endif /* CNFIG_PROC_FS */
- nf_conntrack_cleanup();
- cleanup_nothing:
- return ret;
-}
-
int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
{
int ret = 0;
@@ -808,12 +751,66 @@ void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto)
static int __init nf_conntrack_standalone_init(void)
{
- return init_or_cleanup(1);
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *proc, *proc_exp, *proc_stat;
+#endif
+ int ret = 0;
+
+ ret = nf_conntrack_init();
+ if (ret < 0)
+ return ret;
+
+#ifdef CONFIG_PROC_FS
+ proc = proc_net_fops_create("nf_conntrack", 0440, &ct_file_ops);
+ if (!proc) goto cleanup_init;
+
+ proc_exp = proc_net_fops_create("nf_conntrack_expect", 0440,
+ &exp_file_ops);
+ if (!proc_exp) goto cleanup_proc;
+
+ proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, proc_net_stat);
+ if (!proc_stat)
+ goto cleanup_proc_exp;
+
+ proc_stat->proc_fops = &ct_cpu_seq_fops;
+ proc_stat->owner = THIS_MODULE;
+#endif
+#ifdef CONFIG_SYSCTL
+ nf_ct_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
+ if (nf_ct_sysctl_header == NULL) {
+ printk("nf_conntrack: can't register to sysctl.\n");
+ ret = -ENOMEM;
+ goto cleanup_proc_stat;
+ }
+#endif
+ return ret;
+
+#ifdef CONFIG_SYSCTL
+ cleanup_proc_stat:
+#endif
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nf_conntrack", proc_net_stat);
+ cleanup_proc_exp:
+ proc_net_remove("nf_conntrack_expect");
+ cleanup_proc:
+ proc_net_remove("nf_conntrack");
+ cleanup_init:
+#endif /* CNFIG_PROC_FS */
+ nf_conntrack_cleanup();
+ return ret;
}
static void __exit nf_conntrack_standalone_fini(void)
{
- init_or_cleanup(0);
+#ifdef CONFIG_SYSCTL
+ unregister_sysctl_table(nf_ct_sysctl_header);
+#endif
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nf_conntrack", proc_net_stat);
+ proc_net_remove("nf_conntrack_expect");
+ proc_net_remove("nf_conntrack");
+#endif /* CNFIG_PROC_FS */
+ nf_conntrack_cleanup();
}
module_init(nf_conntrack_standalone_init);
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index d9f0d7ef103..ee8f70889f4 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -17,7 +17,6 @@
* for queueing and must reinject all packets it receives, no matter what.
*/
static struct nf_queue_handler *queue_handler[NPROTO];
-static struct nf_queue_rerouter *queue_rerouter[NPROTO];
static DEFINE_RWLOCK(queue_handler_lock);
@@ -59,32 +58,6 @@ int nf_unregister_queue_handler(int pf)
}
EXPORT_SYMBOL(nf_unregister_queue_handler);
-int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer)
-{
- if (pf >= NPROTO)
- return -EINVAL;
-
- write_lock_bh(&queue_handler_lock);
- rcu_assign_pointer(queue_rerouter[pf], rer);
- write_unlock_bh(&queue_handler_lock);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(nf_register_queue_rerouter);
-
-int nf_unregister_queue_rerouter(int pf)
-{
- if (pf >= NPROTO)
- return -EINVAL;
-
- write_lock_bh(&queue_handler_lock);
- rcu_assign_pointer(queue_rerouter[pf], NULL);
- write_unlock_bh(&queue_handler_lock);
- synchronize_rcu();
- return 0;
-}
-EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter);
-
void nf_unregister_queue_handlers(struct nf_queue_handler *qh)
{
int pf;
@@ -116,7 +89,7 @@ int nf_queue(struct sk_buff **skb,
struct net_device *physindev = NULL;
struct net_device *physoutdev = NULL;
#endif
- struct nf_queue_rerouter *rerouter;
+ struct nf_afinfo *afinfo;
/* QUEUE == DROP if noone is waiting, to be safe. */
read_lock(&queue_handler_lock);
@@ -126,7 +99,14 @@ int nf_queue(struct sk_buff **skb,
return 1;
}
- info = kmalloc(sizeof(*info)+queue_rerouter[pf]->rer_size, GFP_ATOMIC);
+ afinfo = nf_get_afinfo(pf);
+ if (!afinfo) {
+ read_unlock(&queue_handler_lock);
+ kfree_skb(*skb);
+ return 1;
+ }
+
+ info = kmalloc(sizeof(*info) + afinfo->route_key_size, GFP_ATOMIC);
if (!info) {
if (net_ratelimit())
printk(KERN_ERR "OOM queueing packet %p\n",
@@ -158,10 +138,7 @@ int nf_queue(struct sk_buff **skb,
if (physoutdev) dev_hold(physoutdev);
}
#endif
- rerouter = rcu_dereference(queue_rerouter[pf]);
- if (rerouter)
- rerouter->save(*skb, info);
-
+ afinfo->saveroute(*skb, info);
status = queue_handler[pf]->outfn(*skb, info, queuenum,
queue_handler[pf]->data);
@@ -190,7 +167,7 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info,
{
struct list_head *elem = &info->elem->list;
struct list_head *i;
- struct nf_queue_rerouter *rerouter;
+ struct nf_afinfo *afinfo;
rcu_read_lock();
@@ -228,8 +205,8 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info,
}
if (verdict == NF_ACCEPT) {
- rerouter = rcu_dereference(queue_rerouter[info->pf]);
- if (rerouter && rerouter->reroute(&skb, info) < 0)
+ afinfo = nf_get_afinfo(info->pf);
+ if (!afinfo || afinfo->reroute(&skb, info) < 0)
verdict = NF_DROP;
}
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 3e3f5448bac..c60273cad77 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -1033,17 +1033,13 @@ static struct file_operations nful_file_ops = {
#endif /* PROC_FS */
-static int
-init_or_cleanup(int init)
+static int __init nfnetlink_log_init(void)
{
int i, status = -ENOMEM;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_nful;
#endif
- if (!init)
- goto cleanup;
-
for (i = 0; i < INSTANCE_BUCKETS; i++)
INIT_HLIST_HEAD(&instance_table[i]);
@@ -1066,30 +1062,25 @@ init_or_cleanup(int init)
goto cleanup_subsys;
proc_nful->proc_fops = &nful_file_ops;
#endif
-
return status;
-cleanup:
- nf_log_unregister_logger(&nfulnl_logger);
#ifdef CONFIG_PROC_FS
- remove_proc_entry("nfnetlink_log", proc_net_netfilter);
cleanup_subsys:
-#endif
nfnetlink_subsys_unregister(&nfulnl_subsys);
+#endif
cleanup_netlink_notifier:
netlink_unregister_notifier(&nfulnl_rtnl_notifier);
return status;
}
-static int __init nfnetlink_log_init(void)
-{
-
- return init_or_cleanup(1);
-}
-
static void __exit nfnetlink_log_fini(void)
{
- init_or_cleanup(0);
+ nf_log_unregister_logger(&nfulnl_logger);
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nfnetlink_log", proc_net_netfilter);
+#endif
+ nfnetlink_subsys_unregister(&nfulnl_subsys);
+ netlink_unregister_notifier(&nfulnl_rtnl_notifier);
}
MODULE_DESCRIPTION("netfilter userspace logging");
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index d0e62f68139..86a4ac33de3 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1071,17 +1071,13 @@ static struct file_operations nfqnl_file_ops = {
#endif /* PROC_FS */
-static int
-init_or_cleanup(int init)
+static int __init nfnetlink_queue_init(void)
{
int i, status = -ENOMEM;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_nfqueue;
#endif
- if (!init)
- goto cleanup;
-
for (i = 0; i < INSTANCE_BUCKETS; i++)
INIT_HLIST_HEAD(&instance_table[i]);
@@ -1101,31 +1097,26 @@ init_or_cleanup(int init)
#endif
register_netdevice_notifier(&nfqnl_dev_notifier);
-
return status;
-cleanup:
- nf_unregister_queue_handlers(&nfqh);
- unregister_netdevice_notifier(&nfqnl_dev_notifier);
#ifdef CONFIG_PROC_FS
- remove_proc_entry("nfnetlink_queue", proc_net_netfilter);
cleanup_subsys:
-#endif
nfnetlink_subsys_unregister(&nfqnl_subsys);
+#endif
cleanup_netlink_notifier:
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
return status;
}
-static int __init nfnetlink_queue_init(void)
-{
-
- return init_or_cleanup(1);
-}
-
static void __exit nfnetlink_queue_fini(void)
{
- init_or_cleanup(0);
+ nf_unregister_queue_handlers(&nfqh);
+ unregister_netdevice_notifier(&nfqnl_dev_notifier);
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nfnetlink_queue", proc_net_netfilter);
+#endif
+ nfnetlink_subsys_unregister(&nfqnl_subsys);
+ netlink_unregister_notifier(&nfqnl_rtnl_notifier);
}
MODULE_DESCRIPTION("netfilter packet queue handler");
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index a657ab5394c..17abf60f957 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -38,6 +38,7 @@ struct xt_af {
struct list_head match;
struct list_head target;
struct list_head tables;
+ struct mutex compat_mutex;
};
static struct xt_af *xt;
@@ -272,6 +273,54 @@ int xt_check_match(const struct xt_match *match, unsigned short family,
}
EXPORT_SYMBOL_GPL(xt_check_match);
+#ifdef CONFIG_COMPAT
+int xt_compat_match(void *match, void **dstptr, int *size, int convert)
+{
+ struct xt_match *m;
+ struct compat_xt_entry_match *pcompat_m;
+ struct xt_entry_match *pm;
+ u_int16_t msize;
+ int off, ret;
+
+ ret = 0;
+ m = ((struct xt_entry_match *)match)->u.kernel.match;
+ off = XT_ALIGN(m->matchsize) - COMPAT_XT_ALIGN(m->matchsize);
+ switch (convert) {
+ case COMPAT_TO_USER:
+ pm = (struct xt_entry_match *)match;
+ msize = pm->u.user.match_size;
+ if (__copy_to_user(*dstptr, pm, msize)) {
+ ret = -EFAULT;
+ break;
+ }
+ msize -= off;
+ if (put_user(msize, (u_int16_t *)*dstptr))
+ ret = -EFAULT;
+ *size -= off;
+ *dstptr += msize;
+ break;
+ case COMPAT_FROM_USER:
+ pcompat_m = (struct compat_xt_entry_match *)match;
+ pm = (struct xt_entry_match *)*dstptr;
+ msize = pcompat_m->u.user.match_size;
+ memcpy(pm, pcompat_m, msize);
+ msize += off;
+ pm->u.user.match_size = msize;
+ *size += off;
+ *dstptr += msize;
+ break;
+ case COMPAT_CALC_SIZE:
+ *size += off;
+ break;
+ default:
+ ret = -ENOPROTOOPT;
+ break;
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xt_compat_match);
+#endif
+
int xt_check_target(const struct xt_target *target, unsigned short family,
unsigned int size, const char *table, unsigned int hook_mask,
unsigned short proto, int inv_proto)
@@ -301,6 +350,54 @@ int xt_check_target(const struct xt_target *target, unsigned short family,
}
EXPORT_SYMBOL_GPL(xt_check_target);
+#ifdef CONFIG_COMPAT
+int xt_compat_target(void *target, void **dstptr, int *size, int convert)
+{
+ struct xt_target *t;
+ struct compat_xt_entry_target *pcompat;
+ struct xt_entry_target *pt;
+ u_int16_t tsize;
+ int off, ret;
+
+ ret = 0;
+ t = ((struct xt_entry_target *)target)->u.kernel.target;
+ off = XT_ALIGN(t->targetsize) - COMPAT_XT_ALIGN(t->targetsize);
+ switch (convert) {
+ case COMPAT_TO_USER:
+ pt = (struct xt_entry_target *)target;
+ tsize = pt->u.user.target_size;
+ if (__copy_to_user(*dstptr, pt, tsize)) {
+ ret = -EFAULT;
+ break;
+ }
+ tsize -= off;
+ if (put_user(tsize, (u_int16_t *)*dstptr))
+ ret = -EFAULT;
+ *size -= off;
+ *dstptr += tsize;
+ break;
+ case COMPAT_FROM_USER:
+ pcompat = (struct compat_xt_entry_target *)target;
+ pt = (struct xt_entry_target *)*dstptr;
+ tsize = pcompat->u.user.target_size;
+ memcpy(pt, pcompat, tsize);
+ tsize += off;
+ pt->u.user.target_size = tsize;
+ *size += off;
+ *dstptr += tsize;
+ break;
+ case COMPAT_CALC_SIZE:
+ *size += off;
+ break;
+ default:
+ ret = -ENOPROTOOPT;
+ break;
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xt_compat_target);
+#endif
+
struct xt_table_info *xt_alloc_table_info(unsigned int size)
{
struct xt_table_info *newinfo;
@@ -316,7 +413,7 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size)
newinfo->size = size;
- for_each_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
if (size <= PAGE_SIZE)
newinfo->entries[cpu] = kmalloc_node(size,
GFP_KERNEL,
@@ -339,7 +436,7 @@ void xt_free_table_info(struct xt_table_info *info)
{
int cpu;
- for_each_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
if (info->size <= PAGE_SIZE)
kfree(info->entries[cpu]);
else
@@ -371,6 +468,19 @@ void xt_table_unlock(struct xt_table *table)
}
EXPORT_SYMBOL_GPL(xt_table_unlock);
+#ifdef CONFIG_COMPAT
+void xt_compat_lock(int af)
+{
+ mutex_lock(&xt[af].compat_mutex);
+}
+EXPORT_SYMBOL_GPL(xt_compat_lock);
+
+void xt_compat_unlock(int af)
+{
+ mutex_unlock(&xt[af].compat_mutex);
+}
+EXPORT_SYMBOL_GPL(xt_compat_unlock);
+#endif
struct xt_table_info *
xt_replace_table(struct xt_table *table,
@@ -419,6 +529,7 @@ int xt_register_table(struct xt_table *table,
/* Simplifies replace_table code. */
table->private = bootstrap;
+ rwlock_init(&table->lock);
if (!xt_replace_table(table, 0, newinfo, &ret))
goto unlock;
@@ -428,7 +539,6 @@ int xt_register_table(struct xt_table *table,
/* save number of initial entries */
private->initial_entries = private->number;
- rwlock_init(&table->lock);
list_prepend(&xt[table->af].tables, table);
ret = 0;
@@ -671,6 +781,9 @@ static int __init xt_init(void)
for (i = 0; i < NPROTO; i++) {
mutex_init(&xt[i].mutex);
+#ifdef CONFIG_COMPAT
+ mutex_init(&xt[i].compat_mutex);
+#endif
INIT_LIST_HEAD(&xt[i].target);
INIT_LIST_HEAD(&xt[i].match);
INIT_LIST_HEAD(&xt[i].tables);
diff --git a/net/netfilter/xt_esp.c b/net/netfilter/xt_esp.c
new file mode 100644
index 00000000000..9dad6281e0c
--- /dev/null
+++ b/net/netfilter/xt_esp.c
@@ -0,0 +1,136 @@
+/* Kernel module to match ESP parameters. */
+
+/* (C) 1999-2000 Yon Uriarte <yon@astaro.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+
+#include <linux/netfilter/xt_esp.h>
+#include <linux/netfilter/x_tables.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yon Uriarte <yon@astaro.de>");
+MODULE_DESCRIPTION("x_tables ESP SPI match module");
+MODULE_ALIAS("ipt_esp");
+MODULE_ALIAS("ip6t_esp");
+
+#if 0
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+/* Returns 1 if the spi is matched by the range, 0 otherwise */
+static inline int
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+{
+ int r = 0;
+ duprintf("esp spi_match:%c 0x%x <= 0x%x <= 0x%x", invert ? '!' : ' ',
+ min, spi, max);
+ r = (spi >= min && spi <= max) ^ invert;
+ duprintf(" result %s\n", r ? "PASS" : "FAILED");
+ return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo,
+ int offset,
+ unsigned int protoff,
+ int *hotdrop)
+{
+ struct ip_esp_hdr _esp, *eh;
+ const struct xt_esp *espinfo = matchinfo;
+
+ /* Must not be a fragment. */
+ if (offset)
+ return 0;
+
+ eh = skb_header_pointer(skb, protoff, sizeof(_esp), &_esp);
+ if (eh == NULL) {
+ /* We've been asked to examine this packet, and we
+ * can't. Hence, no choice but to drop.
+ */
+ duprintf("Dropping evil ESP tinygram.\n");
+ *hotdrop = 1;
+ return 0;
+ }
+
+ return spi_match(espinfo->spis[0], espinfo->spis[1], ntohl(eh->spi),
+ !!(espinfo->invflags & XT_ESP_INV_SPI));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+ const void *ip_void,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int matchinfosize,
+ unsigned int hook_mask)
+{
+ const struct xt_esp *espinfo = matchinfo;
+
+ if (espinfo->invflags & ~XT_ESP_INV_MASK) {
+ duprintf("xt_esp: unknown flags %X\n", espinfo->invflags);
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct xt_match esp_match = {
+ .name = "esp",
+ .family = AF_INET,
+ .proto = IPPROTO_ESP,
+ .match = &match,
+ .matchsize = sizeof(struct xt_esp),
+ .checkentry = &checkentry,
+ .me = THIS_MODULE,
+};
+
+static struct xt_match esp6_match = {
+ .name = "esp",
+ .family = AF_INET6,
+ .proto = IPPROTO_ESP,
+ .match = &match,
+ .matchsize = sizeof(struct xt_esp),
+ .checkentry = &checkentry,
+ .me = THIS_MODULE,
+};
+
+static int __init xt_esp_init(void)
+{
+ int ret;
+ ret = xt_register_match(&esp_match);
+ if (ret)
+ return ret;
+
+ ret = xt_register_match(&esp6_match);
+ if (ret)
+ xt_unregister_match(&esp_match);
+
+ return ret;
+}
+
+static void __exit xt_esp_cleanup(void)
+{
+ xt_unregister_match(&esp_match);
+ xt_unregister_match(&esp6_match);
+}
+
+module_init(xt_esp_init);
+module_exit(xt_esp_cleanup);
diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c
new file mode 100644
index 00000000000..b56cd2baaac
--- /dev/null
+++ b/net/netfilter/xt_multiport.c
@@ -0,0 +1,314 @@
+/* Kernel module to match one of a list of TCP/UDP ports: ports are in
+ the same place so we can treat them as equal. */
+
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/udp.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+
+#include <linux/netfilter/xt_multiport.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
+MODULE_DESCRIPTION("x_tables multiple port match module");
+MODULE_ALIAS("ipt_multiport");
+MODULE_ALIAS("ip6t_multiport");
+
+#if 0
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+/* Returns 1 if the port is matched by the test, 0 otherwise. */
+static inline int
+ports_match(const u_int16_t *portlist, enum xt_multiport_flags flags,
+ u_int8_t count, u_int16_t src, u_int16_t dst)
+{
+ unsigned int i;
+ for (i = 0; i < count; i++) {
+ if (flags != XT_MULTIPORT_DESTINATION && portlist[i] == src)
+ return 1;
+
+ if (flags != XT_MULTIPORT_SOURCE && portlist[i] == dst)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Returns 1 if the port is matched by the test, 0 otherwise. */
+static inline int
+ports_match_v1(const struct xt_multiport_v1 *minfo,
+ u_int16_t src, u_int16_t dst)
+{
+ unsigned int i;
+ u_int16_t s, e;
+
+ for (i = 0; i < minfo->count; i++) {
+ s = minfo->ports[i];
+
+ if (minfo->pflags[i]) {
+ /* range port matching */
+ e = minfo->ports[++i];
+ duprintf("src or dst matches with %d-%d?\n", s, e);
+
+ if (minfo->flags == XT_MULTIPORT_SOURCE
+ && src >= s && src <= e)
+ return 1 ^ minfo->invert;
+ if (minfo->flags == XT_MULTIPORT_DESTINATION
+ && dst >= s && dst <= e)
+ return 1 ^ minfo->invert;
+ if (minfo->flags == XT_MULTIPORT_EITHER
+ && ((dst >= s && dst <= e)
+ || (src >= s && src <= e)))
+ return 1 ^ minfo->invert;
+ } else {
+ /* exact port matching */
+ duprintf("src or dst matches with %d?\n", s);
+
+ if (minfo->flags == XT_MULTIPORT_SOURCE
+ && src == s)
+ return 1 ^ minfo->invert;
+ if (minfo->flags == XT_MULTIPORT_DESTINATION
+ && dst == s)
+ return 1 ^ minfo->invert;
+ if (minfo->flags == XT_MULTIPORT_EITHER
+ && (src == s || dst == s))
+ return 1 ^ minfo->invert;
+ }
+ }
+
+ return minfo->invert;
+}
+
+static int
+match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo,
+ int offset,
+ unsigned int protoff,
+ int *hotdrop)
+{
+ u16 _ports[2], *pptr;
+ const struct xt_multiport *multiinfo = matchinfo;
+
+ if (offset)
+ return 0;
+
+ pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports);
+ if (pptr == NULL) {
+ /* We've been asked to examine this packet, and we
+ * can't. Hence, no choice but to drop.
+ */
+ duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
+ *hotdrop = 1;
+ return 0;
+ }
+
+ return ports_match(multiinfo->ports,
+ multiinfo->flags, multiinfo->count,
+ ntohs(pptr[0]), ntohs(pptr[1]));
+}
+
+static int
+match_v1(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo,
+ int offset,
+ unsigned int protoff,
+ int *hotdrop)
+{
+ u16 _ports[2], *pptr;
+ const struct xt_multiport_v1 *multiinfo = matchinfo;
+
+ if (offset)
+ return 0;
+
+ pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports);
+ if (pptr == NULL) {
+ /* We've been asked to examine this packet, and we
+ * can't. Hence, no choice but to drop.
+ */
+ duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
+ *hotdrop = 1;
+ return 0;
+ }
+
+ return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1]));
+}
+
+static inline int
+check(u_int16_t proto,
+ u_int8_t ip_invflags,
+ u_int8_t match_flags,
+ u_int8_t count)
+{
+ /* Must specify proto == TCP/UDP, no unknown flags or bad count */
+ return (proto == IPPROTO_TCP || proto == IPPROTO_UDP)
+ && !(ip_invflags & XT_INV_PROTO)
+ && (match_flags == XT_MULTIPORT_SOURCE
+ || match_flags == XT_MULTIPORT_DESTINATION
+ || match_flags == XT_MULTIPORT_EITHER)
+ && count <= XT_MULTI_PORTS;
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+ const void *info,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int matchsize,
+ unsigned int hook_mask)
+{
+ const struct ipt_ip *ip = info;
+ const struct xt_multiport *multiinfo = matchinfo;
+
+ return check(ip->proto, ip->invflags, multiinfo->flags,
+ multiinfo->count);
+}
+
+static int
+checkentry_v1(const char *tablename,
+ const void *info,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int matchsize,
+ unsigned int hook_mask)
+{
+ const struct ipt_ip *ip = info;
+ const struct xt_multiport_v1 *multiinfo = matchinfo;
+
+ return check(ip->proto, ip->invflags, multiinfo->flags,
+ multiinfo->count);
+}
+
+static int
+checkentry6(const char *tablename,
+ const void *info,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int matchsize,
+ unsigned int hook_mask)
+{
+ const struct ip6t_ip6 *ip = info;
+ const struct xt_multiport *multiinfo = matchinfo;
+
+ return check(ip->proto, ip->invflags, multiinfo->flags,
+ multiinfo->count);
+}
+
+static int
+checkentry6_v1(const char *tablename,
+ const void *info,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int matchsize,
+ unsigned int hook_mask)
+{
+ const struct ip6t_ip6 *ip = info;
+ const struct xt_multiport_v1 *multiinfo = matchinfo;
+
+ return check(ip->proto, ip->invflags, multiinfo->flags,
+ multiinfo->count);
+}
+
+static struct xt_match multiport_match = {
+ .name = "multiport",
+ .revision = 0,
+ .matchsize = sizeof(struct xt_multiport),
+ .match = &match,
+ .checkentry = &checkentry,
+ .family = AF_INET,
+ .me = THIS_MODULE,
+};
+
+static struct xt_match multiport_match_v1 = {
+ .name = "multiport",
+ .revision = 1,
+ .matchsize = sizeof(struct xt_multiport_v1),
+ .match = &match_v1,
+ .checkentry = &checkentry_v1,
+ .family = AF_INET,
+ .me = THIS_MODULE,
+};
+
+static struct xt_match multiport6_match = {
+ .name = "multiport",
+ .revision = 0,
+ .matchsize = sizeof(struct xt_multiport),
+ .match = &match,
+ .checkentry = &checkentry6,
+ .family = AF_INET6,
+ .me = THIS_MODULE,
+};
+
+static struct xt_match multiport6_match_v1 = {
+ .name = "multiport",
+ .revision = 1,
+ .matchsize = sizeof(struct xt_multiport_v1),
+ .match = &match_v1,
+ .checkentry = &checkentry6_v1,
+ .family = AF_INET6,
+ .me = THIS_MODULE,
+};
+
+static int __init xt_multiport_init(void)
+{
+ int ret;
+
+ ret = xt_register_match(&multiport_match);
+ if (ret)
+ goto out;
+
+ ret = xt_register_match(&multiport_match_v1);
+ if (ret)
+ goto out_unreg_multi_v0;
+
+ ret = xt_register_match(&multiport6_match);
+ if (ret)
+ goto out_unreg_multi_v1;
+
+ ret = xt_register_match(&multiport6_match_v1);
+ if (ret)
+ goto out_unreg_multi6_v0;
+
+ return ret;
+
+out_unreg_multi6_v0:
+ xt_unregister_match(&multiport6_match);
+out_unreg_multi_v1:
+ xt_unregister_match(&multiport_match_v1);
+out_unreg_multi_v0:
+ xt_unregister_match(&multiport_match);
+out:
+ return ret;
+}
+
+static void __exit xt_multiport_fini(void)
+{
+ xt_unregister_match(&multiport_match);
+ xt_unregister_match(&multiport_match_v1);
+ xt_unregister_match(&multiport6_match);
+ xt_unregister_match(&multiport6_match_v1);
+}
+
+module_init(xt_multiport_init);
+module_exit(xt_multiport_fini);
diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c
index 1099cb005fc..a3aa62fbda6 100644
--- a/net/netfilter/xt_policy.c
+++ b/net/netfilter/xt_policy.c
@@ -71,7 +71,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info,
return 0;
e = &info->pol[pos];
- if (match_xfrm_state(sp->x[i].xvec, e, family)) {
+ if (match_xfrm_state(sp->xvec[i], e, family)) {
if (!strict)
return 1;
} else if (strict)