summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-04-02 12:47:12 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-04-02 12:47:12 -0700
commitbacd3add087770333bdce65cd3dd25e3b2cd67ac (patch)
treeb9a5512a7abbf661020af87ee843e4ad711546ed
parent29e350944fdc2dfca102500790d8ad6d6ff4f69d (diff)
parent9a1875e60e61b563737d8d1fc3876b279710fe93 (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6: [NET]: Fully fix the memory leaks in sys_accept(). [NETFILTER]: iptables 32bit compat layer [NETFILTER]: {ip,nf}_conntrack_netlink: fix expectation notifier unregistration [NETFILTER]: fix ifdef for connmark support in nf_conntrack_netlink [NETFILTER]: x_tables: unify IPv4/IPv6 multiport match [NETFILTER]: x_tables: unify IPv4/IPv6 esp match [NET]: Fix dentry leak in sys_accept(). [IPSEC]: Kill unused decap state structure [IPSEC]: Kill unused decap state argument [NET]: com90xx kmalloc fix [TG3]: Update driver version and reldate. [TG3]: Revert "Speed up SRAM access"
-rw-r--r--drivers/net/arcnet/com90xx.c4
-rw-r--r--drivers/net/tg3.c57
-rw-r--r--include/linux/netfilter/x_tables.h67
-rw-r--r--include/linux/netfilter/xt_esp.h14
-rw-r--r--include/linux/netfilter/xt_multiport.h30
-rw-r--r--include/linux/netfilter_ipv4/ip_tables.h18
-rw-r--r--include/linux/netfilter_ipv4/ipt_esp.h14
-rw-r--r--include/linux/netfilter_ipv4/ipt_multiport.h31
-rw-r--r--include/linux/netfilter_ipv6/ip6t_esp.h12
-rw-r--r--include/linux/netfilter_ipv6/ip6t_multiport.h25
-rw-r--r--include/net/xfrm.h19
-rw-r--r--net/compat.c3
-rw-r--r--net/ipv4/ah4.c2
-rw-r--r--net/ipv4/esp4.c5
-rw-r--r--net/ipv4/ipcomp.c3
-rw-r--r--net/ipv4/netfilter/Kconfig18
-rw-r--r--net/ipv4/netfilter/Makefile3
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netlink.c2
-rw-r--r--net/ipv4/netfilter/ip_tables.c1138
-rw-r--r--net/ipv4/netfilter/ipt_multiport.c195
-rw-r--r--net/ipv4/xfrm4_input.c15
-rw-r--r--net/ipv4/xfrm4_tunnel.c2
-rw-r--r--net/ipv6/ah6.c2
-rw-r--r--net/ipv6/esp6.c2
-rw-r--r--net/ipv6/ipcomp6.c2
-rw-r--r--net/ipv6/netfilter/Kconfig16
-rw-r--r--net/ipv6/netfilter/Makefile3
-rw-r--r--net/ipv6/netfilter/ip6t_esp.c115
-rw-r--r--net/ipv6/netfilter/ip6t_multiport.c125
-rw-r--r--net/ipv6/xfrm6_input.c11
-rw-r--r--net/ipv6/xfrm6_tunnel.c2
-rw-r--r--net/netfilter/Kconfig19
-rw-r--r--net/netfilter/Makefile2
-rw-r--r--net/netfilter/nf_conntrack_netlink.c6
-rw-r--r--net/netfilter/x_tables.c113
-rw-r--r--net/netfilter/xt_esp.c (renamed from net/ipv4/netfilter/ipt_esp.c)81
-rw-r--r--net/netfilter/xt_multiport.c314
-rw-r--r--net/netfilter/xt_policy.c2
-rw-r--r--net/socket.c7
-rw-r--r--net/xfrm/xfrm_input.c4
-rw-r--r--net/xfrm/xfrm_policy.c10
41 files changed, 1739 insertions, 774 deletions
diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c
index 43150b2bd13f..0d45553ff75c 100644
--- a/drivers/net/arcnet/com90xx.c
+++ b/drivers/net/arcnet/com90xx.c
@@ -125,11 +125,11 @@ static void __init com90xx_probe(void)
if (!io && !irq && !shmem && !*device && com90xx_skip_probe)
return;
- shmems = kzalloc(((0x10000-0xa0000) / 0x800) * sizeof(unsigned long),
+ shmems = kzalloc(((0x100000-0xa0000) / 0x800) * sizeof(unsigned long),
GFP_KERNEL);
if (!shmems)
return;
- iomem = kzalloc(((0x10000-0xa0000) / 0x800) * sizeof(void __iomem *),
+ iomem = kzalloc(((0x100000-0xa0000) / 0x800) * sizeof(void __iomem *),
GFP_KERNEL);
if (!iomem) {
kfree(shmems);
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 964c09644832..770e6b6cec60 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -69,8 +69,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.55"
-#define DRV_MODULE_RELDATE "Mar 27, 2006"
+#define DRV_MODULE_VERSION "3.56"
+#define DRV_MODULE_RELDATE "Apr 1, 2006"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -497,40 +497,33 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
unsigned long flags;
spin_lock_irqsave(&tp->indirect_lock, flags);
- if (tp->write32 != tg3_write_indirect_reg32) {
- tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off);
- tw32_f(TG3PCI_MEM_WIN_DATA, val);
+ pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+ pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
- /* Always leave this as zero. */
- tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0);
- } else {
- pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
- pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
-
- /* Always leave this as zero. */
- pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
- }
+ /* Always leave this as zero. */
+ pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
spin_unlock_irqrestore(&tp->indirect_lock, flags);
}
+static void tg3_write_mem_fast(struct tg3 *tp, u32 off, u32 val)
+{
+ /* If no workaround is needed, write to mem space directly */
+ if (tp->write32 != tg3_write_indirect_reg32)
+ tw32(NIC_SRAM_WIN_BASE + off, val);
+ else
+ tg3_write_mem(tp, off, val);
+}
+
static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
{
unsigned long flags;
spin_lock_irqsave(&tp->indirect_lock, flags);
- if (tp->write32 != tg3_write_indirect_reg32) {
- tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off);
- *val = tr32(TG3PCI_MEM_WIN_DATA);
+ pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+ pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
- /* Always leave this as zero. */
- tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0);
- } else {
- pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
- pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
-
- /* Always leave this as zero. */
- pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
- }
+ /* Always leave this as zero. */
+ pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
spin_unlock_irqrestore(&tp->indirect_lock, flags);
}
@@ -1374,12 +1367,12 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
}
}
- tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
-
/* Finally, set the new power state. */
pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
udelay(100); /* Delay after power state change */
+ tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
+
return 0;
}
@@ -6547,11 +6540,11 @@ static void tg3_timer(unsigned long __opaque)
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
u32 val;
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
- FWCMD_NICDRV_ALIVE2);
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
+ tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_MBOX,
+ FWCMD_NICDRV_ALIVE2);
+ tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
/* 5 seconds timeout */
- tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
+ tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
val = tr32(GRC_RX_CPU_EVENT);
val |= (1 << 14);
tw32(GRC_RX_CPU_EVENT, val);
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 1350e47b0234..f6bdef82a322 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -142,6 +142,12 @@ struct xt_counters_info
#define ASSERT_WRITE_LOCK(x)
#include <linux/netfilter_ipv4/listhelp.h>
+#ifdef CONFIG_COMPAT
+#define COMPAT_TO_USER 1
+#define COMPAT_FROM_USER -1
+#define COMPAT_CALC_SIZE 0
+#endif
+
struct xt_match
{
struct list_head list;
@@ -175,6 +181,9 @@ struct xt_match
void (*destroy)(const struct xt_match *match, void *matchinfo,
unsigned int matchinfosize);
+ /* Called when userspace align differs from kernel space one */
+ int (*compat)(void *match, void **dstptr, int *size, int convert);
+
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me;
@@ -220,6 +229,9 @@ struct xt_target
void (*destroy)(const struct xt_target *target, void *targinfo,
unsigned int targinfosize);
+ /* Called when userspace align differs from kernel space one */
+ int (*compat)(void *target, void **dstptr, int *size, int convert);
+
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me;
@@ -314,6 +326,61 @@ extern void xt_proto_fini(int af);
extern struct xt_table_info *xt_alloc_table_info(unsigned int size);
extern void xt_free_table_info(struct xt_table_info *info);
+#ifdef CONFIG_COMPAT
+#include <net/compat.h>
+
+struct compat_xt_entry_match
+{
+ union {
+ struct {
+ u_int16_t match_size;
+ char name[XT_FUNCTION_MAXNAMELEN - 1];
+ u_int8_t revision;
+ } user;
+ u_int16_t match_size;
+ } u;
+ unsigned char data[0];
+};
+
+struct compat_xt_entry_target
+{
+ union {
+ struct {
+ u_int16_t target_size;
+ char name[XT_FUNCTION_MAXNAMELEN - 1];
+ u_int8_t revision;
+ } user;
+ u_int16_t target_size;
+ } u;
+ unsigned char data[0];
+};
+
+/* FIXME: this works only on 32 bit tasks
+ * need to change whole approach in order to calculate align as function of
+ * current task alignment */
+
+struct compat_xt_counters
+{
+ u_int32_t cnt[4];
+};
+
+struct compat_xt_counters_info
+{
+ char name[XT_TABLE_MAXNAMELEN];
+ compat_uint_t num_counters;
+ struct compat_xt_counters counters[0];
+};
+
+#define COMPAT_XT_ALIGN(s) (((s) + (__alignof__(struct compat_xt_counters)-1)) \
+ & ~(__alignof__(struct compat_xt_counters)-1))
+
+extern void xt_compat_lock(int af);
+extern void xt_compat_unlock(int af);
+extern int xt_compat_match(void *match, void **dstptr, int *size, int convert);
+extern int xt_compat_target(void *target, void **dstptr, int *size,
+ int convert);
+
+#endif /* CONFIG_COMPAT */
#endif /* __KERNEL__ */
#endif /* _X_TABLES_H */
diff --git a/include/linux/netfilter/xt_esp.h b/include/linux/netfilter/xt_esp.h
new file mode 100644
index 000000000000..9380fb1c27da
--- /dev/null
+++ b/include/linux/netfilter/xt_esp.h
@@ -0,0 +1,14 @@
+#ifndef _XT_ESP_H
+#define _XT_ESP_H
+
+struct xt_esp
+{
+ u_int32_t spis[2]; /* Security Parameter Index */
+ u_int8_t invflags; /* Inverse flags */
+};
+
+/* Values for "invflags" field in struct xt_esp. */
+#define XT_ESP_INV_SPI 0x01 /* Invert the sense of spi. */
+#define XT_ESP_INV_MASK 0x01 /* All possible flags. */
+
+#endif /*_XT_ESP_H*/
diff --git a/include/linux/netfilter/xt_multiport.h b/include/linux/netfilter/xt_multiport.h
new file mode 100644
index 000000000000..d49ee4183710
--- /dev/null
+++ b/include/linux/netfilter/xt_multiport.h
@@ -0,0 +1,30 @@
+#ifndef _XT_MULTIPORT_H
+#define _XT_MULTIPORT_H
+
+enum xt_multiport_flags
+{
+ XT_MULTIPORT_SOURCE,
+ XT_MULTIPORT_DESTINATION,
+ XT_MULTIPORT_EITHER
+};
+
+#define XT_MULTI_PORTS 15
+
+/* Must fit inside union xt_matchinfo: 16 bytes */
+struct xt_multiport
+{
+ u_int8_t flags; /* Type of comparison */
+ u_int8_t count; /* Number of ports */
+ u_int16_t ports[XT_MULTI_PORTS]; /* Ports */
+};
+
+struct xt_multiport_v1
+{
+ u_int8_t flags; /* Type of comparison */
+ u_int8_t count; /* Number of ports */
+ u_int16_t ports[XT_MULTI_PORTS]; /* Ports */
+ u_int8_t pflags[XT_MULTI_PORTS]; /* Port flags */
+ u_int8_t invert; /* Invert flag */
+};
+
+#endif /*_XT_MULTIPORT_H*/
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
index d5b8c0d6a12b..c0dac16e1902 100644
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -316,5 +316,23 @@ extern unsigned int ipt_do_table(struct sk_buff **pskb,
void *userdata);
#define IPT_ALIGN(s) XT_ALIGN(s)
+
+#ifdef CONFIG_COMPAT
+#include <net/compat.h>
+
+struct compat_ipt_entry
+{
+ struct ipt_ip ip;
+ compat_uint_t nfcache;
+ u_int16_t target_offset;
+ u_int16_t next_offset;
+ compat_uint_t comefrom;
+ struct compat_xt_counters counters;
+ unsigned char elems[0];
+};
+
+#define COMPAT_IPT_ALIGN(s) COMPAT_XT_ALIGN(s)
+
+#endif /* CONFIG_COMPAT */
#endif /*__KERNEL__*/
#endif /* _IPTABLES_H */
diff --git a/include/linux/netfilter_ipv4/ipt_esp.h b/include/linux/netfilter_ipv4/ipt_esp.h
index c782a83e53e0..78296e7eeff9 100644
--- a/include/linux/netfilter_ipv4/ipt_esp.h
+++ b/include/linux/netfilter_ipv4/ipt_esp.h
@@ -1,16 +1,10 @@
#ifndef _IPT_ESP_H
#define _IPT_ESP_H
-struct ipt_esp
-{
- u_int32_t spis[2]; /* Security Parameter Index */
- u_int8_t invflags; /* Inverse flags */
-};
+#include <linux/netfilter/xt_esp.h>
-
-
-/* Values for "invflags" field in struct ipt_esp. */
-#define IPT_ESP_INV_SPI 0x01 /* Invert the sense of spi. */
-#define IPT_ESP_INV_MASK 0x01 /* All possible flags. */
+#define ipt_esp xt_esp
+#define IPT_ESP_INV_SPI XT_ESP_INV_SPI
+#define IPT_ESP_INV_MASK XT_ESP_INV_MASK
#endif /*_IPT_ESP_H*/
diff --git a/include/linux/netfilter_ipv4/ipt_multiport.h b/include/linux/netfilter_ipv4/ipt_multiport.h
index e6b6fff811df..55fe85eca88c 100644
--- a/include/linux/netfilter_ipv4/ipt_multiport.h
+++ b/include/linux/netfilter_ipv4/ipt_multiport.h
@@ -1,30 +1,15 @@
#ifndef _IPT_MULTIPORT_H
#define _IPT_MULTIPORT_H
-#include <linux/netfilter_ipv4/ip_tables.h>
-enum ipt_multiport_flags
-{
- IPT_MULTIPORT_SOURCE,
- IPT_MULTIPORT_DESTINATION,
- IPT_MULTIPORT_EITHER
-};
+#include <linux/netfilter/xt_multiport.h>
-#define IPT_MULTI_PORTS 15
+#define IPT_MULTIPORT_SOURCE XT_MULTIPORT_SOURCE
+#define IPT_MULTIPORT_DESTINATION XT_MULTIPORT_DESTINATION
+#define IPT_MULTIPORT_EITHER XT_MULTIPORT_EITHER
-/* Must fit inside union ipt_matchinfo: 16 bytes */
-struct ipt_multiport
-{
- u_int8_t flags; /* Type of comparison */
- u_int8_t count; /* Number of ports */
- u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */
-};
+#define IPT_MULTI_PORTS XT_MULTI_PORTS
+
+#define ipt_multiport xt_multiport
+#define ipt_multiport_v1 xt_multiport_v1
-struct ipt_multiport_v1
-{
- u_int8_t flags; /* Type of comparison */
- u_int8_t count; /* Number of ports */
- u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */
- u_int8_t pflags[IPT_MULTI_PORTS]; /* Port flags */
- u_int8_t invert; /* Invert flag */
-};
#endif /*_IPT_MULTIPORT_H*/
diff --git a/include/linux/netfilter_ipv6/ip6t_esp.h b/include/linux/netfilter_ipv6/ip6t_esp.h
index a91b6abc8079..f62eaf53c16c 100644
--- a/include/linux/netfilter_ipv6/ip6t_esp.h
+++ b/include/linux/netfilter_ipv6/ip6t_esp.h
@@ -1,14 +1,10 @@
#ifndef _IP6T_ESP_H
#define _IP6T_ESP_H
-struct ip6t_esp
-{
- u_int32_t spis[2]; /* Security Parameter Index */
- u_int8_t invflags; /* Inverse flags */
-};
+#include <linux/netfilter/xt_esp.h>
-/* Values for "invflags" field in struct ip6t_esp. */
-#define IP6T_ESP_INV_SPI 0x01 /* Invert the sense of spi. */
-#define IP6T_ESP_INV_MASK 0x01 /* All possible flags. */
+#define ip6t_esp xt_esp
+#define IP6T_ESP_INV_SPI XT_ESP_INV_SPI
+#define IP6T_ESP_INV_MASK XT_ESP_INV_MASK
#endif /*_IP6T_ESP_H*/
diff --git a/include/linux/netfilter_ipv6/ip6t_multiport.h b/include/linux/netfilter_ipv6/ip6t_multiport.h
index efe4954a8681..042c92661cee 100644
--- a/include/linux/netfilter_ipv6/ip6t_multiport.h
+++ b/include/linux/netfilter_ipv6/ip6t_multiport.h
@@ -1,21 +1,14 @@
#ifndef _IP6T_MULTIPORT_H
#define _IP6T_MULTIPORT_H
-#include <linux/netfilter_ipv6/ip6_tables.h>
-enum ip6t_multiport_flags
-{
- IP6T_MULTIPORT_SOURCE,
- IP6T_MULTIPORT_DESTINATION,
- IP6T_MULTIPORT_EITHER
-};
+#include <linux/netfilter/xt_multiport.h>
-#define IP6T_MULTI_PORTS 15
+#define IP6T_MULTIPORT_SOURCE XT_MULTIPORT_SOURCE
+#define IP6T_MULTIPORT_DESTINATION XT_MULTIPORT_DESTINATION
+#define IP6T_MULTIPORT_EITHER XT_MULTIPORT_EITHER
-/* Must fit inside union ip6t_matchinfo: 16 bytes */
-struct ip6t_multiport
-{
- u_int8_t flags; /* Type of comparison */
- u_int8_t count; /* Number of ports */
- u_int16_t ports[IP6T_MULTI_PORTS]; /* Ports */
-};
-#endif /*_IPT_MULTIPORT_H*/
+#define IP6T_MULTI_PORTS XT_MULTI_PORTS
+
+#define ip6t_multiport xt_multiport
+
+#endif /*_IP6T_MULTIPORT_H*/
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index e100291e43f4..0d5529c382e8 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -242,7 +242,6 @@ extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo);
extern void xfrm_state_delete_tunnel(struct xfrm_state *x);
-struct xfrm_decap_state;
struct xfrm_type
{
char *description;
@@ -251,7 +250,7 @@ struct xfrm_type
int (*init_state)(struct xfrm_state *x);
void (*destructor)(struct xfrm_state *);
- int (*input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb);
+ int (*input)(struct xfrm_state *, struct sk_buff *skb);
int (*output)(struct xfrm_state *, struct sk_buff *pskb);
/* Estimate maximal size of result of transformation of a dgram */
u32 (*get_max_size)(struct xfrm_state *, int size);
@@ -606,25 +605,11 @@ static inline void xfrm_dst_destroy(struct xfrm_dst *xdst)
extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev);
-/* Decapsulation state, used by the input to store data during
- * decapsulation procedure, to be used later (during the policy
- * check
- */
-struct xfrm_decap_state {
- char decap_data[20];
- __u16 decap_type;
-};
-
-struct sec_decap_state {
- struct xfrm_state *xvec;
- struct xfrm_decap_state decap;
-};
-
struct sec_path
{
atomic_t refcnt;
int len;
- struct sec_decap_state x[XFRM_MAX_DEPTH];
+ struct xfrm_state *xvec[XFRM_MAX_DEPTH];
};
static inline struct sec_path *
diff --git a/net/compat.c b/net/compat.c
index 8fd37cd7b501..d5d69fa15d07 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -476,8 +476,7 @@ asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
int err;
struct socket *sock;
- /* SO_SET_REPLACE seems to be the same in all levels */
- if (optname == IPT_SO_SET_REPLACE)
+ if (level == SOL_IPV6 && optname == IPT_SO_SET_REPLACE)
return do_netfilter_replace(fd, level, optname,
optval, optlen);
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index e16d8b42b953..e2e4771fa4c6 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -116,7 +116,7 @@ error:
return err;
}
-static int ah_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
+static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
{
int ah_hlen;
struct iphdr *iph;
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index bf88c620a954..9d1881c07a32 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -133,7 +133,7 @@ error:
* expensive, so we only support truncated data, which is the recommended
* and common case.
*/
-static int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
+static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
{
struct iphdr *iph;
struct ip_esp_hdr *esph;
@@ -208,9 +208,6 @@ static int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struc
struct xfrm_encap_tmpl *encap = x->encap;
struct udphdr *uh;
- if (encap->encap_type != decap->decap_type)
- goto out;
-
uh = (struct udphdr *)(iph + 1);
encap_len = (void*)esph - (void*)uh;
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index c95020f7c81e..0a1d86a0f632 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -81,8 +81,7 @@ out:
return err;
}
-static int ipcomp_input(struct xfrm_state *x,
- struct xfrm_decap_state *decap, struct sk_buff *skb)
+static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
{
u8 nexthdr;
int err = 0;
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 882b842c25d4..77855ccd6b43 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -221,16 +221,6 @@ config IP_NF_MATCH_IPRANGE
To compile it as a module, choose M here. If unsure, say N.
-config IP_NF_MATCH_MULTIPORT
- tristate "Multiple port match support"
- depends on IP_NF_IPTABLES
- 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 IP_NF_MATCH_TOS
tristate "TOS match support"
depends on IP_NF_IPTABLES
@@ -272,12 +262,12 @@ config IP_NF_MATCH_DSCP
To compile it as a module, choose M here. If unsure, say N.
-config IP_NF_MATCH_AH_ESP
- tristate "AH/ESP match support"
+config IP_NF_MATCH_AH
+ tristate "AH match support"
depends on IP_NF_IPTABLES
help
- These two match extensions (`ah' and `esp') allow you to match a
- range of SPIs inside AH or ESP headers of IPSec packets.
+ This match extension allows you to match a range of SPIs
+ inside AH header of IPSec packets.
To compile it as a module, choose M here. If unsure, say N.
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index f2cd9a6c5b91..461cb1eb5de7 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -53,13 +53,12 @@ obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
# matches
obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o
obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
-obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o
-obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
+obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index 9b6e19bae90f..01bd7cab9367 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -1658,7 +1658,7 @@ static void __exit ctnetlink_exit(void)
printk("ctnetlink: unregistering from nfnetlink.\n");
#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
- ip_conntrack_unregister_notifier(&ctnl_notifier_exp);
+ ip_conntrack_expect_unregister_notifier(&ctnl_notifier_exp);
ip_conntrack_unregister_notifier(&ctnl_notifier);
#endif
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 460fd905fad0..d5b8cdd361ce 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/icmp.h>
#include <net/ip.h>
+#include <net/compat.h>
#include <asm/uaccess.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
@@ -799,17 +800,11 @@ get_counters(const struct xt_table_info *t,
}
}
-static int
-copy_entries_to_user(unsigned int total_size,
- struct ipt_table *table,
- void __user *userptr)
+static inline struct xt_counters * alloc_counters(struct ipt_table *table)
{
- unsigned int off, num, countersize;
- struct ipt_entry *e;
+ unsigned int countersize;
struct xt_counters *counters;
struct xt_table_info *private = table->private;
- int ret = 0;
- void *loc_cpu_entry;
/* We need atomic snapshot of counters: rest doesn't change
(other than comefrom, which userspace doesn't care
@@ -818,13 +813,32 @@ copy_entries_to_user(unsigned int total_size,
counters = vmalloc_node(countersize, numa_node_id());
if (counters == NULL)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
/* First, sum counters... */
write_lock_bh(&table->lock);
get_counters(private, counters);
write_unlock_bh(&table->lock);
+ return counters;
+}
+
+static int
+copy_entries_to_user(unsigned int total_size,
+ struct ipt_table *table,
+ void __user *userptr)
+{
+ unsigned int off, num;
+ struct ipt_entry *e;
+ struct xt_counters *counters;
+ struct xt_table_info *private = table->private;
+ int ret = 0;
+ void *loc_cpu_entry;
+
+ counters = alloc_counters(table);
+ if (IS_ERR(counters))
+ return PTR_ERR(counters);
+
/* choose the copy that is on our node/cpu, ...
* This choice is lazy (because current thread is
* allowed to migrate to another cpu)
@@ -884,25 +898,278 @@ copy_entries_to_user(unsigned int total_size,
return ret;
}
+#ifdef CONFIG_COMPAT
+struct compat_delta {
+ struct compat_delta *next;
+ u_int16_t offset;
+ short delta;
+};
+
+static struct compat_delta *compat_offsets = NULL;
+
+static int compat_add_offset(u_int16_t offset, short delta)
+{
+ struct compat_delta *tmp;
+
+ tmp = kmalloc(sizeof(struct compat_delta), GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+ tmp->offset = offset;
+ tmp->delta = delta;
+ if (compat_offsets) {
+ tmp->next = compat_offsets->next;
+ compat_offsets->next = tmp;
+ } else {
+ compat_offsets = tmp;
+ tmp->next = NULL;
+ }
+ return 0;
+}
+
+static void compat_flush_offsets(void)
+{
+ struct compat_delta *tmp, *next;
+
+ if (compat_offsets) {
+ for(tmp = compat_offsets; tmp; tmp = next) {
+ next = tmp->next;
+ kfree(tmp);
+ }
+ compat_offsets = NULL;
+ }
+}
+
+static short compat_calc_jump(u_int16_t offset)
+{
+ struct compat_delta *tmp;
+ short delta;
+
+ for(tmp = compat_offsets, delta = 0; tmp; tmp = tmp->next)
+ if (tmp->offset < offset)
+ delta += tmp->delta;
+ return delta;
+}
+
+struct compat_ipt_standard_target
+{
+ struct compat_xt_entry_target target;
+ compat_int_t verdict;
+};
+
+#define IPT_ST_OFFSET (sizeof(struct ipt_standard_target) - \
+ sizeof(struct compat_ipt_standard_target))
+
+struct compat_ipt_standard
+{
+ struct compat_ipt_entry entry;
+ struct compat_ipt_standard_target target;
+};
+
+static int compat_ipt_standard_fn(void *target,
+ void **dstptr, int *size, int convert)
+{
+ struct compat_ipt_standard_target compat_st, *pcompat_st;
+ struct ipt_standard_target st, *pst;
+ int ret;
+
+ ret = 0;
+ switch (convert) {
+ case COMPAT_TO_USER:
+ pst = (struct ipt_standard_target *)target;
+ memcpy(&compat_st.target, &pst->target,
+ sizeof(struct ipt_entry_target));
+ compat_st.verdict = pst->verdict;
+ if (compat_st.verdict > 0)
+ compat_st.verdict -=
+ compat_calc_jump(compat_st.verdict);
+ compat_st.target.u.user.target_size =
+ sizeof(struct compat_ipt_standard_target);
+ if (__copy_to_user(*dstptr, &compat_st,
+ sizeof(struct compat_ipt_standard_target)))
+ ret = -EFAULT;
+ *size -= IPT_ST_OFFSET;
+ *dstptr += sizeof(struct compat_ipt_standard_target);
+ break;
+ case COMPAT_FROM_USER:
+ pcompat_st =
+ (struct compat_ipt_standard_target *)target;
+ memcpy(&st.target, &pcompat_st->target,
+ sizeof(struct ipt_entry_target));
+ st.verdict = pcompat_st->verdict;
+ if (st.verdict > 0)
+ st.verdict += compat_calc_jump(st.verdict);
+ st.target.u.user.target_size =
+ sizeof(struct ipt_standard_target);
+ memcpy(*dstptr, &st,
+ sizeof(struct ipt_standard_target));
+ *size += IPT_ST_OFFSET;
+ *dstptr += sizeof(struct ipt_standard_target);
+ break;
+ case COMPAT_CALC_SIZE:
+ *size += IPT_ST_OFFSET;
+ break;
+ default:
+ ret = -ENOPROTOOPT;
+ break;
+ }
+ return ret;
+}
+
+static inline int
+compat_calc_match(struct ipt_entry_match *m, int * size)
+{
+ if (m->u.kernel.match->compat)
+ m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE);
+ else
+ xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE);
+ return 0;
+}
+
+static int compat_calc_entry(struct ipt_entry *e, struct xt_table_info *info,
+ void *base, struct xt_table_info *newinfo)
+{
+ struct ipt_entry_target *t;
+ u_int16_t entry_offset;
+ int off, i, ret;
+
+ off = 0;
+ entry_offset = (void *)e - base;
+ IPT_MATCH_ITERATE(e, compat_calc_match, &off);
+ t = ipt_get_target(e);
+ if (t->u.kernel.target->compat)
+ t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE);
+ else
+ xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE);
+ newinfo->size -= off;
+ ret = compat_add_offset(entry_offset, off);
+ if (ret)
+ return ret;
+
+ for (i = 0; i< NF_IP_NUMHOOKS; i++) {
+ if (info->hook_entry[i] && (e < (struct ipt_entry *)
+ (base + info->hook_entry[i])))
+ newinfo->hook_entry[i] -= off;
+ if (info->underflow[i] && (e < (struct ipt_entry *)
+ (base + info->underflow[i])))
+ newinfo->underflow[i] -= off;
+ }
+ return 0;
+}
+
+static int compat_table_info(struct xt_table_info *info,
+ struct xt_table_info *newinfo)
+{
+ void *loc_cpu_entry;
+ int i;
+
+ if (!newinfo || !info)
+ return -EINVAL;
+
+ memset(newinfo, 0, sizeof(struct xt_table_info));
+ newinfo->size = info->size;
+ newinfo->number = info->number;
+ for (i = 0; i < NF_IP_NUMHOOKS; i++) {
+ newinfo->hook_entry[i] = info->hook_entry[i];
+ newinfo->underflow[i] = info->underflow[i];
+ }
+ loc_cpu_entry = info->entries[raw_smp_processor_id()];
+ return IPT_ENTRY_ITERATE(loc_cpu_entry, info->size,
+ compat_calc_entry, info, loc_cpu_entry, newinfo);
+}
+#endif
+
+static int get_info(void __user *user, int *len, int compat)
+{
+ char name[IPT_TABLE_MAXNAMELEN];
+ struct ipt_table *t;
+ int ret;
+
+ if (*len != sizeof(struct ipt_getinfo)) {
+ duprintf("length %u != %u\n", *len,
+ (unsigned int)sizeof(struct ipt_getinfo));
+ return -EINVAL;
+ }
+
+ if (copy_from_user(name, user, sizeof(name)) != 0)
+ return -EFAULT;
+
+ name[IPT_TABLE_MAXNAMELEN-1] = '\0';
+#ifdef CONFIG_COMPAT
+ if (compat)
+ xt_compat_lock(AF_INET);
+#endif
+ t = try_then_request_module(xt_find_table_lock(AF_INET, name),
+ "iptable_%s", name);
+ if (t && !IS_ERR(t)) {
+ struct ipt_getinfo info;
+ struct xt_table_info *private = t->private;
+
+#ifdef CONFIG_COMPAT
+ if (compat) {
+ struct xt_table_info tmp;
+ ret = compat_table_info(private, &tmp);
+ compat_flush_offsets();
+ private = &tmp;
+ }
+#endif
+ info.valid_hooks = t->valid_hooks;
+ memcpy(info.hook_entry, private->hook_entry,
+ sizeof(info.hook_entry));
+ memcpy(info.underflow, private->underflow,
+ sizeof(info.underflow));
+ info.num_entries = private->number;
+ info.size = private->size;
+ strcpy(info.name, name);
+
+ if (copy_to_user(user, &info, *len) != 0)
+ ret = -EFAULT;
+ else
+ ret = 0;
+
+ xt_table_unlock(t);
+ module_put(t->me);
+ } else
+ ret = t ? PTR_ERR(t) : -ENOENT;
+#ifdef CONFIG_COMPAT
+ if (compat)
+ xt_compat_unlock(AF_INET);
+#endif
+ return ret;
+}
+
static int
-get_entries(const struct ipt_get_entries *entries,
- struct ipt_get_entries __user *uptr)
+get_entries(struct ipt_get_entries __user *uptr, int *len)
{
int ret;
+ struct ipt_get_entries get;
struct ipt_table *t;
- t = xt_find_table_lock(AF_INET, entries->name);
+ if (*len < sizeof(get)) {
+ duprintf("get_entries: %u < %d\n", *len,
+ (unsigned int)sizeof(get));
+ return -EINVAL;
+ }
+ if (copy_from_user(&get, uptr, sizeof(get)) != 0)
+ return -EFAULT;
+ if (*len != sizeof(struct ipt_get_entries) + get.size) {
+ duprintf("get_entries: %u != %u\n", *len,
+ (unsigned int)(sizeof(struct ipt_get_entries) +
+ get.size));
+ return -EINVAL;
+ }
+
+ t = xt_find_table_lock(AF_INET, get.name);
if (t && !IS_ERR(t)) {
struct xt_table_info *private = t->private;
duprintf("t->private->number = %u\n",
private->number);
- if (entries->size == private->size)
+ if (get.size == private->size)
ret = copy_entries_to_user(private->size,
t, uptr->entrytable);
else {
duprintf("get_entries: I've got %u not %u!\n",
private->size,
- entries->size);
+ get.size);
ret = -EINVAL;
}
module_put(t->me);
@@ -914,79 +1181,47 @@ get_entries(const struct ipt_get_entries *entries,
}
static int
-do_replace(void __user *user, unsigned int len)
+__do_replace(const char *name, unsigned int valid_hooks,
+ struct xt_table_info *newinfo, unsigned int num_counters,
+ void __user *counters_ptr)
{
int ret;
- struct ipt_replace tmp;
struct ipt_table *t;
- struct xt_table_info *newinfo, *oldinfo;
+ struct xt_table_info *oldinfo;
struct xt_counters *counters;
- void *loc_cpu_entry, *loc_cpu_old_entry;
+ void *loc_cpu_old_entry;
- if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
- return -EFAULT;
-
- /* Hack: Causes ipchains to give correct error msg --RR */
- if (len != sizeof(tmp) + tmp.size)
- return -ENOPROTOOPT;
-
- /* overflow check */
- if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
- SMP_CACHE_BYTES)
- return -ENOMEM;
- if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
- return -ENOMEM;
-
- newinfo = xt_alloc_table_info(tmp.size);
- if (!newinfo)
- return -ENOMEM;
-
- /* choose the copy that is our node/cpu */
- loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
- if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
- tmp.size) != 0) {
- ret = -EFAULT;
- goto free_newinfo;
- }
-
- counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters));
+ ret = 0;
+ counters = vmalloc(num_counters * sizeof(struct xt_counters));
if (!counters) {
ret = -ENOMEM;
- goto free_newinfo;
+ goto out;
}
- ret = translate_table(tmp.name, tmp.valid_hooks,
- newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
- tmp.hook_entry, tmp.underflow);
- if (ret != 0)
- goto free_newinfo_counters;
-
- duprintf("ip_tables: Translated table\n");
-
- t = try_then_request_module(xt_find_table_lock(AF_INET, tmp.name),
- "iptable_%s", tmp.name);
+ t = try_then_request_module(xt_find_table_lock(AF_INET, name),
+ "iptable_%s", name);
if (!t || IS_ERR(t)) {
ret = t ? PTR_ERR(t) : -ENOENT;
goto free_newinfo_counters_untrans;
}
/* You lied! */
- if (tmp.valid_hooks != t->valid_hooks) {
+ if (valid_hooks != t->valid_hooks) {
duprintf("Valid hook crap: %08X vs %08X\n",
- tmp.valid_hooks, t->valid_hooks);
+ valid_hooks, t->valid_hooks);
ret = -EINVAL;
goto put_module;
}
- oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret);
+ oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
if (!oldinfo)
goto put_module;
/* Update module usage count based on number of rules */
duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
oldinfo->number, oldinfo->initial_entries, newinfo->number);
- if ((oldinfo->number > oldinfo->initial_entries) ||
- (newinfo->number <= oldinfo->initial_entries))
+ if ((oldinfo->number > oldinfo->initial_entries) ||
+ (newinfo->number <= oldinfo->initial_entries))
module_put(t->me);
if ((oldinfo->number > oldinfo->initial_entries) &&
(newinfo->number <= oldinfo->initial_entries))
@@ -998,8 +1233,8 @@ do_replace(void __user *user, unsigned int len)
loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
xt_free_table_info(oldinfo);
- if (copy_to_user(tmp.counters, counters,
- sizeof(struct xt_counters) * tmp.num_counters) != 0)
+ if (copy_to_user(counters_ptr, counters,
+ sizeof(struct xt_counters) * num_counters) != 0)
ret = -EFAULT;
vfree(counters);
xt_table_unlock(t);
@@ -1009,9 +1244,62 @@ do_replace(void __user *user, unsigned int len)
module_put(t->me);
xt_table_unlock(t);
free_newinfo_counters_untrans:
- IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
- free_newinfo_counters:
vfree(counters);
+ out:
+ return ret;
+}
+
+static int
+do_replace(void __user *user, unsigned int len)
+{
+ int ret;
+ struct ipt_replace tmp;
+ struct xt_table_info *newinfo;
+ void *loc_cpu_entry;
+
+ if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
+ return -EFAULT;
+
+ /* Hack: Causes ipchains to give correct error msg --RR */
+ if (len != sizeof(tmp) + tmp.size)
+ return -ENOPROTOOPT;
+
+ /* overflow check */
+ if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
+ SMP_CACHE_BYTES)
+ return -ENOMEM;
+ if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
+ return -ENOMEM;
+
+ newinfo = xt_alloc_table_info(tmp.size);
+ if (!newinfo)
+ return -ENOMEM;
+
+ /* choose the copy that is our node/cpu */
+ loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
+ if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
+ tmp.size) != 0) {
+ ret = -EFAULT;
+ goto free_newinfo;
+ }
+
+ ret = translate_table(tmp.name, tmp.valid_hooks,
+ newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
+ tmp.hook_entry, tmp.underflow);
+ if (ret != 0)
+ goto free_newinfo;
+
+ duprintf("ip_tables: Translated table\n");
+
+ ret = __do_replace(tmp.name, tmp.valid_hooks,
+ newinfo, tmp.num_counters,
+ tmp.counters);
+ if (ret)
+ goto free_newinfo_untrans;
+ return 0;
+
+ free_newinfo_untrans:
+ IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
free_newinfo:
xt_free_table_info(newinfo);
return ret;
@@ -1040,31 +1328,59 @@ add_counter_to_entry(struct ipt_entry *e,
}
static int
-do_add_counters(void __user *user, unsigned int len)
+do_add_counters(void __user *user, unsigned int len, int compat)
{
unsigned int i;
- struct xt_counters_info tmp, *paddc;
+ struct xt_counters_info tmp;
+ struct xt_counters *paddc;
+ unsigned int num_counters;
+ char *name;
+ int size;
+ void *ptmp;
struct ipt_table *t;
struct xt_table_info *private;
int ret = 0;
void *loc_cpu_entry;
+#ifdef CONFIG_COMPAT
+ struct compat_xt_counters_info compat_tmp;
- if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
+ if (compat) {
+ ptmp = &compat_tmp;
+ size = sizeof(struct compat_xt_counters_info);
+ } else
+#endif
+ {
+ ptmp = &tmp;
+ size = sizeof(struct xt_counters_info);
+ }
+
+ if (copy_from_user(ptmp, user, size) != 0)
return -EFAULT;
- if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters))
+#ifdef CONFIG_COMPAT
+ if (compat) {
+ num_counters = compat_tmp.num_counters;
+ name = compat_tmp.name;
+ } else
+#endif
+ {
+ num_counters = tmp.num_counters;
+ name = tmp.name;
+ }
+
+ if (len != size + num_counters * sizeof(struct xt_counters))
return -EINVAL;
- paddc = vmalloc_node(len, numa_node_id());
+ paddc = vmalloc_node(len - size, numa_node_id());
if (!paddc)
return -ENOMEM;
- if (copy_from_user(paddc, user, len) != 0) {
+ if (copy_from_user(paddc, user + size, len - size) != 0) {
ret = -EFAULT;
goto free;
}
- t = xt_find_table_lock(AF_INET, tmp.name);
+ t = xt_find_table_lock(AF_INET, name);
if (!t || IS_ERR(t)) {
ret = t ? PTR_ERR(t) : -ENOENT;
goto free;
@@ -1072,7 +1388,7 @@ do_add_counters(void __user *user, unsigned int len)
write_lock_bh(&t->lock);
private = t->private;
- if (private->number != paddc->num_counters) {
+ if (private->number != num_counters) {
ret = -EINVAL;
goto unlock_up_free;
}
@@ -1083,7 +1399,7 @@ do_add_counters(void __user *user, unsigned int len)
IPT_ENTRY_ITERATE(loc_cpu_entry,
private->size,
add_counter_to_entry,
- paddc->counters,
+ paddc,
&i);
unlock_up_free:
write_unlock_bh(&t->lock);
@@ -1095,8 +1411,438 @@ do_add_counters(void __user *user, unsigned int len)
return ret;
}
+#ifdef CONFIG_COMPAT
+struct compat_ipt_replace {
+ char name[IPT_TABLE_MAXNAMELEN];
+ u32 valid_hooks;
+ u32 num_entries;
+ u32 size;
+ u32 hook_entry[NF_IP_NUMHOOKS];
+ u32 underflow[NF_IP_NUMHOOKS];
+ u32 num_counters;
+ compat_uptr_t counters; /* struct ipt_counters * */
+ struct compat_ipt_entry entries[0];
+};
+
+static inline int compat_copy_match_to_user(struct ipt_entry_match *m,
+ void __user **dstptr, compat_uint_t *size)
+{
+ if (m->u.kernel.match->compat)
+ return m->u.kernel.match->compat(m, dstptr, size,
+ COMPAT_TO_USER);
+ else
+ return xt_compat_match(m, dstptr, size, COMPAT_TO_USER);
+}
+
+static int compat_copy_entry_to_user(struct ipt_entry *e,
+ void __user **dstptr, compat_uint_t *size)
+{
+ struct ipt_entry_target __user *t;
+ struct compat_ipt_entry __user *ce;
+ u_int16_t target_offset, next_offset;
+ compat_uint_t origsize;
+ int ret;
+
+ ret = -EFAULT;
+ origsize = *size;
+ ce = (struct compat_ipt_entry __user *)*dstptr;
+ if (__copy_to_user(ce, e, sizeof(struct ipt_entry)))
+ goto out;
+
+ *dstptr += sizeof(struct compat_ipt_entry);
+ ret = IPT_MATCH_ITERATE(e, compat_copy_match_to_user, dstptr, size);
+ target_offset = e->target_offset - (origsize - *size);
+ if (ret)
+ goto out;
+ t = ipt_get_target(e);
+ if (t->u.kernel.target->compat)
+ ret = t->u.kernel.target->compat(t, dstptr, size,
+ COMPAT_TO_USER);
+ else
+ ret = xt_compat_target(t, dstptr, size, COMPAT_TO_USER);
+ if (ret)
+ goto out;
+ ret = -EFAULT;
+ next_offset = e->next_offset - (origsize - *size);
+ if (__put_user(target_offset, &ce->target_offset))
+ goto out;
+ if (__put_user(next_offset, &ce->next_offset))
+ goto out;
+ return 0;
+out:
+ return ret;
+}
+
+static inline int
+compat_check_calc_match(struct ipt_entry_match *m,
+ const char *name,
+ const struct ipt_ip *ip,
+ unsigned int hookmask,
+ int *size, int *i)
+{
+ struct ipt_match *match;
+
+ match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
+ m->u.user.revision),
+ "ipt_%s", m->u.user.name);
+ if (IS_ERR(match) || !match) {
+ duprintf("compat_check_calc_match: `%s' not found\n",
+ m->u.user.name);
+ return match ? PTR_ERR(match) : -ENOENT;
+ }
+ m->u.kernel.match = match;
+
+ if (m->u.kernel.match->compat)
+ m->u.kernel.match->compat(m, NULL, size, COMPAT_CALC_SIZE);
+ else
+ xt_compat_match(m, NULL, size, COMPAT_CALC_SIZE);
+
+ (*i)++;
+ return 0;
+}
+
+static inline int
+check_compat_entry_size_and_hooks(struct ipt_entry *e,
+ struct xt_table_info *newinfo,
+ unsigned int *size,
+ unsigned char *base,
+ unsigned char *limit,
+ unsigned int *hook_entries,
+ unsigned int *underflows,
+ unsigned int *i,
+ const char *name)
+{
+ struct ipt_entry_target *t;
+ struct ipt_target *target;
+ u_int16_t entry_offset;
+ int ret, off, h, j;
+
+ duprintf("check_compat_entry_size_and_hooks %p\n", e);
+ if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0
+ || (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) {
+ duprintf("Bad offset %p, limit = %p\n", e, limit);
+ return -EINVAL;
+ }
+
+ if (e->next_offset < sizeof(struct compat_ipt_entry) +
+ sizeof(struct compat_xt_entry_target)) {
+ duprintf("checking: element %p size %u\n",
+ e, e->next_offset);
+ return -EINVAL;
+ }
+
+ if (!ip_checkentry(&e->ip)) {
+ duprintf("ip_tables: ip check failed %p %s.\n", e, name);
+ return -EINVAL;
+ }
+
+ off = 0;
+ entry_offset = (void *)e - (void *)base;
+ j = 0;
+ ret = IPT_MATCH_ITERATE(e, compat_check_calc_match, name, &e->ip,
+ e->comefrom, &off, &j);
+ if (ret != 0)
+ goto out;
+
+ t = ipt_get_target(e);
+ target = try_then_request_module(xt_find_target(AF_INET,
+ t->u.user.name,
+ t->u.user.revision),
+ "ipt_%s", t->u.user.name);
+ if (IS_ERR(target) || !target) {
+ duprintf("check_entry: `%s' not found\n", t->u.user.name);
+ ret = target ? PTR_ERR(target) : -ENOENT;
+ goto out;
+ }
+ t->u.kernel.target = target;
+
+ if (t->u.kernel.target->compat)
+ t->u.kernel.target->compat(t, NULL, &off, COMPAT_CALC_SIZE);
+ else
+ xt_compat_target(t, NULL, &off, COMPAT_CALC_SIZE);
+ *size += off;
+ ret = compat_add_offset(entry_offset, off);
+ if (ret)
+ goto out;
+
+ /* Check hooks & underflows */
+ for (h = 0; h < NF_IP_NUMHOOKS; h++) {
+ if ((unsigned char *)e - base == hook_entries[h])
+ newinfo->hook_entry[h] = hook_entries[h];
+ if ((unsigned char *)e - base == underflows[h])
+ newinfo->underflow[h] = underflows[h];
+ }
+
+ /* Clear counters and comefrom */
+ e->counters = ((struct ipt_counters) { 0, 0 });
+ e->comefrom = 0;
+
+ (*i)++;
+ return 0;
+out:
+ IPT_MATCH_ITERATE(e, cleanup_match, &j);
+ return ret;
+}
+
+static inline int compat_copy_match_from_user(struct ipt_entry_match *m,
+ void **dstptr, compat_uint_t *size, const char *name,
+ const struct ipt_ip *ip, unsigned int hookmask)
+{
+ struct ipt_entry_match *dm;
+ struct ipt_match *match;
+ int ret;
+
+ dm = (struct ipt_entry_match *)*dstptr;
+ match = m->u.kernel.match;
+ if (match->compat)
+ match->compat(m, dstptr, size, COMPAT_FROM_USER);
+ else
+ xt_compat_match(m, dstptr, size, COMPAT_FROM_USER);
+
+ ret = xt_check_match(match, AF_INET, dm->u.match_size - sizeof(*dm),
+ name, hookmask, ip->proto,
+ ip->invflags & IPT_INV_PROTO);
+ if (ret)
+ return ret;
+
+ if (m->u.kernel.match->checkentry
+ && !m->u.kernel.match->checkentry(name, ip, match, dm->data,
+ dm->u.match_size - sizeof(*dm),
+ hookmask)) {
+ duprintf("ip_tables: check failed for `%s'.\n",
+ m->u.kernel.match->name);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int compat_copy_entry_from_user(struct ipt_entry *e, void **dstptr,
+ unsigned int *size, const char *name,
+ struct xt_table_info *newinfo, unsigned char *base)
+{
+ struct ipt_entry_target *t;
+ struct ipt_target *target;
+ struct ipt_entry *de;
+ unsigned int origsize;
+ int ret, h;
+
+ ret = 0;
+ origsize = *size;
+ de = (struct ipt_entry *)*dstptr;
+ memcpy(de, e, sizeof(struct ipt_entry));
+
+ *dstptr += sizeof(struct compat_ipt_entry);
+ ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
+ name, &de->ip, de->comefrom);
+ if (ret)
+ goto out;
+ de->target_offset = e->target_offset - (origsize - *size);
+ t = ipt_get_target(e);
+ target = t->u.kernel.target;
+ if (target->compat)
+ target->compat(t, dstptr, size, COMPAT_FROM_USER);
+ else
+ xt_compat_target(t, dstptr, size, COMPAT_FROM_USER);
+
+ de->next_offset = e->next_offset - (origsize - *size);
+ for (h = 0; h < NF_IP_NUMHOOKS; h++) {
+ if ((unsigned char *)de - base < newinfo->hook_entry[h])
+ newinfo->hook_entry[h] -= origsize - *size;
+ if ((unsigned char *)de - base < newinfo->underflow[h])
+ newinfo->underflow[h] -= origsize - *size;
+ }
+
+ t = ipt_get_target(de);
+ target = t->u.kernel.target;
+ ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t),
+ name, e->comefrom, e->ip.proto,
+ e->ip.invflags & IPT_INV_PROTO);
+ if (ret)
+ goto out;
+
+ ret = -EINVAL;
+ if (t->u.kernel.target == &ipt_standard_target) {
+ if (!standard_check(t, *size))
+ goto out;
+ } else if (t->u.kernel.target->checkentry
+ && !t->u.kernel.target->checkentry(name, de, target,
+ t->data, t->u.target_size - sizeof(*t),
+ de->comefrom)) {
+ duprintf("ip_tables: compat: check failed for `%s'.\n",
+ t->u.kernel.target->name);
+ goto out;
+ }
+ ret = 0;
+out:
+ return ret;
+}
+
static int
-do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
+translate_compat_table(const char *name,
+ unsigned int valid_hooks,
+ struct xt_table_info **pinfo,
+ void **pentry0,
+ unsigned int total_size,
+ unsigned int number,
+ unsigned int *hook_entries,
+ unsigned int *underflows)
+{
+ unsigned int i;
+ struct xt_table_info *newinfo, *info;
+ void *pos, *entry0, *entry1;
+ unsigned int size;
+ int ret;
+
+ info = *pinfo;
+ entry0 = *pentry0;
+ size = total_size;
+ info->number = number;
+
+ /* Init all hooks to impossible value. */
+ for (i = 0; i < NF_IP_NUMHOOKS; i++) {
+ info->hook_entry[i] = 0xFFFFFFFF;
+ info->underflow[i] = 0xFFFFFFFF;
+ }
+
+ duprintf("translate_compat_table: size %u\n", info->size);
+ i = 0;
+ xt_compat_lock(AF_INET);
+ /* Walk through entries, checking offsets. */
+ ret = IPT_ENTRY_ITERATE(entry0, total_size,
+ check_compat_entry_size_and_hooks,
+ info, &size, entry0,
+ entry0 + total_size,
+ hook_entries, underflows, &i, name);
+ if (ret != 0)
+ goto out_unlock;
+
+ ret = -EINVAL;
+ if (i != number) {
+ duprintf("translate_compat_table: %u not %u entries\n",
+ i, number);
+ goto out_unlock;
+ }
+
+ /* Check hooks all assigned */
+ for (i = 0; i < NF_IP_NUMHOOKS; i++) {
+ /* Only hooks which are valid */
+ if (!(valid_hooks & (1 << i)))
+ continue;
+ if (info->hook_entry[i] == 0xFFFFFFFF) {
+ duprintf("Invalid hook entry %u %u\n",
+ i, hook_entries[i]);
+ goto out_unlock;
+ }
+ if (info->underflow[i] == 0xFFFFFFFF) {
+ duprintf("Invalid underflow %u %u\n",
+ i, underflows[i]);
+ goto out_unlock;
+ }
+ }
+
+ ret = -ENOMEM;
+ newinfo = xt_alloc_table_info(size);
+ if (!newinfo)
+ goto out_unlock;
+
+ newinfo->number = number;
+ for (i = 0; i < NF_IP_NUMHOOKS; i++) {
+ newinfo->hook_entry[i] = info->hook_entry[i];
+ newinfo->underflow[i] = info->underflow[i];
+ }
+ entry1 = newinfo->entries[raw_smp_processor_id()];
+ pos = entry1;
+ size = total_size;
+ ret = IPT_ENTRY_ITERATE(entry0, total_size,
+ compat_copy_entry_from_user, &pos, &size,
+ name, newinfo, entry1);
+ compat_flush_offsets();
+ xt_compat_unlock(AF_INET);
+ if (ret)
+ goto free_newinfo;
+
+ ret = -ELOOP;
+ if (!mark_source_chains(newinfo, valid_hooks, entry1))
+ goto free_newinfo;
+
+ /* And one copy for every other CPU */
+ for_each_cpu(i)
+ if (newinfo->entries[i] && newinfo->entries[i] != entry1)
+ memcpy(newinfo->entries[i], entry1, newinfo->size);
+
+ *pinfo = newinfo;
+ *pentry0 = entry1;
+ xt_free_table_info(info);
+ return 0;
+
+free_newinfo:
+ xt_free_table_info(newinfo);
+out:
+ return ret;
+out_unlock:
+ xt_compat_unlock(AF_INET);
+ goto out;
+}
+
+static int
+compat_do_replace(void __user *user, unsigned int len)
+{
+ int ret;
+ struct compat_ipt_replace tmp;
+ struct xt_table_info *newinfo;
+ void *loc_cpu_entry;
+
+ if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
+ return -EFAULT;
+
+ /* Hack: Causes ipchains to give correct error msg --RR */
+ if (len != sizeof(tmp) + tmp.size)
+ return -ENOPROTOOPT;
+
+ /* overflow check */
+ if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
+ SMP_CACHE_BYTES)
+ return -ENOMEM;
+ if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
+ return -ENOMEM;
+
+ newinfo = xt_alloc_table_info(tmp.size);
+ if (!newinfo)
+ return -ENOMEM;
+
+ /* choose the copy that is our node/cpu */
+ loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
+ if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
+ tmp.size) != 0) {
+ ret = -EFAULT;
+ goto free_newinfo;
+ }
+
+ ret = translate_compat_table(tmp.name, tmp.valid_hooks,
+ &newinfo, &loc_cpu_entry, tmp.size,
+ tmp.num_entries, tmp.hook_entry, tmp.underflow);
+ if (ret != 0)
+ goto free_newinfo;
+
+ duprintf("compat_do_replace: Translated table\n");
+
+ ret = __do_replace(tmp.name, tmp.valid_hooks,
+ newinfo, tmp.num_counters,
+ compat_ptr(tmp.counters));
+ if (ret)
+ goto free_newinfo_untrans;
+ return 0;
+
+ free_newinfo_untrans:
+ IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
+ free_newinfo:
+ xt_free_table_info(newinfo);
+ return ret;
+}
+
+static int
+compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
+ unsigned int len)
{
int ret;
@@ -1105,11 +1851,11 @@ do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
switch (cmd) {
case IPT_SO_SET_REPLACE:
- ret = do_replace(user, len);
+ ret = compat_do_replace(user, len);
break;
case IPT_SO_SET_ADD_COUNTERS:
- ret = do_add_counters(user, len);
+ ret = do_add_counters(user, len, 1);
break;
default:
@@ -1120,75 +1866,196 @@ do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
return ret;
}
+struct compat_ipt_get_entries
+{
+ char name[IPT_TABLE_MAXNAMELEN];
+ compat_uint_t size;
+ struct compat_ipt_entry entrytable[0];
+};
+
+static int compat_copy_entries_to_user(unsigned int total_size,
+ struct ipt_table *table, void __user *userptr)
+{
+ unsigned int off, num;
+ struct compat_ipt_entry e;
+ struct xt_counters *counters;
+ struct xt_table_info *private = table->private;
+ void __user *pos;
+ unsigned int size;
+ int ret = 0;
+ void *loc_cpu_entry;
+
+ counters = alloc_counters(table);
+ if (IS_ERR(counters))
+ return PTR_ERR(counters);
+
+ /* choose the copy that is on our node/cpu, ...
+ * This choice is lazy (because current thread is
+ * allowed to migrate to another cpu)
+ */
+ loc_cpu_entry = private->entries[raw_smp_processor_id()];
+ pos = userptr;
+ size = total_size;
+ ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
+ compat_copy_entry_to_user, &pos, &size);
+ if (ret)
+ goto free_counters;
+
+ /* ... then go back and fix counters and names */
+ for (off = 0, num = 0; off < size; off += e.next_offset, num++) {
+ unsigned int i;
+ struct ipt_entry_match m;
+ struct ipt_entry_target t;
+
+ ret = -EFAULT;
+ if (copy_from_user(&e, userptr + off,
+ sizeof(struct compat_ipt_entry)))
+ goto free_counters;
+ if (copy_to_user(userptr + off +
+ offsetof(struct compat_ipt_entry, counters),
+ &counters[num], sizeof(counters[num])))
+ goto free_counters;
+
+ for (i = sizeof(struct compat_ipt_entry);
+ i < e.target_offset; i += m.u.match_size) {
+ if (copy_from_user(&m, userptr + off + i,
+ sizeof(struct ipt_entry_match)))
+ goto free_counters;
+ if (copy_to_user(userptr + off + i +
+ offsetof(struct ipt_entry_match, u.user.name),
+ m.u.kernel.match->name,
+ strlen(m.u.kernel.match->name) + 1))
+ goto free_counters;
+ }
+
+ if (copy_from_user(&t, userptr + off + e.target_offset,
+ sizeof(struct ipt_entry_target)))
+ goto free_counters;
+ if (copy_to_user(userptr + off + e.target_offset +
+ offsetof(struct ipt_entry_target, u.user.name),
+ t.u.kernel.target->name,
+ strlen(t.u.kernel.target->name) + 1))
+ goto free_counters;
+ }
+ ret = 0;
+free_counters:
+ vfree(counters);
+ return ret;
+}
+
static int
-do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
+compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
{
int ret;
+ struct compat_ipt_get_entries get;
+ struct ipt_table *t;
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- switch (cmd) {
- case IPT_SO_GET_INFO: {
- char name[IPT_TABLE_MAXNAMELEN];
- struct ipt_table *t;
+ if (*len < sizeof(get)) {
+ duprintf("compat_get_entries: %u < %u\n",
+ *len, (unsigned int)sizeof(get));
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&get, uptr, sizeof(get)) != 0)
+ return -EFAULT;
+
+ if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
+ duprintf("compat_get_entries: %u != %u\n", *len,
+ (unsigned int)(sizeof(struct compat_ipt_get_entries) +
+ get.size));
+ return -EINVAL;
+ }
- if (*len != sizeof(struct ipt_getinfo)) {
- duprintf("length %u != %u\n", *len,
- sizeof(struct ipt_getinfo));
+ xt_compat_lock(AF_INET);
+ t = xt_find_table_lock(AF_INET, get.name);
+ if (t && !IS_ERR(t)) {
+ struct xt_table_info *private = t->private;
+ struct xt_table_info info;
+ duprintf("t->private->number = %u\n",
+ private->number);
+ ret = compat_table_info(private, &info);
+ if (!ret && get.size == info.size) {
+ ret = compat_copy_entries_to_user(private->size,
+ t, uptr->entrytable);
+ } else if (!ret) {
+ duprintf("compat_get_entries: I've got %u not %u!\n",
+ private->size,
+ get.size);
ret = -EINVAL;
- break;
}
+ compat_flush_offsets();
+ module_put(t->me);
+ xt_table_unlock(t);
+ } else
+ ret = t ? PTR_ERR(t) : -ENOENT;
- if (copy_from_user(name, user, sizeof(name)) != 0) {
- ret = -EFAULT;
- break;
- }
- name[IPT_TABLE_MAXNAMELEN-1] = '\0';
-
- t = try_then_request_module(xt_find_table_lock(AF_INET, name),
- "iptable_%s", name);
- if (t && !IS_ERR(t)) {
- struct ipt_getinfo info;
- struct xt_table_info *private = t->private;
-
- info.valid_hooks = t->valid_hooks;
- memcpy(info.hook_entry, private->hook_entry,
- sizeof(info.hook_entry));
- memcpy(info.underflow, private->underflow,
- sizeof(info.underflow));
- info.num_entries = private->number;
- info.size = private->size;
- memcpy(info.name, name, sizeof(info.name));
-
- if (copy_to_user(user, &info, *len) != 0)
- ret = -EFAULT;
- else
- ret = 0;
- xt_table_unlock(t);
- module_put(t->me);
- } else
- ret = t ? PTR_ERR(t) : -ENOENT;
+ xt_compat_unlock(AF_INET);
+ return ret;
+}
+
+static int
+compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
+{
+ int ret;
+
+ switch (cmd) {
+ case IPT_SO_GET_INFO:
+ ret = get_info(user, len, 1);
+ break;
+ case IPT_SO_GET_ENTRIES:
+ ret = compat_get_entries(user, len);
+ break;
+ default:
+ duprintf("compat_do_ipt_get_ctl: unknown request %i\n", cmd);
+ ret = -EINVAL;
}
- break;
+ return ret;
+}
+#endif
- case IPT_SO_GET_ENTRIES: {
- struct ipt_get_entries get;
+static int
+do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
+{
+ int ret;
- if (*len < sizeof(get)) {
- duprintf("get_entries: %u < %u\n", *len, sizeof(get));
- ret = -EINVAL;
- } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
- ret = -EFAULT;
- } else if (*len != sizeof(struct ipt_get_entries) + get.size) {
- duprintf("get_entries: %u != %u\n", *len,
- sizeof(struct ipt_get_entries) + get.size);
- ret = -EINVAL;
- } else
- ret = get_entries(&get, user);
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ switch (cmd) {
+ case IPT_SO_SET_REPLACE:
+ ret = do_replace(user, len);
break;
+
+ case IPT_SO_SET_ADD_COUNTERS:
+ ret = do_add_counters(user, len, 0);
+ break;
+
+ default:
+ duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
+ ret = -EINVAL;
}
+ return ret;
+}
+
+static int
+do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
+{
+ int ret;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ switch (cmd) {
+ case IPT_SO_GET_INFO:
+ ret = get_info(user, len, 0);
+ break;
+
+ case IPT_SO_GET_ENTRIES:
+ ret = get_entries(user, len);
+ break;
+
case IPT_SO_GET_REVISION_MATCH:
case IPT_SO_GET_REVISION_TARGET: {
struct ipt_get_revision rev;
@@ -1336,6 +2203,9 @@ static struct ipt_target ipt_standard_target = {
.name = IPT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = AF_INET,
+#ifdef CONFIG_COMPAT
+ .compat = &compat_ipt_standard_fn,
+#endif
};
static struct ipt_target ipt_error_target = {
@@ -1350,9 +2220,15 @@ static struct nf_sockopt_ops ipt_sockopts = {
.set_optmin = IPT_BASE_CTL,
.set_optmax = IPT_SO_SET_MAX+1,
.set = do_ipt_set_ctl,
+#ifdef CONFIG_COMPAT
+ .compat_set = compat_do_ipt_set_ctl,
+#endif
.get_optmin = IPT_BASE_CTL,
.get_optmax = IPT_SO_GET_MAX+1,
.get = do_ipt_get_ctl,
+#ifdef CONFIG_COMPAT
+ .compat_get = compat_do_ipt_get_ctl,
+#endif
};
static struct ipt_match icmp_matchstruct = {
diff --git a/net/ipv4/netfilter/ipt_multiport.c b/net/ipv4/netfilter/ipt_multiport.c
deleted file mode 100644
index ac95d8390bcc..000000000000
--- a/net/ipv4/netfilter/ipt_multiport.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/* 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/netfilter_ipv4/ipt_multiport.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
-MODULE_DESCRIPTION("iptables multiple port match module");
-
-#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 ipt_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 != IPT_MULTIPORT_DESTINATION
- && portlist[i] == src)
- return 1;
-
- if (flags != IPT_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 ipt_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 == IPT_MULTIPORT_SOURCE
- && src >= s && src <= e)
- return 1 ^ minfo->invert;
- if (minfo->flags == IPT_MULTIPORT_DESTINATION
- && dst >= s && dst <= e)
- return 1 ^ minfo->invert;
- if (minfo->flags == IPT_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 == IPT_MULTIPORT_SOURCE
- && src == s)
- return 1 ^ minfo->invert;
- if (minfo->flags == IPT_MULTIPORT_DESTINATION
- && dst == s)
- return 1 ^ minfo->invert;
- if (minfo->flags == IPT_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 ipt_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("ipt_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 ipt_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("ipt_multiport:"
- " Dropping evil offset=0 tinygram.\n");
- *hotdrop = 1;
- return 0;
- }
-
- return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1]));
-}
-
-static struct ipt_match multiport_match = {
- .name = "multiport",
- .revision = 0,
- .match = match,
- .matchsize = sizeof(struct ipt_multiport),
- .me = THIS_MODULE,
-};
-
-static struct ipt_match multiport_match_v1 = {
- .name = "multiport",
- .revision = 1,
- .match = match_v1,
- .matchsize = sizeof(struct ipt_multiport_v1),
- .me = THIS_MODULE,
-};
-
-static int __init ipt_multiport_init(void)
-{
- int err;
-
- err = ipt_register_match(&multiport_match);
- if (!err) {
- err = ipt_register_match(&multiport_match_v1);
- if (err)
- ipt_unregister_match(&multiport_match);
- }
-
- return err;
-}
-
-static void __exit ipt_multiport_fini(void)
-{
- ipt_unregister_match(&multiport_match);
- ipt_unregister_match(&multiport_match_v1);
-}
-
-module_init(ipt_multiport_init);
-module_exit(ipt_multiport_fini);
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index 850d919591d1..e1b8f4b90d80 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -68,7 +68,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
{
int err;
u32 spi, seq;
- struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH];
+ struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
struct xfrm_state *x;
int xfrm_nr = 0;
int decaps = 0;
@@ -90,14 +90,16 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
if (unlikely(x->km.state != XFRM_STATE_VALID))
goto drop_unlock;
+ if (x->encap->encap_type != encap_type)
+ goto drop_unlock;
+
if (x->props.replay_window && xfrm_replay_check(x, seq))
goto drop_unlock;
if (xfrm_state_check_expire(x))
goto drop_unlock;
- xfrm_vec[xfrm_nr].decap.decap_type = encap_type;
- if (x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb))
+ if (x->type->input(x, skb))
goto drop_unlock;
/* only the first xfrm gets the encap type */
@@ -111,7 +113,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
spin_unlock(&x->lock);
- xfrm_vec[xfrm_nr++].xvec = x;
+ xfrm_vec[xfrm_nr++] = x;
iph = skb->nh.iph;
@@ -153,7 +155,8 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
goto drop;
- memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state));
+ memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec,
+ xfrm_nr * sizeof(xfrm_vec[0]));
skb->sp->len += xfrm_nr;
nf_reset(skb);
@@ -184,7 +187,7 @@ drop_unlock:
xfrm_state_put(x);
drop:
while (--xfrm_nr >= 0)
- xfrm_state_put(xfrm_vec[xfrm_nr].xvec);
+ xfrm_state_put(xfrm_vec[xfrm_nr]);
kfree_skb(skb);
return 0;
diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c
index 2d670935c2b5..f8ceaa127c83 100644
--- a/net/ipv4/xfrm4_tunnel.c
+++ b/net/ipv4/xfrm4_tunnel.c
@@ -21,7 +21,7 @@ static int ipip_output(struct xfrm_state *x, struct sk_buff *skb)
return 0;
}
-static int ipip_xfrm_rcv(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
+static int ipip_xfrm_rcv(struct xfrm_state *x, struct sk_buff *skb)
{
return 0;
}
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index cf58251df4b3..6778173a3dda 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -229,7 +229,7 @@ error:
return err;
}
-static int ah6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
+static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
{
/*
* Before process AH
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 3dcaac7a0972..22f046079037 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -130,7 +130,7 @@ error:
return err;
}
-static int esp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
+static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
{
struct ipv6hdr *iph;
struct ipv6_esp_hdr *esph;
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index d4cfec3f414e..00f3fadfcca7 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -63,7 +63,7 @@ static void **ipcomp6_scratches;
static int ipcomp6_scratch_users;
static LIST_HEAD(ipcomp6_tfms_list);
-static int ipcomp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
+static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
{
int err = 0;
u8 nexthdr = 0;
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 98f78759f1ab..4bc4e5b33794 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -87,16 +87,6 @@ config IP6_NF_MATCH_HL
To compile it as a module, choose M here. If unsure, say N.
-config IP6_NF_MATCH_MULTIPORT
- tristate "Multiple port match support"
- depends on IP6_NF_IPTABLES
- 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 IP6_NF_MATCH_OWNER
tristate "Owner match support"
depends on IP6_NF_IPTABLES
@@ -115,11 +105,11 @@ config IP6_NF_MATCH_IPV6HEADER
To compile it as a module, choose M here. If unsure, say N.
-config IP6_NF_MATCH_AHESP
- tristate "AH/ESP match support"
+config IP6_NF_MATCH_AH
+ tristate "AH match support"
depends on IP6_NF_IPTABLES
help
- This module allows one to match AH and ESP packets.
+ This module allows one to match AH packets.
To compile it as a module, choose M here. If unsure, say N.
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index 8436a1a1731f..eeeb57d4c9c5 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -8,9 +8,8 @@ obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
-obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o
+obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
-obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
diff --git a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c
deleted file mode 100644
index 36bedad2c6f7..000000000000
--- a/net/ipv6/netfilter/ip6t_esp.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/* Kernel module to match ESP parameters. */
-/* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu>
- *
- * 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/ip.h>
-#include <linux/ipv6.h>
-#include <linux/types.h>
-#include <net/checksum.h>
-#include <net/ipv6.h>
-
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <linux/netfilter_ipv6/ip6t_esp.h>
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("IPv6 ESP match");
-MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
-
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(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;
- DEBUGP("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
- min,spi,max);
- r=(spi >= min && spi <= max) ^ invert;
- DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
- 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 ip6t_esp *espinfo = matchinfo;
- unsigned int ptr;
-
- /* Make sure this isn't an evil packet */
- /*DEBUGP("ipv6_esp entered \n");*/
-
- if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ESP, NULL) < 0)
- return 0;
-
- eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp);
- if (eh == NULL) {
- *hotdrop = 1;
- return 0;
- }
-
- DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(eh->spi), ntohl(eh->spi));
-
- return (eh != NULL)
- && spi_match(espinfo->spis[0], espinfo->spis[1],
- ntohl(eh->spi),
- !!(espinfo->invflags & IP6T_ESP_INV_SPI));
-}
-
-/* Called when user tries to insert an entry of this type. */
-static int
-checkentry(const char *tablename,
- const void *ip,
- const struct xt_match *match,
- void *matchinfo,
- unsigned int matchinfosize,
- unsigned int hook_mask)
-{
- const struct ip6t_esp *espinfo = matchinfo;
-
- if (espinfo->invflags & ~IP6T_ESP_INV_MASK) {
- DEBUGP("ip6t_esp: unknown flags %X\n",
- espinfo->invflags);
- return 0;
- }
- return 1;
-}
-
-static struct ip6t_match esp_match = {
- .name = "esp",
- .match = match,
- .matchsize = sizeof(struct ip6t_esp),
- .checkentry = checkentry,
- .me = THIS_MODULE,
-};
-
-static int __init ip6t_esp_init(void)
-{
- return ip6t_register_match(&esp_match);
-}
-
-static void __exit ip6t_esp_fini(void)
-{
- ip6t_unregister_match(&esp_match);
-}
-
-module_init(ip6t_esp_init);
-module_exit(ip6t_esp_fini);
diff --git a/net/ipv6/netfilter/ip6t_multiport.c b/net/ipv6/netfilter/ip6t_multiport.c
deleted file mode 100644
index 10c48ba596d6..000000000000
--- a/net/ipv6/netfilter/ip6t_multiport.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/* 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_ipv6/ip6t_multiport.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
-MODULE_DESCRIPTION("ip6tables match for multiple ports");
-
-#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 ip6t_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 != IP6T_MULTIPORT_DESTINATION
- && portlist[i] == src)
- return 1;
-
- if (flags != IP6T_MULTIPORT_SOURCE
- && portlist[i] == dst)
- return 1;
- }
-
- return 0;
-}
-
-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 ip6t_multiport *multiinfo = matchinfo;
-
- /* Must not be a fragment. */
- if (offset)
- return 0;
-
- /* Must be big enough to read ports (both UDP and TCP have
- them at the start). */
- pptr = skb_header_pointer(skb, protoff, sizeof(_ports), &_ports[0]);
- if (pptr == NULL) {
- /* We've been asked to examine this packet, and we
- * can't. Hence, no choice but to drop.
- */
- duprintf("ip6t_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]));
-}
-
-/* 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 ip6t_ip6 *ip = info;
- const struct ip6t_multiport *multiinfo = matchinfo;
-
- /* Must specify proto == TCP/UDP, no unknown flags or bad count */
- return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
- && !(ip->invflags & IP6T_INV_PROTO)
- && (multiinfo->flags == IP6T_MULTIPORT_SOURCE
- || multiinfo->flags == IP6T_MULTIPORT_DESTINATION
- || multiinfo->flags == IP6T_MULTIPORT_EITHER)
- && multiinfo->count <= IP6T_MULTI_PORTS;
-}
-
-static struct ip6t_match multiport_match = {
- .name = "multiport",
- .match = match,
- .matchsize = sizeof(struct ip6t_multiport),
- .checkentry = checkentry,
- .me = THIS_MODULE,
-};
-
-static int __init ip6t_multiport_init(void)
-{
- return ip6t_register_match(&multiport_match);
-}
-
-static void __exit ip6t_multiport_fini(void)
-{
- ip6t_unregister_match(&multiport_match);
-}
-
-module_init(ip6t_multiport_init);
-module_exit(ip6t_multiport_fini);
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index cccf8b76f046..00cfdee18dca 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -32,7 +32,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
{
int err;
u32 seq;
- struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH];
+ struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
struct xfrm_state *x;
int xfrm_nr = 0;
int decaps = 0;
@@ -65,7 +65,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
if (xfrm_state_check_expire(x))
goto drop_unlock;
- nexthdr = x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb);
+ nexthdr = x->type->input(x, skb);
if (nexthdr <= 0)
goto drop_unlock;
@@ -79,7 +79,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
spin_unlock(&x->lock);
- xfrm_vec[xfrm_nr++].xvec = x;
+ xfrm_vec[xfrm_nr++] = x;
if (x->props.mode) { /* XXX */
if (nexthdr != IPPROTO_IPV6)
@@ -118,7 +118,8 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
goto drop;
- memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state));
+ memcpy(skb->sp->xvec + skb->sp->len, xfrm_vec,
+ xfrm_nr * sizeof(xfrm_vec[0]));
skb->sp->len += xfrm_nr;
skb->ip_summed = CHECKSUM_NONE;
@@ -149,7 +150,7 @@ drop_unlock:
xfrm_state_put(x);
drop:
while (--xfrm_nr >= 0)
- xfrm_state_put(xfrm_vec[xfrm_nr].xvec);
+ xfrm_state_put(xfrm_vec[xfrm_nr]);
kfree_skb(skb);
return -1;
}
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index a8f6776c518d..d37768e5064f 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -351,7 +351,7 @@ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
return 0;
}
-static int xfrm6_tunnel_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
+static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
{
return 0;
}
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 332acb37b385..e2893effdfaa 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 9558727f5e79..95b7e416512d 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/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 0e0e9d7b34c8..bd10eb944b65 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/x_tables.c b/net/netfilter/x_tables.c
index a657ab5394c3..feb8a9e066b0 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;
@@ -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,
@@ -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/ipv4/netfilter/ipt_esp.c b/net/netfilter/xt_esp.c
index 3840b417a3c5..9dad6281e0c1 100644
--- a/net/ipv4/netfilter/ipt_esp.c
+++ b/net/netfilter/xt_esp.c
@@ -9,16 +9,22 @@
#include <linux/module.h>
#include <linux/skbuff.h>
+#include <linux/in.h>
#include <linux/ip.h>
-#include <linux/netfilter_ipv4/ipt_esp.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("iptables ESP SPI match module");
+MODULE_DESCRIPTION("x_tables ESP SPI match module");
+MODULE_ALIAS("ipt_esp");
+MODULE_ALIAS("ip6t_esp");
-#ifdef DEBUG_CONNTRACK
+#if 0
#define duprintf(format, args...) printk(format , ## args)
#else
#define duprintf(format, args...)
@@ -28,11 +34,11 @@ MODULE_DESCRIPTION("iptables ESP SPI match module");
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");
+ 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;
}
@@ -47,14 +53,13 @@ match(const struct sk_buff *skb,
int *hotdrop)
{
struct ip_esp_hdr _esp, *eh;
- const struct ipt_esp *espinfo = matchinfo;
+ const struct xt_esp *espinfo = matchinfo;
/* Must not be a fragment. */
if (offset)
return 0;
- eh = skb_header_pointer(skb, protoff,
- sizeof(_esp), &_esp);
+ 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.
@@ -64,9 +69,8 @@ match(const struct sk_buff *skb,
return 0;
}
- return spi_match(espinfo->spis[0], espinfo->spis[1],
- ntohl(eh->spi),
- !!(espinfo->invflags & IPT_ESP_INV_SPI));
+ 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. */
@@ -78,34 +82,55 @@ checkentry(const char *tablename,
unsigned int matchinfosize,
unsigned int hook_mask)
{
- const struct ipt_esp *espinfo = matchinfo;
+ const struct xt_esp *espinfo = matchinfo;
- /* Must specify no unknown invflags */
- if (espinfo->invflags & ~IPT_ESP_INV_MASK) {
- duprintf("ipt_esp: unknown flags %X\n", espinfo->invflags);
+ if (espinfo->invflags & ~XT_ESP_INV_MASK) {
+ duprintf("xt_esp: unknown flags %X\n", espinfo->invflags);
return 0;
}
+
return 1;
}
-static struct ipt_match esp_match = {
+static struct xt_match esp_match = {
.name = "esp",
- .match = match,
- .matchsize = sizeof(struct ipt_esp),
+ .family = AF_INET,
.proto = IPPROTO_ESP,
- .checkentry = checkentry,
+ .match = &match,
+ .matchsize = sizeof(struct xt_esp),
+ .checkentry = &checkentry,
.me = THIS_MODULE,
};
-static int __init ipt_esp_init(void)
+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)
{
- return ipt_register_match(&esp_match);
+ 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 ipt_esp_fini(void)
+static void __exit xt_esp_cleanup(void)
{
- ipt_unregister_match(&esp_match);
+ xt_unregister_match(&esp_match);
+ xt_unregister_match(&esp6_match);
}
-module_init(ipt_esp_init);
-module_exit(ipt_esp_fini);
+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 000000000000..b56cd2baaac2
--- /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 1099cb005fcc..a3aa62fbda6f 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)
diff --git a/net/socket.c b/net/socket.c
index b13042f68c02..b807f360e02c 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1418,7 +1418,8 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _
newfd = sock_alloc_fd(&newfile);
if (unlikely(newfd < 0)) {
err = newfd;
- goto out_release;
+ sock_release(newsock);
+ goto out_put;
}
err = sock_attach_fd(newsock, newfile);
@@ -1455,10 +1456,8 @@ out_put:
out:
return err;
out_fd:
- put_filp(newfile);
+ fput(newfile);
put_unused_fd(newfd);
-out_release:
- sock_release(newsock);
goto out_put;
}
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 2407a7072327..b54971059f16 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -18,7 +18,7 @@ void __secpath_destroy(struct sec_path *sp)
{
int i;
for (i = 0; i < sp->len; i++)
- xfrm_state_put(sp->x[i].xvec);
+ xfrm_state_put(sp->xvec[i]);
kmem_cache_free(secpath_cachep, sp);
}
EXPORT_SYMBOL(__secpath_destroy);
@@ -37,7 +37,7 @@ struct sec_path *secpath_dup(struct sec_path *src)
memcpy(sp, src, sizeof(*sp));
for (i = 0; i < sp->len; i++)
- xfrm_state_hold(sp->x[i].xvec);
+ xfrm_state_hold(sp->xvec[i]);
}
atomic_set(&sp->refcnt, 1);
return sp;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index f5eae9febd26..c3725fe2a8fb 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -943,9 +943,9 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start,
} else
start = -1;
for (; idx < sp->len; idx++) {
- if (xfrm_state_ok(tmpl, sp->x[idx].xvec, family))
+ if (xfrm_state_ok(tmpl, sp->xvec[idx], family))
return ++idx;
- if (sp->x[idx].xvec->props.mode)
+ if (sp->xvec[idx]->props.mode)
break;
}
return start;
@@ -968,7 +968,7 @@ EXPORT_SYMBOL(xfrm_decode_session);
static inline int secpath_has_tunnel(struct sec_path *sp, int k)
{
for (; k < sp->len; k++) {
- if (sp->x[k].xvec->props.mode)
+ if (sp->xvec[k]->props.mode)
return 1;
}
@@ -994,8 +994,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
int i;
for (i=skb->sp->len-1; i>=0; i--) {
- struct sec_decap_state *xvec = &(skb->sp->x[i]);
- if (!xfrm_selector_match(&xvec->xvec->sel, &fl, family))
+ struct xfrm_state *x = skb->sp->xvec[i];
+ if (!xfrm_selector_match(&x->sel, &fl, family))
return 0;
}
}