All of lore.kernel.org
 help / color / mirror / Atom feed
From: Massimiliano Hofer <max@nucleus.it>
To: netfilter-devel@lists.netfilter.org
Cc: Patrick McHardy <kaber@trash.net>
Subject: [PATCH 3/4][data-condition]: instance data support in netfilter core code
Date: Tue, 5 Dec 2006 23:17:08 +0100	[thread overview]
Message-ID: <200612052317.09549.max@nucleus.it> (raw)
In-Reply-To: <200612052312.28824.max@nucleus.it>

From b0ff8190113c29f440ee420c238836492c7e23ff Mon Sep 17 00:00:00 2001
From: Massimiliano Hofer <max@nucleus.it>
Date: Tue, 5 Dec 2006 22:57:21 +0100
Subject: [PATCH] [NETFILTER]: instance data support in netfilter core code

This patch adds the relevant code to support instance specific data in matches and targets.
Some code shuffling happened and I used the opportunity to move some common code
from ip_tables.c, arp_tables.c and ip6_tables.c to x_tables.c.

Signed-off-by: Massimiliano Hofer <max@nucleus.it>
---
 include/linux/netfilter/x_tables.h |   16 +++--
 net/ipv4/netfilter/arp_tables.c    |   30 +++-------
 net/ipv4/netfilter/ip_tables.c     |   84 ++++++++------------------
 net/ipv6/netfilter/ip6_tables.c    |   75 ++++++------------------
 net/netfilter/x_tables.c           |  113 +++++++++++++++++++++++++++++++++---
 5 files changed, 168 insertions(+), 150 deletions(-)

diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 17aa03b..8903d35 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -284,12 +284,16 @@ extern void xt_unregister_match(struct x
 extern int xt_register_matches(struct xt_match *match, unsigned int n);
 extern void xt_unregister_matches(struct xt_match *match, unsigned int n);
 
-extern int xt_init_match(const struct xt_match *match, unsigned short family,
-			 unsigned int size, const char *table, unsigned int hook,
-			 unsigned short proto, int inv_proto);
-extern int xt_init_target(const struct xt_target *target, unsigned short family,
-			  unsigned int size, const char *table, unsigned int hook,
-			  unsigned short proto, int inv_proto);
+extern int xt_init_match(struct xt_entry_match *m,
+                        unsigned short family, const char *table,
+                        unsigned int hook_mask, const void *ip,
+			unsigned short proto, int inv_proto);
+extern void xt_destroy_match(struct xt_entry_match *m);
+extern int xt_init_target(struct xt_entry_target *t,
+                         unsigned short family, const char *table,
+                         unsigned int hook_mask, unsigned short proto,
+                         int inv_proto);
+extern void xt_destroy_target(struct xt_entry_target *m);
 
 extern int xt_register_table(struct xt_table *table,
 			     struct xt_table_info *bootstrap,
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 683179f..dce28d9 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -456,11 +456,10 @@ static inline int standard_check(const s
 
 static struct arpt_target arpt_standard_target;
 
-static inline int check_entry(struct arpt_entry *e, const char *name, unsigned int size,
-			      unsigned int *i)
+static inline int init_entry(struct arpt_entry *e, const char *name, unsigned int size,
+			     unsigned int *i)
 {
 	struct arpt_entry_target *t;
-	struct arpt_target *target;
 	int ret;
 
 	if (!arp_checkentry(&e->arp)) {
@@ -475,30 +474,20 @@ static inline int check_entry(struct arp
 	if (e->target_offset + t->u.target_size > e->next_offset)
 		return -EINVAL;
 
-	target = try_then_request_module(xt_find_target(NF_ARP, t->u.user.name,
-							t->u.user.revision),
-					 "arpt_%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;
-
-	ret = xt_init_target(target, NF_ARP, t->u.target_size - sizeof(*t),
+	ret = xt_init_target(t, NF_ARP,
 			     name, e->comefrom, 0, 0);
+
 	if (ret)
 		goto err;
 
-	t->u.kernel.data=NULL;
 	if (t->u.kernel.target == &arpt_standard_target) {
 		if (!standard_check(t, size)) {
 			ret = -EINVAL;
 			goto err;
 		}
 	} else if (t->u.kernel.target->init
-		   && !t->u.kernel.target->init(name, e, target, t->data,
-						t->u.kernel.data,
+		   && !t->u.kernel.target->init(name, e, t->u.kernel.target,
+						t->data, t->u.kernel.data,
 						e->comefrom)) {
 		duprintf("arp_tables: check failed for `%s'.\n",
 			 t->u.kernel.target->name);
@@ -509,8 +498,7 @@ static inline int check_entry(struct arp
 	(*i)++;
 	return 0;
 err:
-	module_put(t->u.kernel.target->me);
-out:
+	xt_destroy_target(t);
 	return ret;
 }
 
@@ -567,7 +555,7 @@ static inline int cleanup_entry(struct a
 	if (t->u.kernel.target->destroy)
 		t->u.kernel.target->destroy(t->u.kernel.target, t->data,
 					    t->u.kernel.data);
-	module_put(t->u.kernel.target->me);
+	xt_destroy_target(t);
 	return 0;
 }
 
@@ -635,7 +623,7 @@ static int translate_table(const char *n
 	/* Finally, each sanity check must pass */
 	i = 0;
 	ret = ARPT_ENTRY_ITERATE(entry0, newinfo->size,
-				 check_entry, name, size, &i);
+				 init_entry, name, size, &i);
 
 	if (ret != 0)
 		goto cleanup;
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 4077577..98a2e28 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -469,7 +469,7 @@ cleanup_match(struct ipt_entry_match *m,
 	if (m->u.kernel.match->destroy)
 		m->u.kernel.match->destroy(m->u.kernel.match, m->data,
 					   m->u.kernel.data);
-	module_put(m->u.kernel.match->me);
+	xt_destroy_match(m);
 	return 0;
 }
 
@@ -501,49 +501,24 @@ init_match(struct ipt_entry_match *m,
 	    unsigned int hookmask,
 	    unsigned int *i)
 {
-	struct ipt_match *match;
 	int ret;
 
-	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("check_match: `%s' not found\n", m->u.user.name);
-		return match ? PTR_ERR(match) : -ENOENT;
-	}
-	m->u.kernel.match = match;
-
-	ret = xt_init_match(match, AF_INET, m->u.match_size - sizeof(*m),
-			    name, hookmask, ip->proto,
+	ret = xt_init_match(m, AF_INET,
+			    name, hookmask, ip, ip->proto,
 			    ip->invflags & IPT_INV_PROTO);
-	if (ret)
-		goto err;
 
-	m->u.kernel.data = NULL;
-	if (m->u.kernel.match->init
-	    && !m->u.kernel.match->init(name, ip, match, m->data,
-					m->u.kernel.data, hookmask)) {
-		duprintf("ip_tables: check failed for `%s'.\n",
-			 m->u.kernel.match->name);
-		ret = -EINVAL;
-		goto err;
-	}
-
-	(*i)++;
-	return 0;
-err:
-	module_put(m->u.kernel.match->me);
+	if(!ret)
+		(*i)++;
 	return ret;
 }
 
 static struct ipt_target ipt_standard_target;
 
 static inline int
-check_entry(struct ipt_entry *e, const char *name, unsigned int size,
-	    unsigned int *i)
+init_entry(struct ipt_entry *e, const char *name, unsigned int size,
+	   unsigned int *i)
 {
 	struct ipt_entry_target *t;
-	struct ipt_target *target;
 	int ret;
 	unsigned int j;
 
@@ -564,32 +539,20 @@ check_entry(struct ipt_entry *e, const c
 	ret = -EINVAL;
 	if (e->target_offset + t->u.target_size > e->next_offset)
 			goto cleanup_matches;
-	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 cleanup_matches;
-	}
-	t->u.kernel.target = target;
-
-	ret = xt_init_target(target, AF_INET, t->u.target_size - sizeof(*t),
+	ret = xt_init_target(t, AF_INET,
 			     name, e->comefrom, e->ip.proto,
 			     e->ip.invflags & IPT_INV_PROTO);
 	if (ret)
 		goto err;
 
-	t->u.kernel.data = NULL;
 	if (t->u.kernel.target == &ipt_standard_target) {
 		if (!standard_check(t, size)) {
 			ret = -EINVAL;
 			goto err;
 		}
 	} else if (t->u.kernel.target->init
-		   && !t->u.kernel.target->init(name, e, target, t->data,
-						t->u.kernel.data,
+		   && !t->u.kernel.target->init(name, e, t->u.kernel.target,
+						t->data, t->u.kernel.data,
 						e->comefrom)) {
 		duprintf("ip_tables: check failed for `%s'.\n",
 			 t->u.kernel.target->name);
@@ -600,7 +563,7 @@ check_entry(struct ipt_entry *e, const c
 	(*i)++;
 	return 0;
  err:
-	module_put(t->u.kernel.target->me);
+	xt_destroy_target(t);
  cleanup_matches:
 	IPT_MATCH_ITERATE(e, cleanup_match, &j);
 	return ret;
@@ -663,7 +626,7 @@ cleanup_entry(struct ipt_entry *e, unsig
 	if (t->u.kernel.target->destroy)
 		t->u.kernel.target->destroy(t->u.kernel.target, t->data,
 					    t->u.kernel.data);
-	module_put(t->u.kernel.target->me);
+	xt_destroy_target(t);
 	return 0;
 }
 
@@ -729,7 +692,7 @@ translate_table(const char *name,
 	/* Finally, each sanity check must pass */
 	i = 0;
 	ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
-				check_entry, name, size, &i);
+				init_entry, name, size, &i);
 
 	if (ret != 0)
 		goto cleanup;
@@ -1499,7 +1462,7 @@ check_compat_entry_size_and_hooks(struct
 						     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);
+		duprintf("init_entry: `%s' not found\n", t->u.user.name);
 		ret = target ? PTR_ERR(target) : -ENOENT;
 		goto cleanup_matches;
 	}
@@ -1545,17 +1508,22 @@ static inline int compat_copy_match_from
 	match = m->u.kernel.match;
 	xt_compat_match_from_user(m, dstptr, size);
 
-	ret = xt_init_match(match, AF_INET, dm->u.match_size - sizeof(*dm),
-			    name, hookmask, ip->proto,
+	ret = xt_init_match(m, AF_INET, name, hookmask,
+			    ip, ip->proto,
 			    ip->invflags & IPT_INV_PROTO);
-	m->u.kernel.data = NULL;
-	if (!ret && m->u.kernel.match->init
+	if(ret)
+		goto err;
+	if (m->u.kernel.match->init
 	    && !m->u.kernel.match->init(name, ip, match, dm->data,
 					m->u.kernel.data, hookmask)) {
 		duprintf("ip_tables: check failed for `%s'.\n",
 			 m->u.kernel.match->name);
 		ret = -EINVAL;
+		goto err;
 	}
+	return 0;
+err:
+	xt_destroy_match(m);
 	return ret;
 }
 
@@ -1578,7 +1546,7 @@ static int compat_copy_entry_from_user(s
 	ret = IPT_MATCH_ITERATE(e, compat_copy_match_from_user, dstptr, size,
 			name, &de->ip, de->comefrom);
 	if (ret)
-		goto err;
+		return ret;
 	de->target_offset = e->target_offset - (origsize - *size);
 	t = ipt_get_target(e);
 	target = t->u.kernel.target;
@@ -1594,14 +1562,13 @@ static int compat_copy_entry_from_user(s
 
 	t = ipt_get_target(de);
 	target = t->u.kernel.target;
-	ret = xt_init_target(target, AF_INET, t->u.target_size - sizeof(*t),
+	ret = xt_init_target(t, AF_INET,
 			     name, e->comefrom, e->ip.proto,
 			     e->ip.invflags & IPT_INV_PROTO);
 	if (ret)
 		goto err;
 
 	ret = -EINVAL;
-	t->u.kernel.data = NULL;
 	if (t->u.kernel.target == &ipt_standard_target) {
 		if (!standard_check(t, *size))
 			goto err;
@@ -1615,6 +1582,7 @@ static int compat_copy_entry_from_user(s
 	}
 	ret = 0;
 err:
+	xt_destroy_target(t);
 	return ret;
 }
 
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index f14fe12..055fec0 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -508,7 +508,7 @@ cleanup_match(struct ip6t_entry_match *m
 	if (m->u.kernel.match->destroy)
 		m->u.kernel.match->destroy(m->u.kernel.match, m->data,
 					   m->u.kernel.data);
-	module_put(m->u.kernel.match->me);
+	xt_destroy_match(m);
 	return 0;
 }
 
@@ -534,55 +534,30 @@ standard_check(const struct ip6t_entry_t
 }
 
 static inline int
-check_match(struct ip6t_entry_match *m,
-	    const char *name,
-	    const struct ip6t_ip6 *ipv6,
-	    unsigned int hookmask,
-	    unsigned int *i)
+init_match(struct ip6t_entry_match *m,
+	   const char *name,
+	   const struct ip6t_ip6 *ipv6,
+	   unsigned int hookmask,
+	   unsigned int *i)
 {
-	struct ip6t_match *match;
 	int ret;
 
-	match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
-			      		m->u.user.revision),
-					"ip6t_%s", m->u.user.name);
-	if (IS_ERR(match) || !match) {
-	  	duprintf("check_match: `%s' not found\n", m->u.user.name);
-		return match ? PTR_ERR(match) : -ENOENT;
-	}
-	m->u.kernel.match = match;
-
-	ret = xt_init_match(match, AF_INET6, m->u.match_size - sizeof(*m),
-			    name, hookmask, ipv6->proto,
+	ret = xt_init_match(m, AF_INET6,
+			    name, hookmask, ipv6, ipv6->proto,
 			    ipv6->invflags & IP6T_INV_PROTO);
-	if (ret)
-		goto err;
-
-	m->u.kernel.data=NULL;
-	if (m->u.kernel.match->init
-	    && !m->u.kernel.match->init(name, ipv6, match,  m->data,
-					m->u.kernel.data, hookmask)) {
-		duprintf("ip_tables: check failed for `%s'.\n",
-			 m->u.kernel.match->name);
-		ret = -EINVAL;
-		goto err;
-	}
 
-	(*i)++;
+	if(!ret)
+		(*i)++;
 	return 0;
-err:
-	module_put(m->u.kernel.match->me);
-	return ret;
 }
 
 static struct ip6t_target ip6t_standard_target;
 
 static inline int
-check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
-	    unsigned int *i)
+init_entry(struct ip6t_entry *e, const char *name, unsigned int size,
+	   unsigned int *i)
 {
 	struct ip6t_entry_target *t;
-	struct ip6t_target *target;
 	int ret;
 	unsigned int j;
 
@@ -596,7 +571,7 @@ check_entry(struct ip6t_entry *e, const
 		return -EINVAL;
 
 	j = 0;
-	ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
+	ret = IP6T_MATCH_ITERATE(e, init_match, name, &e->ipv6, e->comefrom, &j);
 	if (ret != 0)
 		goto cleanup_matches;
 
@@ -604,32 +579,20 @@ check_entry(struct ip6t_entry *e, const
 	ret = -EINVAL;
 	if (e->target_offset + t->u.target_size > e->next_offset)
 			goto cleanup_matches;
-	target = try_then_request_module(xt_find_target(AF_INET6,
-							t->u.user.name,
-							t->u.user.revision),
-					 "ip6t_%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 cleanup_matches;
-	}
-	t->u.kernel.target = target;
-
-	ret = xt_init_target(target, AF_INET6, t->u.target_size - sizeof(*t),
+	ret = xt_init_target(t, AF_INET6,
 			     name, e->comefrom, e->ipv6.proto,
 			     e->ipv6.invflags & IP6T_INV_PROTO);
 	if (ret)
 		goto err;
 
-	t->u.kernel.data=NULL;
 	if (t->u.kernel.target == &ip6t_standard_target) {
 		if (!standard_check(t, size)) {
 			ret = -EINVAL;
 			goto err;
 		}
 	} else if (t->u.kernel.target->init
-		   && !t->u.kernel.target->init(name, e, target, t->data,
-						t->u.kernel.data,
+		   && !t->u.kernel.target->init(name, e, t->u.kernel.target,
+						t->data, t->u.kernel.data,
 						e->comefrom)) {
 		duprintf("ip_tables: check failed for `%s'.\n",
 			 t->u.kernel.target->name);
@@ -640,7 +603,7 @@ check_entry(struct ip6t_entry *e, const
 	(*i)++;
 	return 0;
  err:
-	module_put(t->u.kernel.target->me);
+	xt_destroy_target(t);
  cleanup_matches:
 	IP6T_MATCH_ITERATE(e, cleanup_match, &j);
 	return ret;
@@ -703,7 +666,7 @@ cleanup_entry(struct ip6t_entry *e, unsi
 	if (t->u.kernel.target->destroy)
 		t->u.kernel.target->destroy(t->u.kernel.target, t->data,
 					    t->u.kernel.data);
-	module_put(t->u.kernel.target->me);
+	xt_destroy_target(t);
 	return 0;
 }
 
@@ -769,7 +732,7 @@ translate_table(const char *name,
 	/* Finally, each sanity check must pass */
 	i = 0;
 	ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
-				check_entry, name, size, &i);
+				init_entry, name, size, &i);
 
 	if (ret != 0)
 		goto cleanup;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 679c430..7f2b16c 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -304,35 +304,91 @@ int xt_find_revision(int af, const char
 }
 EXPORT_SYMBOL_GPL(xt_find_revision);
 
-int xt_init_match(const struct xt_match *match, unsigned short family,
-                  unsigned int size, const char *table, unsigned int hook_mask,
+int xt_init_match(struct xt_entry_match *m,
+		  unsigned short family, const char *table,
+		  unsigned int hook_mask, const void *ip,
 		  unsigned short proto, int inv_proto)
 {
+	struct xt_match *match;
+	unsigned int size = (m->u.match_size - sizeof(*m));
+	int ret=0;
+
+	match = try_then_request_module(xt_find_match(family, m->u.user.name,
+						   m->u.user.revision),
+					"%st_%s",
+					xt_prefix[family], m->u.user.name);
+	if (IS_ERR(match) || !match) {
+		duprintf("init_match: `%s' not found\n", m->u.user.name);
+		m->u.kernel.match = NULL;
+		m->u.kernel.data = NULL;
+		return match ? PTR_ERR(match) : -ENOENT;
+	}
+	m->u.kernel.match = match;
+	m->u.kernel.data = NULL;
+
 	if (XT_ALIGN(match->matchsize) != size) {
 		printk("%s_tables: %s match: invalid size %Zu != %u\n",
 		       xt_prefix[family], match->name,
 		       XT_ALIGN(match->matchsize), size);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err;
 	}
 	if (match->table && strcmp(match->table, table)) {
 		printk("%s_tables: %s match: only valid in %s table, not %s\n",
 		       xt_prefix[family], match->name, match->table, table);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err;
 	}
 	if (match->hooks && (hook_mask & ~match->hooks) != 0) {
 		printk("%s_tables: %s match: bad hook_mask %u\n",
 		       xt_prefix[family], match->name, hook_mask);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err;
 	}
 	if (match->proto && (match->proto != proto || inv_proto)) {
 		printk("%s_tables: %s match: only valid for protocol %u\n",
 		       xt_prefix[family], match->name, match->proto);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err;
 	}
+
+	if (match->datasize) {
+		m->u.kernel.data = kzalloc(match->datasize,
+					   GFP_KERNEL);
+		if (!m->u.kernel.data) {
+			printk("%s_tables: %s match: "
+			       "unable to allocate memory\n",
+			       xt_prefix[family], match->name);
+			ret = -ENOMEM;
+			goto err;
+		}
+	}
+
+	if (m->u.kernel.match->init
+	    && !m->u.kernel.match->init(table, ip, m->u.kernel.match, m->data,
+					m->u.kernel.data, hook_mask)) {
+		duprintf("ip_tables: check failed for `%s'.\n",
+			 m->u.kernel.match->name);
+		ret = -EINVAL;
+		goto err;
+	}
+
 	return 0;
+err:
+	xt_destroy_match(m);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(xt_init_match);
 
+void xt_destroy_match(struct xt_entry_match *m)
+{
+	BUG_ON(!m);
+	kfree(m->u.kernel.data);
+	if (m->u.kernel.match)
+		module_put(m->u.kernel.match->me);
+}
+EXPORT_SYMBOL_GPL(xt_destroy_match);
+
 #ifdef CONFIG_COMPAT
 int xt_compat_match_offset(struct xt_match *match)
 {
@@ -394,10 +450,28 @@ int xt_compat_match_to_user(struct xt_en
 EXPORT_SYMBOL_GPL(xt_compat_match_to_user);
 #endif /* CONFIG_COMPAT */
 
-int xt_init_target(const struct xt_target *target, unsigned short family,
-		   unsigned int size, const char *table, unsigned int hook_mask,
-		   unsigned short proto, int inv_proto)
+int xt_init_target(struct xt_entry_target *t,
+		   unsigned short family, const char *table,
+		   unsigned int hook_mask, unsigned short proto,
+		   int inv_proto)
 {
+	struct xt_target *target;
+	unsigned int size = t->u.target_size - sizeof(*t);
+	
+	target = try_then_request_module(xt_find_target(family,
+						     t->u.user.name,
+						     t->u.user.revision),
+					 "%st_%s",
+					 xt_prefix[family], t->u.user.name);
+	if (IS_ERR(target) || !target) {
+		duprintf("init_target: `%s' not found\n", t->u.user.name);
+		t->u.kernel.target = NULL;
+		t->u.kernel.data = NULL;
+		return target ? PTR_ERR(target) : -ENOENT;
+	}
+	t->u.kernel.target = target;
+	t->u.kernel.data = NULL;
+
 	if (XT_ALIGN(target->targetsize) != size) {
 		printk("%s_tables: %s target: invalid size %Zu != %u\n",
 		       xt_prefix[family], target->name,
@@ -419,10 +493,31 @@ int xt_init_target(const struct xt_targe
 		       xt_prefix[family], target->name, target->proto);
 		return -EINVAL;
 	}
+
+	if (target->datasize) {
+		t->u.kernel.data = kzalloc(target->datasize,
+					   GFP_KERNEL);
+		if (!t->u.kernel.data) {
+			printk("%s_tables: %s target: "
+			       "unable to allocate memory\n",
+			       xt_prefix[family], target->name);
+			return -ENOMEM;
+		}
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(xt_init_target);
 
+void xt_destroy_target(struct xt_entry_target *t)
+{
+	BUG_ON(!t);
+	kfree(t->u.kernel.data);
+	if (t->u.kernel.target)
+		module_put(t->u.kernel.target->me);
+}
+EXPORT_SYMBOL_GPL(xt_destroy_target);
+
 #ifdef CONFIG_COMPAT
 int xt_compat_target_offset(struct xt_target *target)
 {
-- 
1.4.3.3

  parent reply	other threads:[~2006-12-05 22:17 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-12-05 22:12 [PATCH 0/4][data-condition] Massimiliano Hofer
2006-12-05 22:15 ` [PATCH 1/4][data-condition]: instance data support in matches' prototypes and structures Massimiliano Hofer
2006-12-05 22:16 ` [PATCH 2/4][data-condition]: instance data support in targets' " Massimiliano Hofer
2006-12-05 22:17 ` Massimiliano Hofer [this message]
2006-12-05 22:18 ` [PATCH 4/4][data-condition]: condition match Massimiliano Hofer
2006-12-05 22:22 ` [PATCH -/4][data-condition]: userspace code Massimiliano Hofer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200612052317.09549.max@nucleus.it \
    --to=max@nucleus.it \
    --cc=kaber@trash.net \
    --cc=netfilter-devel@lists.netfilter.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.