Commit bacd3add authored by Linus Torvalds's avatar Linus Torvalds

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"
parents 29e35094 9a1875e6
...@@ -125,11 +125,11 @@ static void __init com90xx_probe(void) ...@@ -125,11 +125,11 @@ static void __init com90xx_probe(void)
if (!io && !irq && !shmem && !*device && com90xx_skip_probe) if (!io && !irq && !shmem && !*device && com90xx_skip_probe)
return; return;
shmems = kzalloc(((0x10000-0xa0000) / 0x800) * sizeof(unsigned long), shmems = kzalloc(((0x100000-0xa0000) / 0x800) * sizeof(unsigned long),
GFP_KERNEL); GFP_KERNEL);
if (!shmems) if (!shmems)
return; return;
iomem = kzalloc(((0x10000-0xa0000) / 0x800) * sizeof(void __iomem *), iomem = kzalloc(((0x100000-0xa0000) / 0x800) * sizeof(void __iomem *),
GFP_KERNEL); GFP_KERNEL);
if (!iomem) { if (!iomem) {
kfree(shmems); kfree(shmems);
......
...@@ -69,8 +69,8 @@ ...@@ -69,8 +69,8 @@
#define DRV_MODULE_NAME "tg3" #define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": " #define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "3.55" #define DRV_MODULE_VERSION "3.56"
#define DRV_MODULE_RELDATE "Mar 27, 2006" #define DRV_MODULE_RELDATE "Apr 1, 2006"
#define TG3_DEF_MAC_MODE 0 #define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0 #define TG3_DEF_RX_MODE 0
...@@ -497,40 +497,33 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) ...@@ -497,40 +497,33 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&tp->indirect_lock, flags); spin_lock_irqsave(&tp->indirect_lock, flags);
if (tp->write32 != tg3_write_indirect_reg32) { pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off); pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
tw32_f(TG3PCI_MEM_WIN_DATA, val);
/* Always leave this as zero. */ /* Always leave this as zero. */
tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0); pci_write_config_dword(tp->pdev, 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);
}
spin_unlock_irqrestore(&tp->indirect_lock, flags); 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) static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&tp->indirect_lock, flags); spin_lock_irqsave(&tp->indirect_lock, flags);
if (tp->write32 != tg3_write_indirect_reg32) { pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off); pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
*val = tr32(TG3PCI_MEM_WIN_DATA);
/* Always leave this as zero. */ /* Always leave this as zero. */
tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0); pci_write_config_dword(tp->pdev, 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);
}
spin_unlock_irqrestore(&tp->indirect_lock, flags); spin_unlock_irqrestore(&tp->indirect_lock, flags);
} }
...@@ -1374,12 +1367,12 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) ...@@ -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. */ /* Finally, set the new power state. */
pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control); pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
udelay(100); /* Delay after power state change */ udelay(100); /* Delay after power state change */
tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
return 0; return 0;
} }
...@@ -6547,11 +6540,11 @@ static void tg3_timer(unsigned long __opaque) ...@@ -6547,11 +6540,11 @@ static void tg3_timer(unsigned long __opaque)
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
u32 val; u32 val;
tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_MBOX,
FWCMD_NICDRV_ALIVE2); FWCMD_NICDRV_ALIVE2);
tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
/* 5 seconds timeout */ /* 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 = tr32(GRC_RX_CPU_EVENT);
val |= (1 << 14); val |= (1 << 14);
tw32(GRC_RX_CPU_EVENT, val); tw32(GRC_RX_CPU_EVENT, val);
......
...@@ -142,6 +142,12 @@ struct xt_counters_info ...@@ -142,6 +142,12 @@ struct xt_counters_info
#define ASSERT_WRITE_LOCK(x) #define ASSERT_WRITE_LOCK(x)
#include <linux/netfilter_ipv4/listhelp.h> #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 xt_match
{ {
struct list_head list; struct list_head list;
...@@ -175,6 +181,9 @@ struct xt_match ...@@ -175,6 +181,9 @@ struct xt_match
void (*destroy)(const struct xt_match *match, void *matchinfo, void (*destroy)(const struct xt_match *match, void *matchinfo,
unsigned int matchinfosize); 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 */ /* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me; struct module *me;
...@@ -220,6 +229,9 @@ struct xt_target ...@@ -220,6 +229,9 @@ struct xt_target
void (*destroy)(const struct xt_target *target, void *targinfo, void (*destroy)(const struct xt_target *target, void *targinfo,
unsigned int targinfosize); 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 */ /* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me; struct module *me;
...@@ -314,6 +326,61 @@ extern void xt_proto_fini(int af); ...@@ -314,6 +326,61 @@ extern void xt_proto_fini(int af);
extern struct xt_table_info *xt_alloc_table_info(unsigned int size); extern struct xt_table_info *xt_alloc_table_info(unsigned int size);
extern void xt_free_table_info(struct xt_table_info *info); 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 /* __KERNEL__ */
#endif /* _X_TABLES_H */ #endif /* _X_TABLES_H */
#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*/
#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*/
...@@ -316,5 +316,23 @@ extern unsigned int ipt_do_table(struct sk_buff **pskb, ...@@ -316,5 +316,23 @@ extern unsigned int ipt_do_table(struct sk_buff **pskb,
void *userdata); void *userdata);
#define IPT_ALIGN(s) XT_ALIGN(s) #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 /*__KERNEL__*/
#endif /* _IPTABLES_H */ #endif /* _IPTABLES_H */
#ifndef _IPT_ESP_H #ifndef _IPT_ESP_H
#define _IPT_ESP_H #define _IPT_ESP_H
struct ipt_esp #include <linux/netfilter/xt_esp.h>
{
u_int32_t spis[2]; /* Security Parameter Index */
u_int8_t invflags; /* Inverse flags */
};
#define ipt_esp xt_esp
#define IPT_ESP_INV_SPI XT_ESP_INV_SPI
/* Values for "invflags" field in struct ipt_esp. */ #define IPT_ESP_INV_MASK XT_ESP_INV_MASK
#define IPT_ESP_INV_SPI 0x01 /* Invert the sense of spi. */
#define IPT_ESP_INV_MASK 0x01 /* All possible flags. */
#endif /*_IPT_ESP_H*/ #endif /*_IPT_ESP_H*/
#ifndef _IPT_MULTIPORT_H #ifndef _IPT_MULTIPORT_H
#define _IPT_MULTIPORT_H #define _IPT_MULTIPORT_H
#include <linux/netfilter_ipv4/ip_tables.h>
enum ipt_multiport_flags #include <linux/netfilter/xt_multiport.h>
{
IPT_MULTIPORT_SOURCE,
IPT_MULTIPORT_DESTINATION,
IPT_MULTIPORT_EITHER
};
#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 */ #define IPT_MULTI_PORTS XT_MULTI_PORTS
struct ipt_multiport
{ #define ipt_multiport xt_multiport
u_int8_t flags; /* Type of comparison */ #define ipt_multiport_v1 xt_multiport_v1
u_int8_t count; /* Number of ports */
u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */
};
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*/ #endif /*_IPT_MULTIPORT_H*/
#ifndef _IP6T_ESP_H #ifndef _IP6T_ESP_H
#define _IP6T_ESP_H #define _IP6T_ESP_H
struct ip6t_esp #include <linux/netfilter/xt_esp.h>
{
u_int32_t spis[2]; /* Security Parameter Index */
u_int8_t invflags; /* Inverse flags */
};
/* Values for "invflags" field in struct ip6t_esp. */ #define ip6t_esp xt_esp
#define IP6T_ESP_INV_SPI 0x01 /* Invert the sense of spi. */ #define IP6T_ESP_INV_SPI XT_ESP_INV_SPI
#define IP6T_ESP_INV_MASK 0x01 /* All possible flags. */ #define IP6T_ESP_INV_MASK XT_ESP_INV_MASK
#endif /*_IP6T_ESP_H*/ #endif /*_IP6T_ESP_H*/
#ifndef _IP6T_MULTIPORT_H #ifndef _IP6T_MULTIPORT_H
#define _IP6T_MULTIPORT_H #define _IP6T_MULTIPORT_H
#include <linux/netfilter_ipv6/ip6_tables.h>
enum ip6t_multiport_flags #include <linux/netfilter/xt_multiport.h>
{
IP6T_MULTIPORT_SOURCE,
IP6T_MULTIPORT_DESTINATION,
IP6T_MULTIPORT_EITHER
};
#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 */ #define IP6T_MULTI_PORTS XT_MULTI_PORTS
struct ip6t_multiport
{ #define ip6t_multiport xt_multiport
u_int8_t flags; /* Type of comparison */
u_int8_t count; /* Number of ports */ #endif /*_IP6T_MULTIPORT_H*/
u_int16_t ports[IP6T_MULTI_PORTS]; /* Ports */
};
#endif /*_IPT_MULTIPORT_H*/
...@@ -242,7 +242,6 @@ extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo); ...@@ -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); extern void xfrm_state_delete_tunnel(struct xfrm_state *x);
struct xfrm_decap_state;
struct xfrm_type struct xfrm_type
{ {
char *description; char *description;
...@@ -251,7 +250,7 @@ struct xfrm_type ...@@ -251,7 +250,7 @@ struct xfrm_type
int (*init_state)(struct xfrm_state *x); int (*init_state)(struct xfrm_state *x);
void (*destructor)(struct xfrm_state *); 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); int (*output)(struct xfrm_state *, struct sk_buff *pskb);
/* Estimate maximal size of result of transformation of a dgram */ /* Estimate maximal size of result of transformation of a dgram */
u32 (*get_max_size)(struct xfrm_state *, int size); u32 (*get_max_size)(struct xfrm_state *, int size);
...@@ -606,25 +605,11 @@ static inline void xfrm_dst_destroy(struct xfrm_dst *xdst) ...@@ -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); 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 struct sec_path
{ {
atomic_t refcnt; atomic_t refcnt;
int len; int len;
struct sec_decap_state x[XFRM_MAX_DEPTH]; struct xfrm_state *xvec[XFRM_MAX_DEPTH];
}; };
static inline struct sec_path * static inline struct sec_path *
......
...@@ -476,8 +476,7 @@ asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, ...@@ -476,8 +476,7 @@ asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
int err; int err;
struct socket *sock; struct socket *sock;
/* SO_SET_REPLACE seems to be the same in all levels */ if (level == SOL_IPV6 && optname == IPT_SO_SET_REPLACE)
if (optname == IPT_SO_SET_REPLACE)
return do_netfilter_replace(fd, level, optname, return do_netfilter_replace(fd, level, optname,
optval, optlen); optval, optlen);
......
...@@ -116,7 +116,7 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) ...@@ -116,7 +116,7 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
return err; 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; int ah_hlen;
struct iphdr *iph; struct iphdr *iph;
......
...@@ -133,7 +133,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) ...@@ -133,7 +133,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
* expensive, so we only support truncated data, which is the recommended * expensive, so we only support truncated data, which is the recommended
* and common case. * 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 iphdr *iph;
struct ip_esp_hdr *esph; struct ip_esp_hdr *esph;
...@@ -208,9 +208,6 @@ static int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struc ...@@ -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 xfrm_encap_tmpl *encap = x->encap;
struct udphdr *uh; struct udphdr *uh;
if (encap->encap_type != decap->decap_type)
goto out;
uh = (struct udphdr *)(iph + 1); uh = (struct udphdr *)(iph + 1);
encap_len = (void*)esph - (void*)uh; encap_len = (void*)esph - (void*)uh;
......
...@@ -81,8 +81,7 @@ static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb) ...@@ -81,8 +81,7 @@ static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
return err; return err;
} }
static int ipcomp_input(struct xfrm_state *x, static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
struct xfrm_decap_state *decap, struct sk_buff *skb)
{ {
u8 nexthdr; u8 nexthdr;
int err = 0; int err = 0;
......
...@@ -221,16 +221,6 @@ config IP_NF_MATCH_IPRANGE ...@@ -221,16 +221,6 @@ config IP_NF_MATCH_IPRANGE
To compile it as a module, choose M here. If unsure, say N. 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 config IP_NF_MATCH_TOS
tristate "TOS match support" tristate "TOS match support"
depends on IP_NF_IPTABLES depends on IP_NF_IPTABLES
...@@ -272,12 +262,12 @@ config IP_NF_MATCH_DSCP ...@@ -272,12 +262,12 @@ config IP_NF_MATCH_DSCP
To compile it as a module, choose M here. If unsure, say N. To compile it as a module, choose M here. If unsure, say N.
config IP_NF_MATCH_AH_ESP config IP_NF_MATCH_AH
tristate "AH/ESP match support" tristate "AH match support"
depends on IP_NF_IPTABLES depends on IP_NF_IPTABLES
help help
These two match extensions (`ah' and `esp') allow you to match a This match extension allows you to match a range of SPIs
range of SPIs inside AH or ESP headers of IPSec packets. inside AH header of IPSec packets.
To compile it as a module, choose M here. If unsure, say N. To compile it as a module, choose M here. If unsure, say N.
......
...@@ -53,13 +53,12 @@ obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o ...@@ -53,13 +53,12 @@ obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
# matches # matches
obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o
obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.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_OWNER) += ipt_owner.o
obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.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_TTL) += ipt_ttl.o
obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
......
...@@ -1658,7 +1658,7 @@ static void __exit ctnetlink_exit(void) ...@@ -1658,7 +1658,7 @@ static void __exit ctnetlink_exit(void)
printk("ctnetlink: unregistering from nfnetlink.\n"); printk("ctnetlink: unregistering from nfnetlink.\n");
#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS #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); ip_conntrack_unregister_notifier(&ctnl_notifier);
#endif #endif
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/icmp.h> #include <linux/icmp.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/compat.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
...@@ -799,17 +800,11 @@ get_counters(const struct xt_table_info *t, ...@@ -799,17 +800,11 @@ get_counters(const struct xt_table_info *t,
} }
} }
static int static inline struct xt_counters * alloc_counters(struct ipt_table *table)
copy_entries_to_user(unsigned int total_size,
struct ipt_table *table,
void __user *userptr)
{ {
unsigned int off, num, countersize; unsigned int countersize;
struct ipt_entry *e;
struct xt_counters *counters; struct xt_counters *counters;
struct xt_table_info *private = table->private; struct xt_table_info *private = table->private;
int ret = 0;
void *loc_cpu_entry;
/* We need atomic snapshot of counters: rest doesn't change /* We need atomic snapshot of counters: rest doesn't change
(other than comefrom, which userspace doesn't care (other than comefrom, which userspace doesn't care
...@@ -818,13 +813,32 @@ copy_entries_to_user(unsigned int total_size, ...@@ -818,13 +813,32 @@ copy_entries_to_user(unsigned int total_size,
counters = vmalloc_node(countersize, numa_node_id()); counters = vmalloc_node(countersize, numa_node_id());
if (counters == NULL) if (counters == NULL)
return -ENOMEM; return ERR_PTR(-ENOMEM);
/* First, sum counters... */ /* First, sum counters... */
write_lock_bh(&table->lock); write_lock_bh(&table->lock);
get_counters(private, counters); get_counters(private, counters);
write_unlock_bh(&table->lock); 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, ... /* choose the copy that is on our node/cpu, ...
* This choice is lazy (because current thread is * This choice is lazy (because current thread is
* allowed to migrate to another cpu) * allowed to migrate to another cpu)
...@@ -884,44 +898,899 @@ copy_entries_to_user(unsigned int total_size, ...@@ -884,44 +898,899 @@ copy_entries_to_user(unsigned int total_size,
return ret; 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(struct ipt_get_entries __user *uptr, int *len)
{
int ret;
struct ipt_get_entries get;
struct ipt_table *t;
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 (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,
get.size);
ret = -EINVAL;
}
module_put(t->me);
xt_table_unlock(t);
} else
ret = t ? PTR_ERR(t) : -ENOENT;
return ret;
}
static int
__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_table *t;
struct xt_table_info *oldinfo;
struct xt_counters *counters;
void *loc_cpu_old_entry;
ret = 0;
counters = vmalloc(num_counters * sizeof(struct xt_counters));
if (!counters) {
ret = -ENOMEM;
goto out;
}
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 (valid_hooks != t->valid_hooks) {
duprintf("Valid hook crap: %08X vs %08X\n",
valid_hooks, t->valid_hooks);
ret = -EINVAL;
goto put_module;
}
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))
module_put(t->me);
if ((oldinfo->number > oldinfo->initial_entries) &&
(newinfo->number <= oldinfo->initial_entries))
module_put(t->me);
/* Get the old counters. */
get_counters(oldinfo, counters);
/* Decrease module usage counts and free resource */
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(counters_ptr, counters,
sizeof(struct xt_counters) * num_counters) != 0)
ret = -EFAULT;
vfree(counters);
xt_table_unlock(t);
return ret;
put_module:
module_put(t->me);
xt_table_unlock(t);
free_newinfo_counters_untrans:
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;
}
/* We're lazy, and add to the first CPU; overflow works its fey magic
* and everything is OK. */
static inline int
add_counter_to_entry(struct ipt_entry *e,
const struct xt_counters addme[],
unsigned int *i)
{
#if 0
duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
*i,
(long unsigned int)e->counters.pcnt,
(long unsigned int)e->counters.bcnt,
(long unsigned int)addme[*i].pcnt,
(long unsigned int)addme[*i].bcnt);
#endif
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
(*i)++;
return 0;
}
static int
do_add_counters(void __user *user, unsigned int len, int compat)
{
unsigned int i;
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 (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;
#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 - size, numa_node_id());
if (!paddc)
return -ENOMEM;
if (copy_from_user(paddc, user + size, len - size) != 0) {
ret = -EFAULT;
goto free;
}
t = xt_find_table_lock(AF_INET, name);
if (!t || IS_ERR(t)) {
ret = t ? PTR_ERR(t) : -ENOENT;
goto free;
}
write_lock_bh(&t->lock);
private = t->private;
if (private->number != num_counters) {
ret = -EINVAL;
goto unlock_up_free;
}
i = 0;
/* Choose the copy that is on our node */
loc_cpu_entry = private->entries[raw_smp_processor_id()];
IPT_ENTRY_ITERATE(loc_cpu_entry,
private->size,
add_counter_to_entry,
paddc,
&i);
unlock_up_free:
write_unlock_bh(&t->lock);
xt_table_unlock(t);
module_put(t->me);
free:
vfree(paddc);
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 static int
get_entries(const struct ipt_get_entries *entries, translate_compat_table(const char *name,
struct ipt_get_entries __user *uptr) 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; int ret;
struct ipt_table *t;
t = xt_find_table_lock(AF_INET, entries->name); info = *pinfo;
if (t && !IS_ERR(t)) { entry0 = *pentry0;
struct xt_table_info *private = t->private; size = total_size;
duprintf("t->private->number = %u\n", info->number = number;
private->number);
if (entries->size == private->size) /* Init all hooks to impossible value. */
ret = copy_entries_to_user(private->size, for (i = 0; i < NF_IP_NUMHOOKS; i++) {
t, uptr->entrytable); info->hook_entry[i] = 0xFFFFFFFF;
else { info->underflow[i] = 0xFFFFFFFF;
duprintf("get_entries: I've got %u not %u!\n", }
private->size,
entries->size); duprintf("translate_compat_table: size %u\n", info->size);
ret = -EINVAL; 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;
} }
module_put(t->me); if (info->underflow[i] == 0xFFFFFFFF) {
xt_table_unlock(t); duprintf("Invalid underflow %u %u\n",
} else i, underflows[i]);
ret = t ? PTR_ERR(t) : -ENOENT; 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; return ret;
out_unlock:
xt_compat_unlock(AF_INET);
goto out;
} }
static int static int
do_replace(void __user *user, unsigned int len) compat_do_replace(void __user *user, unsigned int len)
{ {
int ret; int ret;
struct ipt_replace tmp; struct compat_ipt_replace tmp;
struct ipt_table *t; struct xt_table_info *newinfo;
struct xt_table_info *newinfo, *oldinfo; void *loc_cpu_entry;
struct xt_counters *counters;
void *loc_cpu_entry, *loc_cpu_old_entry;
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
return -EFAULT; return -EFAULT;
...@@ -949,151 +1818,201 @@ do_replace(void __user *user, unsigned int len) ...@@ -949,151 +1818,201 @@ do_replace(void __user *user, unsigned int len)
goto free_newinfo; goto free_newinfo;
} }
counters = vmalloc(tmp.num_counters * sizeof(struct xt_counters)); ret = translate_compat_table(tmp.name, tmp.valid_hooks,
if (!counters) { &newinfo, &loc_cpu_entry, tmp.size,
ret = -ENOMEM; tmp.num_entries, tmp.hook_entry, tmp.underflow);
if (ret != 0)
goto free_newinfo; goto free_newinfo;
}
ret = translate_table(tmp.name, tmp.valid_hooks, duprintf("compat_do_replace: Translated table\n");
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"); ret = __do_replace(tmp.name, tmp.valid_hooks,
newinfo, tmp.num_counters,
compat_ptr(tmp.counters));
if (ret)
goto free_newinfo_untrans;
return 0;
t = try_then_request_module(xt_find_table_lock(AF_INET, tmp.name), free_newinfo_untrans:
"iptable_%s", tmp.name); IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
if (!t || IS_ERR(t)) { free_newinfo:
ret = t ? PTR_ERR(t) : -ENOENT; xt_free_table_info(newinfo);
goto free_newinfo_counters_untrans; return ret;
} }
/* You lied! */ static int
if (tmp.valid_hooks != t->valid_hooks) { compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user,
duprintf("Valid hook crap: %08X vs %08X\n", unsigned int len)
tmp.valid_hooks, t->valid_hooks); {
ret = -EINVAL; int ret;
goto put_module;
}
oldinfo = xt_replace_table(t, tmp.num_counters, newinfo, &ret); if (!capable(CAP_NET_ADMIN))
if (!oldinfo) return -EPERM;
goto put_module;
/* Update module usage count based on number of rules */ switch (cmd) {
duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n", case IPT_SO_SET_REPLACE:
oldinfo->number, oldinfo->initial_entries, newinfo->number); ret = compat_do_replace(user, len);
if ((oldinfo->number > oldinfo->initial_entries) || break;
(newinfo->number <= oldinfo->initial_entries))
module_put(t->me);
if ((oldinfo->number > oldinfo->initial_entries) &&
(newinfo->number <= oldinfo->initial_entries))
module_put(t->me);
/* Get the old counters. */ case IPT_SO_SET_ADD_COUNTERS:
get_counters(oldinfo, counters); ret = do_add_counters(user, len, 1);
/* Decrease module usage counts and free resource */ break;
loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL); default:
xt_free_table_info(oldinfo); duprintf("do_ipt_set_ctl: unknown request %i\n", cmd);
if (copy_to_user(tmp.counters, counters, ret = -EINVAL;
sizeof(struct xt_counters) * tmp.num_counters) != 0) }
ret = -EFAULT;
vfree(counters);
xt_table_unlock(t);
return ret;
put_module:
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);
free_newinfo:
xt_free_table_info(newinfo);
return ret; return ret;
} }
/* We're lazy, and add to the first CPU; overflow works its fey magic struct compat_ipt_get_entries
* and everything is OK. */
static inline int
add_counter_to_entry(struct ipt_entry *e,
const struct xt_counters addme[],
unsigned int *i)
{ {
#if 0 char name[IPT_TABLE_MAXNAMELEN];
duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n", compat_uint_t size;
*i, struct compat_ipt_entry entrytable[0];
(long unsigned int)e->counters.pcnt, };
(long unsigned int)e->counters.bcnt,
(long unsigned int)addme[*i].pcnt,
(long unsigned int)addme[*i].bcnt);
#endif
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); 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;
(*i)++; counters = alloc_counters(table);
return 0; 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 static int
do_add_counters(void __user *user, unsigned int len) compat_get_entries(struct compat_ipt_get_entries __user *uptr, int *len)
{ {
unsigned int i; int ret;
struct xt_counters_info tmp, *paddc; struct compat_ipt_get_entries get;
struct ipt_table *t; struct ipt_table *t;
struct xt_table_info *private;
int ret = 0;
void *loc_cpu_entry;
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
return -EFAULT;
if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct xt_counters)) if (*len < sizeof(get)) {
duprintf("compat_get_entries: %u < %u\n",
*len, (unsigned int)sizeof(get));
return -EINVAL; return -EINVAL;
}
paddc = vmalloc_node(len, numa_node_id()); if (copy_from_user(&get, uptr, sizeof(get)) != 0)
if (!paddc) return -EFAULT;
return -ENOMEM;
if (copy_from_user(paddc, user, len) != 0) { if (*len != sizeof(struct compat_ipt_get_entries) + get.size) {
ret = -EFAULT; duprintf("compat_get_entries: %u != %u\n", *len,
goto free; (unsigned int)(sizeof(struct compat_ipt_get_entries) +
get.size));
return -EINVAL;
} }
t = xt_find_table_lock(AF_INET, tmp.name); xt_compat_lock(AF_INET);
if (!t || IS_ERR(t)) { 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;
}
compat_flush_offsets();
module_put(t->me);
xt_table_unlock(t);
} else
ret = t ? PTR_ERR(t) : -ENOENT; ret = t ? PTR_ERR(t) : -ENOENT;
goto free;
}
write_lock_bh(&t->lock); xt_compat_unlock(AF_INET);
private = t->private; return ret;
if (private->number != paddc->num_counters) { }
ret = -EINVAL;
goto unlock_up_free;
}
i = 0; static int
/* Choose the copy that is on our node */ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
loc_cpu_entry = private->entries[raw_smp_processor_id()]; {
IPT_ENTRY_ITERATE(loc_cpu_entry, int ret;
private->size,
add_counter_to_entry,
paddc->counters,
&i);
unlock_up_free:
write_unlock_bh(&t->lock);
xt_table_unlock(t);
module_put(t->me);
free:
vfree(paddc);
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;
}
return ret; return ret;
} }
#endif
static int static int
do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
...@@ -1109,7 +2028,7 @@ do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) ...@@ -1109,7 +2028,7 @@ do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
break; break;
case IPT_SO_SET_ADD_COUNTERS: case IPT_SO_SET_ADD_COUNTERS:
ret = do_add_counters(user, len); ret = do_add_counters(user, len, 0);
break; break;
default: default:
...@@ -1129,65 +2048,13 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) ...@@ -1129,65 +2048,13 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
return -EPERM; return -EPERM;
switch (cmd) { switch (cmd) {
case IPT_SO_GET_INFO: { case IPT_SO_GET_INFO:
char name[IPT_TABLE_MAXNAMELEN]; ret = get_info(user, len, 0);
struct ipt_table *t; break;
if (*len != sizeof(struct ipt_getinfo)) {
duprintf("length %u != %u\n", *len,
sizeof(struct ipt_getinfo));
ret = -EINVAL;
break;
}
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;
}
break;
case IPT_SO_GET_ENTRIES: {
struct ipt_get_entries get;
if (*len < sizeof(get)) { case IPT_SO_GET_ENTRIES:
duprintf("get_entries: %u < %u\n", *len, sizeof(get)); ret = get_entries(user, len);
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);
break; break;
}
case IPT_SO_GET_REVISION_MATCH: case IPT_SO_GET_REVISION_MATCH:
case IPT_SO_GET_REVISION_TARGET: { case IPT_SO_GET_REVISION_TARGET: {
...@@ -1336,6 +2203,9 @@ static struct ipt_target ipt_standard_target = { ...@@ -1336,6 +2203,9 @@ static struct ipt_target ipt_standard_target = {
.name = IPT_STANDARD_TARGET, .name = IPT_STANDARD_TARGET,
.targetsize = sizeof(int), .targetsize = sizeof(int),
.family = AF_INET, .family = AF_INET,
#ifdef CONFIG_COMPAT
.compat = &compat_ipt_standard_fn,
#endif
}; };
static struct ipt_target ipt_error_target = { static struct ipt_target ipt_error_target = {
...@@ -1350,9 +2220,15 @@ static struct nf_sockopt_ops ipt_sockopts = { ...@@ -1350,9 +2220,15 @@ static struct nf_sockopt_ops ipt_sockopts = {
.set_optmin = IPT_BASE_CTL, .set_optmin = IPT_BASE_CTL,
.set_optmax = IPT_SO_SET_MAX+1, .set_optmax = IPT_SO_SET_MAX+1,
.set = do_ipt_set_ctl, .set = do_ipt_set_ctl,
#ifdef CONFIG_COMPAT
.compat_set = compat_do_ipt_set_ctl,
#endif
.get_optmin = IPT_BASE_CTL, .get_optmin = IPT_BASE_CTL,
.get_optmax = IPT_SO_GET_MAX+1, .get_optmax = IPT_SO_GET_MAX+1,
.get = do_ipt_get_ctl, .get = do_ipt_get_ctl,
#ifdef CONFIG_COMPAT
.compat_get = compat_do_ipt_get_ctl,
#endif
}; };
static struct ipt_match icmp_matchstruct = { static struct ipt_match icmp_matchstruct = {
......
...@@ -68,7 +68,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) ...@@ -68,7 +68,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
{ {
int err; int err;
u32 spi, seq; u32 spi, seq;
struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH]; struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
struct xfrm_state *x; struct xfrm_state *x;
int xfrm_nr = 0; int xfrm_nr = 0;
int decaps = 0; int decaps = 0;
...@@ -90,14 +90,16 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) ...@@ -90,14 +90,16 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
if (unlikely(x->km.state != XFRM_STATE_VALID)) if (unlikely(x->km.state != XFRM_STATE_VALID))
goto drop_unlock; goto drop_unlock;
if (x->encap->encap_type != encap_type)
goto drop_unlock;
if (x->props.replay_window && xfrm_replay_check(x, seq)) if (x->props.replay_window && xfrm_replay_check(x, seq))
goto drop_unlock; goto drop_unlock;
if (xfrm_state_check_expire(x)) if (xfrm_state_check_expire(x))
goto drop_unlock; goto drop_unlock;
xfrm_vec[xfrm_nr].decap.decap_type = encap_type; if (x->type->input(x, skb))
if (x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb))
goto drop_unlock; goto drop_unlock;
/* only the first xfrm gets the encap type */ /* only the first xfrm gets the encap type */
...@@ -111,7 +113,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) ...@@ -111,7 +113,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
spin_unlock(&x->lock); spin_unlock(&x->lock);
xfrm_vec[xfrm_nr++].xvec = x; xfrm_vec[xfrm_nr++] = x;
iph = skb->nh.iph; iph = skb->nh.iph;
...@@ -153,7 +155,8 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) ...@@ -153,7 +155,8 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
goto drop; 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->sp->len += xfrm_nr;
nf_reset(skb); nf_reset(skb);
...@@ -184,7 +187,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) ...@@ -184,7 +187,7 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
xfrm_state_put(x); xfrm_state_put(x);
drop: drop:
while (--xfrm_nr >= 0) while (--xfrm_nr >= 0)
xfrm_state_put(xfrm_vec[xfrm_nr].xvec); xfrm_state_put(xfrm_vec[xfrm_nr]);
kfree_skb(skb); kfree_skb(skb);
return 0; return 0;
......
...@@ -21,7 +21,7 @@ static int ipip_output(struct xfrm_state *x, struct sk_buff *skb) ...@@ -21,7 +21,7 @@ static int ipip_output(struct xfrm_state *x, struct sk_buff *skb)
return 0; 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; return 0;
} }
......
...@@ -229,7 +229,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) ...@@ -229,7 +229,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
return err; 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 * Before process AH
......
...@@ -130,7 +130,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) ...@@ -130,7 +130,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
return err; 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 ipv6hdr *iph;
struct ipv6_esp_hdr *esph; struct ipv6_esp_hdr *esph;
......
...@@ -63,7 +63,7 @@ static void **ipcomp6_scratches; ...@@ -63,7 +63,7 @@ static void **ipcomp6_scratches;
static int ipcomp6_scratch_users; static int ipcomp6_scratch_users;
static LIST_HEAD(ipcomp6_tfms_list); 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; int err = 0;
u8 nexthdr = 0; u8 nexthdr = 0;
......
...@@ -87,16 +87,6 @@ config IP6_NF_MATCH_HL ...@@ -87,16 +87,6 @@ config IP6_NF_MATCH_HL
To compile it as a module, choose M here. If unsure, say N. 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 config IP6_NF_MATCH_OWNER
tristate "Owner match support" tristate "Owner match support"
depends on IP6_NF_IPTABLES depends on IP6_NF_IPTABLES
...@@ -115,11 +105,11 @@ config IP6_NF_MATCH_IPV6HEADER ...@@ -115,11 +105,11 @@ config IP6_NF_MATCH_IPV6HEADER
To compile it as a module, choose M here. If unsure, say N. To compile it as a module, choose M here. If unsure, say N.
config IP6_NF_MATCH_AHESP config IP6_NF_MATCH_AH
tristate "AH/ESP match support" tristate "AH match support"
depends on IP6_NF_IPTABLES depends on IP6_NF_IPTABLES
help 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. To compile it as a module, choose M here. If unsure, say N.
......
...@@ -8,9 +8,8 @@ obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o ...@@ -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_OPTS) += ip6t_hbh.o ip6t_dst.o
obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.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_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_MATCH_OWNER) += ip6t_owner.o
obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
......
/* 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);
/* 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);
...@@ -32,7 +32,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) ...@@ -32,7 +32,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
{ {
int err; int err;
u32 seq; u32 seq;
struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH]; struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
struct xfrm_state *x; struct xfrm_state *x;
int xfrm_nr = 0; int xfrm_nr = 0;
int decaps = 0; int decaps = 0;
...@@ -65,7 +65,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) ...@@ -65,7 +65,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
if (xfrm_state_check_expire(x)) if (xfrm_state_check_expire(x))
goto drop_unlock; goto drop_unlock;
nexthdr = x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb); nexthdr = x->type->input(x, skb);
if (nexthdr <= 0) if (nexthdr <= 0)
goto drop_unlock; goto drop_unlock;
...@@ -79,7 +79,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) ...@@ -79,7 +79,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
spin_unlock(&x->lock); spin_unlock(&x->lock);
xfrm_vec[xfrm_nr++].xvec = x; xfrm_vec[xfrm_nr++] = x;
if (x->props.mode) { /* XXX */ if (x->props.mode) { /* XXX */
if (nexthdr != IPPROTO_IPV6) if (nexthdr != IPPROTO_IPV6)
...@@ -118,7 +118,8 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) ...@@ -118,7 +118,8 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH) if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
goto drop; 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->sp->len += xfrm_nr;
skb->ip_summed = CHECKSUM_NONE; skb->ip_summed = CHECKSUM_NONE;
...@@ -149,7 +150,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) ...@@ -149,7 +150,7 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
xfrm_state_put(x); xfrm_state_put(x);
drop: drop:
while (--xfrm_nr >= 0) while (--xfrm_nr >= 0)
xfrm_state_put(xfrm_vec[xfrm_nr].xvec); xfrm_state_put(xfrm_vec[xfrm_nr]);
kfree_skb(skb); kfree_skb(skb);
return -1; return -1;
} }
......
...@@ -351,7 +351,7 @@ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) ...@@ -351,7 +351,7 @@ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
return 0; 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; return 0;
} }
......
...@@ -231,6 +231,15 @@ config NETFILTER_XT_MATCH_DCCP ...@@ -231,6 +231,15 @@ config NETFILTER_XT_MATCH_DCCP
If you want to compile it as a module, say M here and read If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'. <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 config NETFILTER_XT_MATCH_HELPER
tristate '"helper" match support' tristate '"helper" match support'
depends on NETFILTER_XTABLES depends on NETFILTER_XTABLES
...@@ -289,6 +298,16 @@ config NETFILTER_XT_MATCH_POLICY ...@@ -289,6 +298,16 @@ config NETFILTER_XT_MATCH_POLICY
To compile it as a module, choose M here. If unsure, say N. 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 config NETFILTER_XT_MATCH_PHYSDEV
tristate '"physdev" match support' tristate '"physdev" match support'
depends on NETFILTER_XTABLES && BRIDGE_NETFILTER depends on NETFILTER_XTABLES && BRIDGE_NETFILTER
......
...@@ -35,11 +35,13 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o ...@@ -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_CONNMARK) += xt_connmark.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.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_HELPER) += xt_helper.o
obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.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_POLICY) += xt_policy.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o obj-$(CONFIG_NETFILTER_XT_MATCH_PKTTYPE) += xt_pkttype.o
obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o obj-$(CONFIG_NETFILTER_XT_MATCH_REALM) += xt_realm.o
......
...@@ -1022,7 +1022,7 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[]) ...@@ -1022,7 +1022,7 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[])
return err; return err;
} }
#if defined(CONFIG_IP_NF_CONNTRACK_MARK) #if defined(CONFIG_NF_CONNTRACK_MARK)
if (cda[CTA_MARK-1]) if (cda[CTA_MARK-1])
ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
#endif #endif
...@@ -1062,7 +1062,7 @@ ctnetlink_create_conntrack(struct nfattr *cda[], ...@@ -1062,7 +1062,7 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
return err; return err;
} }
#if defined(CONFIG_IP_NF_CONNTRACK_MARK) #if defined(CONFIG_NF_CONNTRACK_MARK)
if (cda[CTA_MARK-1]) if (cda[CTA_MARK-1])
ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
#endif #endif
...@@ -1687,7 +1687,7 @@ static void __exit ctnetlink_exit(void) ...@@ -1687,7 +1687,7 @@ static void __exit ctnetlink_exit(void)
printk("ctnetlink: unregistering from nfnetlink.\n"); printk("ctnetlink: unregistering from nfnetlink.\n");
#ifdef CONFIG_NF_CONNTRACK_EVENTS #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); nf_conntrack_unregister_notifier(&ctnl_notifier);
#endif #endif
......
...@@ -38,6 +38,7 @@ struct xt_af { ...@@ -38,6 +38,7 @@ struct xt_af {
struct list_head match; struct list_head match;
struct list_head target; struct list_head target;
struct list_head tables; struct list_head tables;
struct mutex compat_mutex;
}; };
static struct xt_af *xt; static struct xt_af *xt;
...@@ -272,6 +273,54 @@ int xt_check_match(const struct xt_match *match, unsigned short family, ...@@ -272,6 +273,54 @@ int xt_check_match(const struct xt_match *match, unsigned short family,
} }
EXPORT_SYMBOL_GPL(xt_check_match); 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, int xt_check_target(const struct xt_target *target, unsigned short family,
unsigned int size, const char *table, unsigned int hook_mask, unsigned int size, const char *table, unsigned int hook_mask,
unsigned short proto, int inv_proto) unsigned short proto, int inv_proto)
...@@ -301,6 +350,54 @@ int xt_check_target(const struct xt_target *target, unsigned short family, ...@@ -301,6 +350,54 @@ int xt_check_target(const struct xt_target *target, unsigned short family,
} }
EXPORT_SYMBOL_GPL(xt_check_target); 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 *xt_alloc_table_info(unsigned int size)
{ {
struct xt_table_info *newinfo; struct xt_table_info *newinfo;
...@@ -371,6 +468,19 @@ void xt_table_unlock(struct xt_table *table) ...@@ -371,6 +468,19 @@ void xt_table_unlock(struct xt_table *table)
} }
EXPORT_SYMBOL_GPL(xt_table_unlock); 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 * struct xt_table_info *
xt_replace_table(struct xt_table *table, xt_replace_table(struct xt_table *table,
...@@ -671,6 +781,9 @@ static int __init xt_init(void) ...@@ -671,6 +781,9 @@ static int __init xt_init(void)
for (i = 0; i < NPROTO; i++) { for (i = 0; i < NPROTO; i++) {
mutex_init(&xt[i].mutex); 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].target);
INIT_LIST_HEAD(&xt[i].match); INIT_LIST_HEAD(&xt[i].match);
INIT_LIST_HEAD(&xt[i].tables); INIT_LIST_HEAD(&xt[i].tables);
......
...@@ -9,16 +9,22 @@ ...@@ -9,16 +9,22 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/ip.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_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yon Uriarte <yon@astaro.de>"); 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) #define duprintf(format, args...) printk(format , ## args)
#else #else
#define duprintf(format, args...) #define duprintf(format, args...)
...@@ -28,11 +34,11 @@ MODULE_DESCRIPTION("iptables ESP SPI match module"); ...@@ -28,11 +34,11 @@ MODULE_DESCRIPTION("iptables ESP SPI match module");
static inline int static inline int
spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert) spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
{ {
int r=0; int r = 0;
duprintf("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ', duprintf("esp spi_match:%c 0x%x <= 0x%x <= 0x%x", invert ? '!' : ' ',
min,spi,max); min, spi, max);
r=(spi >= min && spi <= max) ^ invert; r = (spi >= min && spi <= max) ^ invert;
duprintf(" result %s\n",r? "PASS" : "FAILED"); duprintf(" result %s\n", r ? "PASS" : "FAILED");
return r; return r;
} }
...@@ -47,14 +53,13 @@ match(const struct sk_buff *skb, ...@@ -47,14 +53,13 @@ match(const struct sk_buff *skb,
int *hotdrop) int *hotdrop)
{ {
struct ip_esp_hdr _esp, *eh; struct ip_esp_hdr _esp, *eh;
const struct ipt_esp *espinfo = matchinfo; const struct xt_esp *espinfo = matchinfo;
/* Must not be a fragment. */ /* Must not be a fragment. */
if (offset) if (offset)
return 0; return 0;
eh = skb_header_pointer(skb, protoff, eh = skb_header_pointer(skb, protoff, sizeof(_esp), &_esp);
sizeof(_esp), &_esp);
if (eh == NULL) { if (eh == NULL) {
/* We've been asked to examine this packet, and we /* We've been asked to examine this packet, and we
* can't. Hence, no choice but to drop. * can't. Hence, no choice but to drop.
...@@ -64,9 +69,8 @@ match(const struct sk_buff *skb, ...@@ -64,9 +69,8 @@ match(const struct sk_buff *skb,
return 0; return 0;
} }
return spi_match(espinfo->spis[0], espinfo->spis[1], return spi_match(espinfo->spis[0], espinfo->spis[1], ntohl(eh->spi),
ntohl(eh->spi), !!(espinfo->invflags & XT_ESP_INV_SPI));
!!(espinfo->invflags & IPT_ESP_INV_SPI));
} }
/* Called when user tries to insert an entry of this type. */ /* Called when user tries to insert an entry of this type. */
...@@ -78,34 +82,55 @@ checkentry(const char *tablename, ...@@ -78,34 +82,55 @@ checkentry(const char *tablename,
unsigned int matchinfosize, unsigned int matchinfosize,
unsigned int hook_mask) unsigned int hook_mask)
{ {
const struct ipt_esp *espinfo = matchinfo; const struct xt_esp *espinfo = matchinfo;
/* Must specify no unknown invflags */ if (espinfo->invflags & ~XT_ESP_INV_MASK) {
if (espinfo->invflags & ~IPT_ESP_INV_MASK) { duprintf("xt_esp: unknown flags %X\n", espinfo->invflags);
duprintf("ipt_esp: unknown flags %X\n", espinfo->invflags);
return 0; return 0;
} }
return 1; return 1;
} }
static struct ipt_match esp_match = { static struct xt_match esp_match = {
.name = "esp", .name = "esp",
.match = match, .family = AF_INET,
.matchsize = sizeof(struct ipt_esp),
.proto = IPPROTO_ESP, .proto = IPPROTO_ESP,
.checkentry = checkentry, .match = &match,
.matchsize = sizeof(struct xt_esp),
.checkentry = &checkentry,
.me = THIS_MODULE, .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_init(xt_esp_init);
module_exit(ipt_esp_fini); module_exit(xt_esp_cleanup);
...@@ -13,13 +13,18 @@ ...@@ -13,13 +13,18 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/udp.h> #include <linux/udp.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/netfilter_ipv4/ipt_multiport.h> #include <linux/netfilter/xt_multiport.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
MODULE_DESCRIPTION("iptables multiple port match module"); MODULE_DESCRIPTION("x_tables multiple port match module");
MODULE_ALIAS("ipt_multiport");
MODULE_ALIAS("ip6t_multiport");
#if 0 #if 0
#define duprintf(format, args...) printk(format , ## args) #define duprintf(format, args...) printk(format , ## args)
...@@ -29,17 +34,15 @@ MODULE_DESCRIPTION("iptables multiple port match module"); ...@@ -29,17 +34,15 @@ MODULE_DESCRIPTION("iptables multiple port match module");
/* Returns 1 if the port is matched by the test, 0 otherwise. */ /* Returns 1 if the port is matched by the test, 0 otherwise. */
static inline int static inline int
ports_match(const u_int16_t *portlist, enum ipt_multiport_flags flags, ports_match(const u_int16_t *portlist, enum xt_multiport_flags flags,
u_int8_t count, u_int16_t src, u_int16_t dst) u_int8_t count, u_int16_t src, u_int16_t dst)
{ {
unsigned int i; unsigned int i;
for (i=0; i<count; i++) { for (i = 0; i < count; i++) {
if (flags != IPT_MULTIPORT_DESTINATION if (flags != XT_MULTIPORT_DESTINATION && portlist[i] == src)
&& portlist[i] == src)
return 1; return 1;
if (flags != IPT_MULTIPORT_SOURCE if (flags != XT_MULTIPORT_SOURCE && portlist[i] == dst)
&& portlist[i] == dst)
return 1; return 1;
} }
...@@ -48,13 +51,13 @@ ports_match(const u_int16_t *portlist, enum ipt_multiport_flags flags, ...@@ -48,13 +51,13 @@ ports_match(const u_int16_t *portlist, enum ipt_multiport_flags flags,
/* Returns 1 if the port is matched by the test, 0 otherwise. */ /* Returns 1 if the port is matched by the test, 0 otherwise. */
static inline int static inline int
ports_match_v1(const struct ipt_multiport_v1 *minfo, ports_match_v1(const struct xt_multiport_v1 *minfo,
u_int16_t src, u_int16_t dst) u_int16_t src, u_int16_t dst)
{ {
unsigned int i; unsigned int i;
u_int16_t s, e; u_int16_t s, e;
for (i=0; i < minfo->count; i++) { for (i = 0; i < minfo->count; i++) {
s = minfo->ports[i]; s = minfo->ports[i];
if (minfo->pflags[i]) { if (minfo->pflags[i]) {
...@@ -62,13 +65,13 @@ ports_match_v1(const struct ipt_multiport_v1 *minfo, ...@@ -62,13 +65,13 @@ ports_match_v1(const struct ipt_multiport_v1 *minfo,
e = minfo->ports[++i]; e = minfo->ports[++i];
duprintf("src or dst matches with %d-%d?\n", s, e); duprintf("src or dst matches with %d-%d?\n", s, e);
if (minfo->flags == IPT_MULTIPORT_SOURCE if (minfo->flags == XT_MULTIPORT_SOURCE
&& src >= s && src <= e) && src >= s && src <= e)
return 1 ^ minfo->invert; return 1 ^ minfo->invert;
if (minfo->flags == IPT_MULTIPORT_DESTINATION if (minfo->flags == XT_MULTIPORT_DESTINATION
&& dst >= s && dst <= e) && dst >= s && dst <= e)
return 1 ^ minfo->invert; return 1 ^ minfo->invert;
if (minfo->flags == IPT_MULTIPORT_EITHER if (minfo->flags == XT_MULTIPORT_EITHER
&& ((dst >= s && dst <= e) && ((dst >= s && dst <= e)
|| (src >= s && src <= e))) || (src >= s && src <= e)))
return 1 ^ minfo->invert; return 1 ^ minfo->invert;
...@@ -76,18 +79,18 @@ ports_match_v1(const struct ipt_multiport_v1 *minfo, ...@@ -76,18 +79,18 @@ ports_match_v1(const struct ipt_multiport_v1 *minfo,
/* exact port matching */ /* exact port matching */
duprintf("src or dst matches with %d?\n", s); duprintf("src or dst matches with %d?\n", s);
if (minfo->flags == IPT_MULTIPORT_SOURCE if (minfo->flags == XT_MULTIPORT_SOURCE
&& src == s) && src == s)
return 1 ^ minfo->invert; return 1 ^ minfo->invert;
if (minfo->flags == IPT_MULTIPORT_DESTINATION if (minfo->flags == XT_MULTIPORT_DESTINATION
&& dst == s) && dst == s)
return 1 ^ minfo->invert; return 1 ^ minfo->invert;
if (minfo->flags == IPT_MULTIPORT_EITHER if (minfo->flags == XT_MULTIPORT_EITHER
&& (src == s || dst == s)) && (src == s || dst == s))
return 1 ^ minfo->invert; return 1 ^ minfo->invert;
} }
} }
return minfo->invert; return minfo->invert;
} }
...@@ -102,19 +105,17 @@ match(const struct sk_buff *skb, ...@@ -102,19 +105,17 @@ match(const struct sk_buff *skb,
int *hotdrop) int *hotdrop)
{ {
u16 _ports[2], *pptr; u16 _ports[2], *pptr;
const struct ipt_multiport *multiinfo = matchinfo; const struct xt_multiport *multiinfo = matchinfo;
if (offset) if (offset)
return 0; return 0;
pptr = skb_header_pointer(skb, protoff, pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports);
sizeof(_ports), _ports);
if (pptr == NULL) { if (pptr == NULL) {
/* We've been asked to examine this packet, and we /* We've been asked to examine this packet, and we
* can't. Hence, no choice but to drop. * can't. Hence, no choice but to drop.
*/ */
duprintf("ipt_multiport:" duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
" Dropping evil offset=0 tinygram.\n");
*hotdrop = 1; *hotdrop = 1;
return 0; return 0;
} }
...@@ -135,19 +136,17 @@ match_v1(const struct sk_buff *skb, ...@@ -135,19 +136,17 @@ match_v1(const struct sk_buff *skb,
int *hotdrop) int *hotdrop)
{ {
u16 _ports[2], *pptr; u16 _ports[2], *pptr;
const struct ipt_multiport_v1 *multiinfo = matchinfo; const struct xt_multiport_v1 *multiinfo = matchinfo;
if (offset) if (offset)
return 0; return 0;
pptr = skb_header_pointer(skb, protoff, pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports);
sizeof(_ports), _ports);
if (pptr == NULL) { if (pptr == NULL) {
/* We've been asked to examine this packet, and we /* We've been asked to examine this packet, and we
* can't. Hence, no choice but to drop. * can't. Hence, no choice but to drop.
*/ */
duprintf("ipt_multiport:" duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
" Dropping evil offset=0 tinygram.\n");
*hotdrop = 1; *hotdrop = 1;
return 0; return 0;
} }
...@@ -155,41 +154,161 @@ match_v1(const struct sk_buff *skb, ...@@ -155,41 +154,161 @@ match_v1(const struct sk_buff *skb,
return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1])); return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1]));
} }
static struct ipt_match multiport_match = { 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", .name = "multiport",
.revision = 0, .revision = 0,
.match = match, .matchsize = sizeof(struct xt_multiport),
.matchsize = sizeof(struct ipt_multiport), .match = &match,
.checkentry = &checkentry6,
.family = AF_INET6,
.me = THIS_MODULE, .me = THIS_MODULE,
}; };
static struct ipt_match multiport_match_v1 = { static struct xt_match multiport6_match_v1 = {
.name = "multiport", .name = "multiport",
.revision = 1, .revision = 1,
.match = match_v1, .matchsize = sizeof(struct xt_multiport_v1),
.matchsize = sizeof(struct ipt_multiport_v1), .match = &match_v1,
.checkentry = &checkentry6_v1,
.family = AF_INET6,
.me = THIS_MODULE, .me = THIS_MODULE,
}; };
static int __init ipt_multiport_init(void) static int __init xt_multiport_init(void)
{ {
int err; int ret;
err = ipt_register_match(&multiport_match); ret = xt_register_match(&multiport_match);
if (!err) { if (ret)
err = ipt_register_match(&multiport_match_v1); goto out;
if (err)
ipt_unregister_match(&multiport_match); 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;
return err; 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 ipt_multiport_fini(void) static void __exit xt_multiport_fini(void)
{ {
ipt_unregister_match(&multiport_match); xt_unregister_match(&multiport_match);
ipt_unregister_match(&multiport_match_v1); xt_unregister_match(&multiport_match_v1);
xt_unregister_match(&multiport6_match);
xt_unregister_match(&multiport6_match_v1);
} }
module_init(ipt_multiport_init); module_init(xt_multiport_init);
module_exit(ipt_multiport_fini); module_exit(xt_multiport_fini);
...@@ -71,7 +71,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info, ...@@ -71,7 +71,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info,
return 0; return 0;
e = &info->pol[pos]; 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) if (!strict)
return 1; return 1;
} else if (strict) } else if (strict)
......
...@@ -1418,7 +1418,8 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _ ...@@ -1418,7 +1418,8 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _
newfd = sock_alloc_fd(&newfile); newfd = sock_alloc_fd(&newfile);
if (unlikely(newfd < 0)) { if (unlikely(newfd < 0)) {
err = newfd; err = newfd;
goto out_release; sock_release(newsock);
goto out_put;
} }
err = sock_attach_fd(newsock, newfile); err = sock_attach_fd(newsock, newfile);
...@@ -1455,10 +1456,8 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _ ...@@ -1455,10 +1456,8 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int _
out: out:
return err; return err;
out_fd: out_fd:
put_filp(newfile); fput(newfile);
put_unused_fd(newfd); put_unused_fd(newfd);
out_release:
sock_release(newsock);
goto out_put; goto out_put;
} }
......
...@@ -18,7 +18,7 @@ void __secpath_destroy(struct sec_path *sp) ...@@ -18,7 +18,7 @@ void __secpath_destroy(struct sec_path *sp)
{ {
int i; int i;
for (i = 0; i < sp->len; 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); kmem_cache_free(secpath_cachep, sp);
} }
EXPORT_SYMBOL(__secpath_destroy); EXPORT_SYMBOL(__secpath_destroy);
...@@ -37,7 +37,7 @@ struct sec_path *secpath_dup(struct sec_path *src) ...@@ -37,7 +37,7 @@ struct sec_path *secpath_dup(struct sec_path *src)
memcpy(sp, src, sizeof(*sp)); memcpy(sp, src, sizeof(*sp));
for (i = 0; i < sp->len; i++) 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); atomic_set(&sp->refcnt, 1);
return sp; return sp;
......
...@@ -943,9 +943,9 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start, ...@@ -943,9 +943,9 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int start,
} else } else
start = -1; start = -1;
for (; idx < sp->len; idx++) { 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; return ++idx;
if (sp->x[idx].xvec->props.mode) if (sp->xvec[idx]->props.mode)
break; break;
} }
return start; return start;
...@@ -968,7 +968,7 @@ EXPORT_SYMBOL(xfrm_decode_session); ...@@ -968,7 +968,7 @@ EXPORT_SYMBOL(xfrm_decode_session);
static inline int secpath_has_tunnel(struct sec_path *sp, int k) static inline int secpath_has_tunnel(struct sec_path *sp, int k)
{ {
for (; k < sp->len; k++) { for (; k < sp->len; k++) {
if (sp->x[k].xvec->props.mode) if (sp->xvec[k]->props.mode)
return 1; return 1;
} }
...@@ -994,8 +994,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, ...@@ -994,8 +994,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
int i; int i;
for (i=skb->sp->len-1; i>=0; i--) { for (i=skb->sp->len-1; i>=0; i--) {
struct sec_decap_state *xvec = &(skb->sp->x[i]); struct xfrm_state *x = skb->sp->xvec[i];
if (!xfrm_selector_match(&xvec->xvec->sel, &fl, family)) if (!xfrm_selector_match(&x->sel, &fl, family))
return 0; return 0;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment