Linus, please apply.
Note to all: I am out this week (knee reconstruction). If I post
before Thursday, I'm probably on pain medication, so check my patches
carefully 8).
This fixes:
1) Module unload races.
2) NAT on fragment issues (GameSpy crash).
3) Partially-initialized NAT entries if protocol doesn't like packet.
4) `check' failure one-too-many-down() bug.
Some paranoia issues:
1) Now doing an external lookup will never create a new connection.
2) Extra checks for locally-injected truncated IP packets (raw
sockets).
Enjoy!
Rusty.
diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h
--exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude
version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config
--exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude
consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude
modversions.h --exclude install-kernel
linux-2.3.99-pre4-2/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
working/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
--- linux-2.3.99-pre4-2/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
Sat Apr 8 18:10:12 2000
+++ working/include/linux/netfilter_ipv4/ip_conntrack_protocol.h Mon Apr
3 14:47:59 2000
@@ -37,10 +37,10 @@
struct iphdr *iph, size_t len,
enum ip_conntrack_info ctinfo);
- /* Called when a new connection for this protocol found; returns
- * TRUE if it's OK. If so, packet() called next. */
- int (*new)(struct ip_conntrack *conntrack,
- struct iphdr *iph, size_t len);
+ /* Called when a new connection for this protocol found;
+ * returns timeout. If so, packet() called next. */
+ unsigned long (*new)(struct ip_conntrack *conntrack,
+ struct iphdr *iph, size_t len);
/* Module (if any) which this is connected to. */
struct module *me;
diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h
--exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude
version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config
--exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude
consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude
modversions.h --exclude install-kernel
linux-2.3.99-pre4-2/include/linux/netfilter_ipv4/ipt_state.h
working/include/linux/netfilter_ipv4/ipt_state.h
--- linux-2.3.99-pre4-2/include/linux/netfilter_ipv4/ipt_state.h Sat Mar
18 05:26:20 2000
+++ working/include/linux/netfilter_ipv4/ipt_state.h Mon Apr 3 14:18:20 2000
@@ -1,8 +1,7 @@
#ifndef _IPT_STATE_H
#define _IPT_STATE_H
-#define _IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)+1))
-#define IPT_STATE_BIT(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ?
_IPT_STATE_BIT((ctinfo)-IP_CT_IS_REPLY) : _IPT_STATE_BIT(ctinfo))
+#define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
#define IPT_STATE_INVALID (1 << 0)
struct ipt_state_info
diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h
--exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude
version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config
--exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude
consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude
modversions.h --exclude install-kernel
linux-2.3.99-pre4-2/net/ipv4/ip_fragment.c working/net/ipv4/ip_fragment.c
--- linux-2.3.99-pre4-2/net/ipv4/ip_fragment.c Thu Feb 10 14:38:09 2000
+++ working/net/ipv4/ip_fragment.c Mon Apr 3 14:18:20 2000
@@ -387,8 +387,13 @@
*/
skb->security = qp->fragments->skb->security;
+#ifdef CONFIG_NETFILTER
+ /* Connection association is same as fragment (if any). */
+ skb->nfct = qp->fragments->skb->nfct;
+ nf_conntrack_get(skb->nfct);
#ifdef CONFIG_NETFILTER_DEBUG
skb->nf_debug = qp->fragments->skb->nf_debug;
+#endif
#endif
/* Done with all fragments. Fixup the new IP header. */
diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h
--exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude
version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config
--exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude
consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude
modversions.h --exclude install-kernel
linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_core.c
working/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_core.c Sat Apr 1
19:03:03 2000
+++ working/net/ipv4/netfilter/ip_conntrack_core.c Mon Apr 3 14:18:20 2000
@@ -343,6 +343,7 @@
size_t hash, repl_hash;
struct ip_conntrack_expect *expected;
enum ip_conntrack_info ctinfo;
+ unsigned long extra_jiffies;
int i;
if (!invert_tuple(&repl_tuple, tuple, protocol)) {
@@ -366,19 +367,24 @@
repl_hash = hash_conntrack(&repl_tuple);
memset(conntrack, 0, sizeof(struct ip_conntrack));
- atomic_set(&conntrack->ct_general.use, 1);
+ atomic_set(&conntrack->ct_general.use, 2);
conntrack->ct_general.destroy = destroy_conntrack;
conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
- for(i=0; i < IP_CT_NUMBER; i++)
+ for (i=0; i < IP_CT_NUMBER; i++)
conntrack->infos[i].master = &conntrack->ct_general;
- if (!protocol->new(conntrack, skb->nh.iph, skb->len)) {
+ extra_jiffies = protocol->new(conntrack, skb->nh.iph, skb->len);
+ if (!extra_jiffies) {
kmem_cache_free(ip_conntrack_cachep, conntrack);
return 1;
}
+ conntrack->timeout.data = (unsigned long)conntrack;
+ conntrack->timeout.function = death_by_timeout;
+ conntrack->timeout.expires = jiffies + extra_jiffies;
+ add_timer(&conntrack->timeout);
/* Sew in at head of hash list. */
WRITE_LOCK(&ip_conntrack_lock);
@@ -421,7 +427,7 @@
}
static void
-resolve_normal_ct(struct sk_buff *skb)
+resolve_normal_ct(struct sk_buff *skb, int create)
{
struct ip_conntrack_tuple tuple;
struct ip_conntrack_tuple_hash *h;
@@ -436,7 +442,7 @@
do {
/* look for tuple match */
h = ip_conntrack_find_get(&tuple, NULL);
- if (!h && init_conntrack(&tuple, proto, skb))
+ if (!h && (!create || init_conntrack(&tuple, proto, skb)))
return;
} while (!h);
@@ -464,13 +470,15 @@
}
/* Return conntrack and conntrack_info a given skb */
-struct ip_conntrack *
-ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
+static struct ip_conntrack *
+__ip_conntrack_get(struct sk_buff *skb,
+ enum ip_conntrack_info *ctinfo,
+ int create)
{
if (!skb->nfct) {
/* It may be an icmp error... */
if (!icmp_error_track(skb))
- resolve_normal_ct(skb);
+ resolve_normal_ct(skb, create);
}
if (skb->nfct) {
@@ -485,6 +493,12 @@
return NULL;
}
+struct ip_conntrack *
+ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
+{
+ return __ip_conntrack_get(skb, ctinfo, 0);
+}
+
/* Netfilter hook itself. */
unsigned int ip_conntrack_in(unsigned int hooknum,
struct sk_buff **pskb,
@@ -512,13 +526,13 @@
return NF_STOLEN;
}
- ct = ip_conntrack_get(*pskb, &ctinfo);
- if (!ct)
+ ct = __ip_conntrack_get(*pskb, &ctinfo, 1);
+ if (!ct) {
/* Not valid part of a connection */
return NF_ACCEPT;
+ }
proto = find_proto((*pskb)->nh.iph->protocol);
- /* If this is new, this is first time timer will be set */
ret = proto->packet(ct, (*pskb)->nh.iph, (*pskb)->len, ctinfo);
if (ret == -1) {
@@ -645,24 +659,16 @@
MOD_DEC_USE_COUNT;
}
-/* Refresh conntrack for this many jiffies: if noone calls this,
- conntrack will vanish with current skb. */
+/* Refresh conntrack for this many jiffies. */
void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
{
+ IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
+
WRITE_LOCK(&ip_conntrack_lock);
- /* If this hasn't had a timer before, it's still being set up */
- if (ct->timeout.data == 0) {
- ct->timeout.data = (unsigned long)ct;
- ct->timeout.function = death_by_timeout;
+ /* Need del_timer for race avoidance (may already be dying). */
+ if (del_timer(&ct->timeout)) {
ct->timeout.expires = jiffies + extra_jiffies;
- atomic_inc(&ct->ct_general.use);
add_timer(&ct->timeout);
- } else {
- /* Need del_timer for race avoidance (may already be dying). */
- if (del_timer(&ct->timeout)) {
- ct->timeout.expires = jiffies + extra_jiffies;
- add_timer(&ct->timeout);
- }
}
WRITE_UNLOCK(&ip_conntrack_lock);
}
diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h
--exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude
version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config
--exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude
consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude
modversions.h --exclude install-kernel
linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_generic.c
working/net/ipv4/netfilter/ip_conntrack_proto_generic.c
--- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_generic.c Sat Mar
18 05:26:20 2000
+++ working/net/ipv4/netfilter/ip_conntrack_proto_generic.c Mon Apr 3
14:18:20 2000
@@ -48,9 +48,10 @@
}
/* Called when a new connection for this protocol found. */
-static int new(struct ip_conntrack *conntrack, struct iphdr *iph, size_t len)
+static unsigned long
+new(struct ip_conntrack *conntrack, struct iphdr *iph, size_t len)
{
- return 1;
+ return GENERIC_TIMEOUT;
}
struct ip_conntrack_protocol ip_conntrack_generic_protocol
diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h
--exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude
version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config
--exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude
consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude
modversions.h --exclude install-kernel
linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
working/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
--- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_icmp.c Sat Apr
1 19:03:03 2000
+++ working/net/ipv4/netfilter/ip_conntrack_proto_icmp.c Mon Apr 3
14:18:20 2000
@@ -86,8 +86,8 @@
}
/* Called when a new connection for this protocol found. */
-static int icmp_new(struct ip_conntrack *conntrack,
- struct iphdr *iph, size_t len)
+static unsigned long icmp_new(struct ip_conntrack *conntrack,
+ struct iphdr *iph, size_t len)
{
static u_int8_t valid_new[]
= { [ICMP_ECHO] = 1,
@@ -103,7 +103,7 @@
DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
return 0;
}
- return 1;
+ return ICMP_TIMEOUT;
}
struct ip_conntrack_protocol ip_conntrack_protocol_icmp
diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h
--exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude
version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config
--exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude
consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude
modversions.h --exclude install-kernel
linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
working/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_tcp.c Sat Apr
1 19:03:03 2000
+++ working/net/ipv4/netfilter/ip_conntrack_proto_tcp.c Mon Apr 3 14:18:20 2000
@@ -189,14 +189,13 @@
conntrack->proto.tcp_state = newconntrack;
WRITE_UNLOCK(&tcp_lock);
- /* Refresh: need write lock to write to conntrack. */
ip_ct_refresh(conntrack, tcp_timeouts[conntrack->proto.tcp_state]);
return NF_ACCEPT;
}
/* Called when a new connection for this protocol found. */
-static int tcp_new(struct ip_conntrack *conntrack,
- struct iphdr *iph, size_t len)
+static unsigned long tcp_new(struct ip_conntrack *conntrack,
+ struct iphdr *iph, size_t len)
{
enum tcp_conntrack newconntrack;
struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
@@ -210,11 +209,10 @@
if (newconntrack == TCP_CONNTRACK_MAX) {
DEBUGP("ip_conntrack_tcp: invalid new deleting.\n");
return 0;
- } else {
- conntrack->proto.tcp_state = newconntrack;
- ip_ct_refresh(conntrack,
tcp_timeouts[conntrack->proto.tcp_state]);
}
- return 1;
+
+ conntrack->proto.tcp_state = newconntrack;
+ return tcp_timeouts[conntrack->proto.tcp_state];
}
struct ip_conntrack_protocol ip_conntrack_protocol_tcp
diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h
--exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude
version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config
--exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude
consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude
modversions.h --exclude install-kernel
linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_udp.c
working/net/ipv4/netfilter/ip_conntrack_proto_udp.c
--- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_proto_udp.c Sat Apr
1 19:03:03 2000
+++ working/net/ipv4/netfilter/ip_conntrack_proto_udp.c Mon Apr 3 14:18:20 2000
@@ -54,10 +54,10 @@
}
/* Called when a new connection for this protocol found. */
-static int udp_new(struct ip_conntrack *conntrack,
- struct iphdr *iph, size_t len)
+static unsigned long udp_new(struct ip_conntrack *conntrack,
+ struct iphdr *iph, size_t len)
{
- return 1;
+ return UDP_TIMEOUT;
}
struct ip_conntrack_protocol ip_conntrack_protocol_udp
diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h
--exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude
version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config
--exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude
consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude
modversions.h --exclude install-kernel
linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_standalone.c
working/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_conntrack_standalone.c Sat Apr
1 19:03:03 2000
+++ working/net/ipv4/netfilter/ip_conntrack_standalone.c Mon Apr 3
14:18:20 2000
@@ -169,8 +169,6 @@
interface. We degfragment them at LOCAL_OUT, however,
so we have to refragment them here. */
if ((*pskb)->len > rt->u.dst.pmtu) {
- DEBUGP("ip_conntrack: refragm %p (size %u) to %u (okfn %p)\n",
- *pskb, (*pskb)->len, rt->u.dst.pmtu, okfn);
/* No hook can be after us, so this should be OK. */
ip_fragment(*pskb, okfn);
return NF_STOLEN;
@@ -178,13 +176,29 @@
return NF_ACCEPT;
}
+static unsigned int ip_conntrack_local(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ /* root is playing with raw sockets. */
+ if ((*pskb)->len < sizeof(struct iphdr)
+ || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
+ if (net_ratelimit())
+ printk("ipt_hook: happy cracking.\n");
+ return NF_ACCEPT;
+ }
+ return ip_conntrack_in(hooknum, pskb, in, out, okfn);
+}
+
/* Connection tracking may drop packets, but never alters them, so
make it the first hook. */
static struct nf_hook_ops ip_conntrack_in_ops
= { { NULL, NULL }, ip_conntrack_in, PF_INET, NF_IP_PRE_ROUTING,
NF_IP_PRI_CONNTRACK };
static struct nf_hook_ops ip_conntrack_local_out_ops
-= { { NULL, NULL }, ip_conntrack_in, PF_INET, NF_IP_LOCAL_OUT,
+= { { NULL, NULL }, ip_conntrack_local, PF_INET, NF_IP_LOCAL_OUT,
NF_IP_PRI_CONNTRACK };
/* Refragmenter; last chance. */
static struct nf_hook_ops ip_conntrack_out_ops
diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h
--exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude
version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config
--exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude
consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude
modversions.h --exclude install-kernel
linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_nat_standalone.c
working/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_nat_standalone.c Sat Apr 1
19:03:03 2000
+++ working/net/ipv4/netfilter/ip_nat_standalone.c Mon Apr 3 14:18:20 2000
@@ -130,6 +130,11 @@
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
+ /* root is playing with raw sockets. */
+ if ((*pskb)->len < sizeof(struct iphdr)
+ || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
+ return NF_ACCEPT;
+
/* We can hit fragment here; forwarded packets get
defragmented by connection tracking coming in, then
fragmented (grr) by the forward code.
@@ -150,6 +155,21 @@
return ip_nat_fn(hooknum, pskb, in, out, okfn);
}
+static unsigned int
+ip_nat_local_fn(unsigned int hooknum,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ /* root is playing with raw sockets. */
+ if ((*pskb)->len < sizeof(struct iphdr)
+ || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
+ return NF_ACCEPT;
+
+ return ip_nat_fn(hooknum, pskb, in, out, okfn);
+}
+
/* We must be after connection tracking and before packet filtering. */
/* Before packet filtering, change destination */
@@ -160,7 +180,7 @@
= { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING,
NF_IP_PRI_NAT_SRC};
/* Before packet filtering, change destination */
static struct nf_hook_ops ip_nat_local_out_ops
-= { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_NAT_DST };
+= { { NULL, NULL }, ip_nat_local_fn, PF_INET, NF_IP_LOCAL_OUT,
NF_IP_PRI_NAT_DST };
/* Protocol registration. */
int ip_nat_protocol_register(struct ip_nat_protocol *proto)
diff -urN --minimal --exclude *.lds --exclude *.sgml --exclude classlist.h
--exclude devlist.h --exclude autoconf.h --exclude compile.h --exclude
version.h --exclude .* --exclude *.[oa] --exclude *.orig --exclude config
--exclude asm --exclude modules --exclude *.[Ss] --exclude System.map --exclude
consolemap_deftbl.c --exclude *~ --exclude TAGS --exclude tags --exclude
modversions.h --exclude install-kernel
linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_tables.c
working/net/ipv4/netfilter/ip_tables.c
--- linux-2.3.99-pre4-2/net/ipv4/netfilter/ip_tables.c Sat Apr 1 19:03:03 2000
+++ working/net/ipv4/netfilter/ip_tables.c Mon Apr 3 14:52:21 2000
@@ -39,7 +39,7 @@
#define IP_NF_ASSERT(x) \
do { \
if (!(x)) \
- printk("IPT_ASSERT: %s:%s:%u\n", \
+ printk("IP_NF_ASSERT: %s:%s:%u\n", \
__FUNCTION__, __FILE__, __LINE__); \
} while(0)
#else
@@ -683,7 +683,6 @@
target = find_target_lock(t->u.name, &ret, &ipt_mutex);
if (!target) {
duprintf("check_entry: `%s' not found\n", t->u.name);
- up(&ipt_mutex);
return ret;
}
if (target->me)
@@ -1283,17 +1282,16 @@
{
int ret;
+ MOD_INC_USE_COUNT;
ret = down_interruptible(&ipt_mutex);
if (ret != 0)
return ret;
- if (list_named_insert(&ipt_target, target)) {
- MOD_INC_USE_COUNT;
- ret = 0;
- } else {
+ if (!list_named_insert(&ipt_target, target)) {
duprintf("ipt_register_target: `%s' already in list!\n",
target->name);
ret = -EINVAL;
+ MOD_DEC_USE_COUNT;
}
up(&ipt_mutex);
return ret;
@@ -1313,16 +1311,18 @@
{
int ret;
+ MOD_INC_USE_COUNT;
ret = down_interruptible(&ipt_mutex);
- if (ret != 0)
+ if (ret != 0) {
+ MOD_DEC_USE_COUNT;
return ret;
-
+ }
if (list_named_insert(&ipt_match, match)) {
- MOD_INC_USE_COUNT;
ret = 0;
} else {
duprintf("ipt_register_match: `%s' already in list!\n",
match->name);
+ MOD_DEC_USE_COUNT;
ret = -EINVAL;
}
up(&ipt_mutex);
@@ -1346,10 +1346,12 @@
static struct ipt_table_info bootstrap
= { 0, 0, { 0 }, { 0 }, { }, { } };
+ MOD_INC_USE_COUNT;
newinfo = vmalloc(sizeof(struct ipt_table_info)
+ SMP_ALIGN(table->table->size) * smp_num_cpus);
if (!newinfo) {
ret = -ENOMEM;
+ MOD_DEC_USE_COUNT;
return ret;
}
memcpy(newinfo->entries, table->table->entries, table->table->size);
@@ -1361,12 +1363,14 @@
table->table->underflow);
if (ret != 0) {
vfree(newinfo);
+ MOD_DEC_USE_COUNT;
return ret;
}
ret = down_interruptible(&ipt_mutex);
if (ret != 0) {
vfree(newinfo);
+ MOD_DEC_USE_COUNT;
return ret;
}
@@ -1386,7 +1390,6 @@
table->lock = RW_LOCK_UNLOCKED;
list_prepend(&ipt_tables, table);
- MOD_INC_USE_COUNT;
unlock:
up(&ipt_mutex);
@@ -1394,6 +1397,7 @@
free_unlock:
vfree(newinfo);
+ MOD_DEC_USE_COUNT;
goto unlock;
}
--
Hacking time.
|