mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-09-20 02:15:28 +03:00
dab3ca1324
git-svn-id: svn://svn.openwrt.org/openwrt/trunk/openwrt@2877 3c298f89-4303-0410-b956-a3cf2f4a3e73
626 lines
18 KiB
Diff
626 lines
18 KiB
Diff
diff -ruN linux-2.4.30-old/Documentation/Configure.help linux-2.4.30-new/Documentation/Configure.help
|
|
--- linux-2.4.30-old/Documentation/Configure.help 2005-11-13 21:52:27.000000000 +0100
|
|
+++ linux-2.4.30-new/Documentation/Configure.help 2005-11-13 22:20:15.000000000 +0100
|
|
@@ -2979,6 +2979,14 @@
|
|
If you want to compile it as a module, say M here and read
|
|
<file:Documentation/modules.txt>. If unsure, say `N'.
|
|
|
|
+Condition variable match support
|
|
+CONFIG_IP_NF_MATCH_CONDITION
|
|
+ This option allows you to match firewall rules against condition
|
|
+ variables stored in the /proc/net/ipt_condition directory.
|
|
+
|
|
+ If you want to compile it as a module, say M here and read
|
|
+ Documentation/modules.txt. If unsure, say `N'.
|
|
+
|
|
conntrack match support
|
|
CONFIG_IP_NF_MATCH_CONNTRACK
|
|
This is a general conntrack match module, a superset of the state match.
|
|
@@ -3354,6 +3362,14 @@
|
|
If you want to compile it as a module, say M here and read
|
|
<file:Documentation/modules.txt>. If unsure, say `N'.
|
|
|
|
+Condition variable match support
|
|
+CONFIG_IP6_NF_MATCH_CONDITION
|
|
+ This option allows you to match firewall rules against condition
|
|
+ variables stored in the /proc/net/ipt_condition directory.
|
|
+
|
|
+ If you want to compile it as a module, say M here and read
|
|
+ Documentation/modules.txt. If unsure, say `N'.
|
|
+
|
|
Multiple port match support
|
|
CONFIG_IP6_NF_MATCH_MULTIPORT
|
|
Multiport matching allows you to match TCP or UDP packets based on
|
|
diff -ruN linux-2.4.30-old/include/linux/netfilter_ipv4/ipt_condition.h linux-2.4.30-new/include/linux/netfilter_ipv4/ipt_condition.h
|
|
--- linux-2.4.30-old/include/linux/netfilter_ipv4/ipt_condition.h 1970-01-01 01:00:00.000000000 +0100
|
|
+++ linux-2.4.30-new/include/linux/netfilter_ipv4/ipt_condition.h 2005-11-13 22:20:14.000000000 +0100
|
|
@@ -0,0 +1,11 @@
|
|
+#ifndef __IPT_CONDITION_MATCH__
|
|
+#define __IPT_CONDITION_MATCH__
|
|
+
|
|
+#define CONDITION_NAME_LEN 32
|
|
+
|
|
+struct condition_info {
|
|
+ char name[CONDITION_NAME_LEN];
|
|
+ int invert;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff -ruN linux-2.4.30-old/include/linux/netfilter_ipv6/ip6t_condition.h linux-2.4.30-new/include/linux/netfilter_ipv6/ip6t_condition.h
|
|
--- linux-2.4.30-old/include/linux/netfilter_ipv6/ip6t_condition.h 1970-01-01 01:00:00.000000000 +0100
|
|
+++ linux-2.4.30-new/include/linux/netfilter_ipv6/ip6t_condition.h 2005-11-13 22:20:14.000000000 +0100
|
|
@@ -0,0 +1,11 @@
|
|
+#ifndef __IP6T_CONDITION_MATCH__
|
|
+#define __IP6T_CONDITION_MATCH__
|
|
+
|
|
+#define CONDITION6_NAME_LEN 32
|
|
+
|
|
+struct condition6_info {
|
|
+ char name[CONDITION6_NAME_LEN];
|
|
+ int invert;
|
|
+};
|
|
+
|
|
+#endif
|
|
diff -ruN linux-2.4.30-old/net/ipv4/netfilter/Config.in linux-2.4.30-new/net/ipv4/netfilter/Config.in
|
|
--- linux-2.4.30-old/net/ipv4/netfilter/Config.in 2005-11-13 21:52:27.000000000 +0100
|
|
+++ linux-2.4.30-new/net/ipv4/netfilter/Config.in 2005-11-13 22:20:15.000000000 +0100
|
|
@@ -43,6 +43,7 @@
|
|
dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
|
|
dep_tristate ' Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
|
|
dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
|
|
+ dep_tristate ' condition match support' CONFIG_IP_NF_MATCH_CONDITION $CONFIG_IP_NF_IPTABLES
|
|
dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES
|
|
dep_tristate ' ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES
|
|
dep_tristate ' peer to peer traffic match support' CONFIG_IP_NF_MATCH_IPP2P $CONFIG_IP_NF_IPTABLES
|
|
diff -ruN linux-2.4.30-old/net/ipv4/netfilter/Makefile linux-2.4.30-new/net/ipv4/netfilter/Makefile
|
|
--- linux-2.4.30-old/net/ipv4/netfilter/Makefile 2005-11-13 21:52:27.000000000 +0100
|
|
+++ linux-2.4.30-new/net/ipv4/netfilter/Makefile 2005-11-13 22:20:15.000000000 +0100
|
|
@@ -94,6 +94,7 @@
|
|
obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
|
|
obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
|
|
obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
|
|
+obj-$(CONFIG_IP_NF_MATCH_CONDITION) += ipt_condition.o
|
|
|
|
obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
|
|
|
|
diff -ruN linux-2.4.30-old/net/ipv4/netfilter/ipt_condition.c linux-2.4.30-new/net/ipv4/netfilter/ipt_condition.c
|
|
--- linux-2.4.30-old/net/ipv4/netfilter/ipt_condition.c 1970-01-01 01:00:00.000000000 +0100
|
|
+++ linux-2.4.30-new/net/ipv4/netfilter/ipt_condition.c 2005-11-13 22:20:14.000000000 +0100
|
|
@@ -0,0 +1,256 @@
|
|
+/*-------------------------------------------*\
|
|
+| Netfilter Condition Module |
|
|
+| |
|
|
+| Description: This module allows firewall |
|
|
+| rules to match using condition variables |
|
|
+| stored in /proc files. |
|
|
+| |
|
|
+| Author: Stephane Ouellette 2002-10-22 |
|
|
+| <ouellettes@videotron.ca> |
|
|
+| |
|
|
+| History: |
|
|
+| 2003-02-10 Second version with improved |
|
|
+| locking and simplified code. |
|
|
+| |
|
|
+| This software is distributed under the |
|
|
+| terms of the GNU GPL. |
|
|
+\*-------------------------------------------*/
|
|
+
|
|
+#include<linux/module.h>
|
|
+#include<linux/proc_fs.h>
|
|
+#include<linux/spinlock.h>
|
|
+#include<linux/string.h>
|
|
+#include<asm/atomic.h>
|
|
+#include<linux/netfilter_ipv4/ip_tables.h>
|
|
+#include<linux/netfilter_ipv4/ipt_condition.h>
|
|
+
|
|
+
|
|
+#ifndef CONFIG_PROC_FS
|
|
+#error "Proc file system support is required for this module"
|
|
+#endif
|
|
+
|
|
+
|
|
+MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca>");
|
|
+MODULE_DESCRIPTION("Allows rules to match against condition variables");
|
|
+MODULE_LICENSE("GPL");
|
|
+
|
|
+
|
|
+struct condition_variable {
|
|
+ struct condition_variable *next;
|
|
+ struct proc_dir_entry *status_proc;
|
|
+ atomic_t refcount;
|
|
+ int enabled; /* TRUE == 1, FALSE == 0 */
|
|
+};
|
|
+
|
|
+
|
|
+static rwlock_t list_lock;
|
|
+static struct condition_variable *head = NULL;
|
|
+static struct proc_dir_entry *proc_net_condition = NULL;
|
|
+
|
|
+
|
|
+static int
|
|
+ipt_condition_read_info(char *buffer, char **start, off_t offset,
|
|
+ int length, int *eof, void *data)
|
|
+{
|
|
+ struct condition_variable *var =
|
|
+ (struct condition_variable *) data;
|
|
+
|
|
+ if (offset == 0) {
|
|
+ *start = buffer;
|
|
+ buffer[0] = (var->enabled) ? '1' : '0';
|
|
+ buffer[1] = '\n';
|
|
+ return 2;
|
|
+ }
|
|
+
|
|
+ *eof = 1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static int
|
|
+ipt_condition_write_info(struct file *file, const char *buffer,
|
|
+ unsigned long length, void *data)
|
|
+{
|
|
+ struct condition_variable *var =
|
|
+ (struct condition_variable *) data;
|
|
+
|
|
+ if (length) {
|
|
+ /* Match only on the first character */
|
|
+ switch (buffer[0]) {
|
|
+ case '0':
|
|
+ var->enabled = 0;
|
|
+ break;
|
|
+ case '1':
|
|
+ var->enabled = 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return (int) length;
|
|
+}
|
|
+
|
|
+
|
|
+static int
|
|
+match(const struct sk_buff *skb, const struct net_device *in,
|
|
+ const struct net_device *out, const void *matchinfo, int offset,
|
|
+ const void *hdr, u_int16_t datalen, int *hotdrop)
|
|
+{
|
|
+ const struct condition_info *info =
|
|
+ (const struct condition_info *) matchinfo;
|
|
+ struct condition_variable *var;
|
|
+ int condition_status = 0;
|
|
+
|
|
+ read_lock(&list_lock);
|
|
+
|
|
+ for (var = head; var; var = var->next) {
|
|
+ if (strcmp(info->name, var->status_proc->name) == 0) {
|
|
+ condition_status = var->enabled;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ read_unlock(&list_lock);
|
|
+
|
|
+ return condition_status ^ info->invert;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+static int
|
|
+checkentry(const char *tablename, const struct ipt_ip *ip,
|
|
+ void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
|
|
+{
|
|
+ struct condition_info *info = (struct condition_info *) matchinfo;
|
|
+ struct condition_variable *var, *newvar;
|
|
+
|
|
+ if (matchsize != IPT_ALIGN(sizeof(struct condition_info)))
|
|
+ return 0;
|
|
+
|
|
+ /* The first step is to check if the condition variable already exists. */
|
|
+ /* Here, a read lock is sufficient because we won't change the list */
|
|
+ read_lock(&list_lock);
|
|
+
|
|
+ for (var = head; var; var = var->next) {
|
|
+ if (strcmp(info->name, var->status_proc->name) == 0) {
|
|
+ atomic_inc(&var->refcount);
|
|
+ read_unlock(&list_lock);
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ read_unlock(&list_lock);
|
|
+
|
|
+ /* At this point, we need to allocate a new condition variable */
|
|
+ newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL);
|
|
+
|
|
+ if (!newvar)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ /* Create the condition variable's proc file entry */
|
|
+ newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition);
|
|
+
|
|
+ if (!newvar->status_proc) {
|
|
+ /*
|
|
+ * There are two possibilities:
|
|
+ * 1- Another condition variable with the same name has been created, which is valid.
|
|
+ * 2- There was a memory allocation error.
|
|
+ */
|
|
+ kfree(newvar);
|
|
+ read_lock(&list_lock);
|
|
+
|
|
+ for (var = head; var; var = var->next) {
|
|
+ if (strcmp(info->name, var->status_proc->name) == 0) {
|
|
+ atomic_inc(&var->refcount);
|
|
+ read_unlock(&list_lock);
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ read_unlock(&list_lock);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ atomic_set(&newvar->refcount, 1);
|
|
+ newvar->enabled = 0;
|
|
+ newvar->status_proc->owner = THIS_MODULE;
|
|
+ newvar->status_proc->data = newvar;
|
|
+ wmb();
|
|
+ newvar->status_proc->read_proc = ipt_condition_read_info;
|
|
+ newvar->status_proc->write_proc = ipt_condition_write_info;
|
|
+
|
|
+ write_lock(&list_lock);
|
|
+
|
|
+ newvar->next = head;
|
|
+ head = newvar;
|
|
+
|
|
+ write_unlock(&list_lock);
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+destroy(void *matchinfo, unsigned int matchsize)
|
|
+{
|
|
+ struct condition_info *info = (struct condition_info *) matchinfo;
|
|
+ struct condition_variable *var, *prev = NULL;
|
|
+
|
|
+ if (matchsize != IPT_ALIGN(sizeof(struct condition_info)))
|
|
+ return;
|
|
+
|
|
+ write_lock(&list_lock);
|
|
+
|
|
+ for (var = head; var && strcmp(info->name, var->status_proc->name);
|
|
+ prev = var, var = var->next);
|
|
+
|
|
+ if (var && atomic_dec_and_test(&var->refcount)) {
|
|
+ if (prev)
|
|
+ prev->next = var->next;
|
|
+ else
|
|
+ head = var->next;
|
|
+
|
|
+ write_unlock(&list_lock);
|
|
+ remove_proc_entry(var->status_proc->name, proc_net_condition);
|
|
+ kfree(var);
|
|
+ } else
|
|
+ write_unlock(&list_lock);
|
|
+}
|
|
+
|
|
+
|
|
+static struct ipt_match condition_match = {
|
|
+ .name = "condition",
|
|
+ .match = &match,
|
|
+ .checkentry = &checkentry,
|
|
+ .destroy = &destroy,
|
|
+ .me = THIS_MODULE
|
|
+};
|
|
+
|
|
+
|
|
+static int __init
|
|
+init(void)
|
|
+{
|
|
+ int errorcode;
|
|
+
|
|
+ rwlock_init(&list_lock);
|
|
+ proc_net_condition = proc_mkdir("ipt_condition", proc_net);
|
|
+
|
|
+ if (proc_net_condition) {
|
|
+ errorcode = ipt_register_match(&condition_match);
|
|
+
|
|
+ if (errorcode)
|
|
+ remove_proc_entry("ipt_condition", proc_net);
|
|
+ } else
|
|
+ errorcode = -EACCES;
|
|
+
|
|
+ return errorcode;
|
|
+}
|
|
+
|
|
+
|
|
+static void __exit
|
|
+fini(void)
|
|
+{
|
|
+ ipt_unregister_match(&condition_match);
|
|
+ remove_proc_entry("ipt_condition", proc_net);
|
|
+}
|
|
+
|
|
+module_init(init);
|
|
+module_exit(fini);
|
|
diff -ruN linux-2.4.30-old/net/ipv6/netfilter/Config.in linux-2.4.30-new/net/ipv6/netfilter/Config.in
|
|
--- linux-2.4.30-old/net/ipv6/netfilter/Config.in 2003-06-13 16:51:39.000000000 +0200
|
|
+++ linux-2.4.30-new/net/ipv6/netfilter/Config.in 2005-11-13 22:20:15.000000000 +0100
|
|
@@ -17,6 +17,7 @@
|
|
if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; then
|
|
# The simple matches.
|
|
dep_tristate ' limit match support' CONFIG_IP6_NF_MATCH_LIMIT $CONFIG_IP6_NF_IPTABLES
|
|
+ dep_tristate ' condition match support' CONFIG_IP6_NF_MATCH_CONDITION $CONFIG_IP6_NF_IPTABLES
|
|
dep_tristate ' MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES
|
|
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
|
|
dep_tristate ' Routing header match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_RT $CONFIG_IP6_NF_IPTABLES
|
|
diff -ruN linux-2.4.30-old/net/ipv6/netfilter/Makefile linux-2.4.30-new/net/ipv6/netfilter/Makefile
|
|
--- linux-2.4.30-old/net/ipv6/netfilter/Makefile 2003-06-13 16:51:39.000000000 +0200
|
|
+++ linux-2.4.30-new/net/ipv6/netfilter/Makefile 2005-11-13 22:20:15.000000000 +0100
|
|
@@ -14,6 +14,7 @@
|
|
# Link order matters here.
|
|
obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
|
|
obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o
|
|
+obj-$(CONFIG_IP6_NF_MATCH_CONDITION) += ip6t_condition.o
|
|
obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
|
|
obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
|
|
obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
|
|
diff -ruN linux-2.4.30-old/net/ipv6/netfilter/ip6t_condition.c linux-2.4.30-new/net/ipv6/netfilter/ip6t_condition.c
|
|
--- linux-2.4.30-old/net/ipv6/netfilter/ip6t_condition.c 1970-01-01 01:00:00.000000000 +0100
|
|
+++ linux-2.4.30-new/net/ipv6/netfilter/ip6t_condition.c 2005-11-13 22:20:14.000000000 +0100
|
|
@@ -0,0 +1,254 @@
|
|
+/*-------------------------------------------*\
|
|
+| Netfilter Condition Module for IPv6 |
|
|
+| |
|
|
+| Description: This module allows firewall |
|
|
+| rules to match using condition variables |
|
|
+| stored in /proc files. |
|
|
+| |
|
|
+| Author: Stephane Ouellette 2003-02-10 |
|
|
+| <ouellettes@videotron.ca> |
|
|
+| |
|
|
+| This software is distributed under the |
|
|
+| terms of the GNU GPL. |
|
|
+\*-------------------------------------------*/
|
|
+
|
|
+#include<linux/module.h>
|
|
+#include<linux/proc_fs.h>
|
|
+#include<linux/spinlock.h>
|
|
+#include<linux/string.h>
|
|
+#include<asm/atomic.h>
|
|
+#include<linux/netfilter_ipv6/ip6_tables.h>
|
|
+#include<linux/netfilter_ipv6/ip6t_condition.h>
|
|
+
|
|
+
|
|
+#ifndef CONFIG_PROC_FS
|
|
+#error "Proc file system support is required for this module"
|
|
+#endif
|
|
+
|
|
+
|
|
+MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca>");
|
|
+MODULE_DESCRIPTION("Allows rules to match against condition variables");
|
|
+MODULE_LICENSE("GPL");
|
|
+
|
|
+
|
|
+struct condition_variable {
|
|
+ struct condition_variable *next;
|
|
+ struct proc_dir_entry *status_proc;
|
|
+ atomic_t refcount;
|
|
+ int enabled; /* TRUE == 1, FALSE == 0 */
|
|
+};
|
|
+
|
|
+
|
|
+static rwlock_t list_lock;
|
|
+static struct condition_variable *head = NULL;
|
|
+static struct proc_dir_entry *proc_net_condition = NULL;
|
|
+
|
|
+
|
|
+static int
|
|
+ipt_condition_read_info(char *buffer, char **start, off_t offset,
|
|
+ int length, int *eof, void *data)
|
|
+{
|
|
+ struct condition_variable *var =
|
|
+ (struct condition_variable *) data;
|
|
+
|
|
+ if (offset == 0) {
|
|
+ *start = buffer;
|
|
+ buffer[0] = (var->enabled) ? '1' : '0';
|
|
+ buffer[1] = '\n';
|
|
+ return 2;
|
|
+ }
|
|
+
|
|
+ *eof = 1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static int
|
|
+ipt_condition_write_info(struct file *file, const char *buffer,
|
|
+ unsigned long length, void *data)
|
|
+{
|
|
+ struct condition_variable *var =
|
|
+ (struct condition_variable *) data;
|
|
+
|
|
+ if (length) {
|
|
+ /* Match only on the first character */
|
|
+ switch (buffer[0]) {
|
|
+ case '0':
|
|
+ var->enabled = 0;
|
|
+ break;
|
|
+ case '1':
|
|
+ var->enabled = 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return (int) length;
|
|
+}
|
|
+
|
|
+
|
|
+static int
|
|
+match(const struct sk_buff *skb, const struct net_device *in,
|
|
+ const struct net_device *out, const void *matchinfo, int offset,
|
|
+ const void *hdr, u_int16_t datalen, int *hotdrop)
|
|
+{
|
|
+ const struct condition6_info *info =
|
|
+ (const struct condition6_info *) matchinfo;
|
|
+ struct condition_variable *var;
|
|
+ int condition_status = 0;
|
|
+
|
|
+ read_lock(&list_lock);
|
|
+
|
|
+ for (var = head; var; var = var->next) {
|
|
+ if (strcmp(info->name, var->status_proc->name) == 0) {
|
|
+ condition_status = var->enabled;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ read_unlock(&list_lock);
|
|
+
|
|
+ return condition_status ^ info->invert;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+static int
|
|
+checkentry(const char *tablename, const struct ip6t_ip6 *ip,
|
|
+ void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
|
|
+{
|
|
+ struct condition6_info *info =
|
|
+ (struct condition6_info *) matchinfo;
|
|
+ struct condition_variable *var, *newvar;
|
|
+
|
|
+ if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info)))
|
|
+ return 0;
|
|
+
|
|
+ /* The first step is to check if the condition variable already exists. */
|
|
+ /* Here, a read lock is sufficient because we won't change the list */
|
|
+ read_lock(&list_lock);
|
|
+
|
|
+ for (var = head; var; var = var->next) {
|
|
+ if (strcmp(info->name, var->status_proc->name) == 0) {
|
|
+ atomic_inc(&var->refcount);
|
|
+ read_unlock(&list_lock);
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ read_unlock(&list_lock);
|
|
+
|
|
+ /* At this point, we need to allocate a new condition variable */
|
|
+ newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL);
|
|
+
|
|
+ if (!newvar)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ /* Create the condition variable's proc file entry */
|
|
+ newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition);
|
|
+
|
|
+ if (!newvar->status_proc) {
|
|
+ /*
|
|
+ * There are two possibilities:
|
|
+ * 1- Another condition variable with the same name has been created, which is valid.
|
|
+ * 2- There was a memory allocation error.
|
|
+ */
|
|
+ kfree(newvar);
|
|
+ read_lock(&list_lock);
|
|
+
|
|
+ for (var = head; var; var = var->next) {
|
|
+ if (strcmp(info->name, var->status_proc->name) == 0) {
|
|
+ atomic_inc(&var->refcount);
|
|
+ read_unlock(&list_lock);
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ read_unlock(&list_lock);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ atomic_set(&newvar->refcount, 1);
|
|
+ newvar->enabled = 0;
|
|
+ newvar->status_proc->owner = THIS_MODULE;
|
|
+ newvar->status_proc->data = newvar;
|
|
+ wmb();
|
|
+ newvar->status_proc->read_proc = ipt_condition_read_info;
|
|
+ newvar->status_proc->write_proc = ipt_condition_write_info;
|
|
+
|
|
+ write_lock(&list_lock);
|
|
+
|
|
+ newvar->next = head;
|
|
+ head = newvar;
|
|
+
|
|
+ write_unlock(&list_lock);
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+destroy(void *matchinfo, unsigned int matchsize)
|
|
+{
|
|
+ struct condition6_info *info =
|
|
+ (struct condition6_info *) matchinfo;
|
|
+ struct condition_variable *var, *prev = NULL;
|
|
+
|
|
+ if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info)))
|
|
+ return;
|
|
+
|
|
+ write_lock(&list_lock);
|
|
+
|
|
+ for (var = head; var && strcmp(info->name, var->status_proc->name);
|
|
+ prev = var, var = var->next);
|
|
+
|
|
+ if (var && atomic_dec_and_test(&var->refcount)) {
|
|
+ if (prev)
|
|
+ prev->next = var->next;
|
|
+ else
|
|
+ head = var->next;
|
|
+
|
|
+ write_unlock(&list_lock);
|
|
+ remove_proc_entry(var->status_proc->name, proc_net_condition);
|
|
+ kfree(var);
|
|
+ } else
|
|
+ write_unlock(&list_lock);
|
|
+}
|
|
+
|
|
+
|
|
+static struct ip6t_match condition_match = {
|
|
+ .name = "condition",
|
|
+ .match = &match,
|
|
+ .checkentry = &checkentry,
|
|
+ .destroy = &destroy,
|
|
+ .me = THIS_MODULE
|
|
+};
|
|
+
|
|
+
|
|
+static int __init
|
|
+init(void)
|
|
+{
|
|
+ int errorcode;
|
|
+
|
|
+ rwlock_init(&list_lock);
|
|
+ proc_net_condition = proc_mkdir("ip6t_condition", proc_net);
|
|
+
|
|
+ if (proc_net_condition) {
|
|
+ errorcode = ipt_register_match(&condition_match);
|
|
+
|
|
+ if (errorcode)
|
|
+ remove_proc_entry("ip6t_condition", proc_net);
|
|
+ } else
|
|
+ errorcode = -EACCES;
|
|
+
|
|
+ return errorcode;
|
|
+}
|
|
+
|
|
+
|
|
+static void __exit
|
|
+fini(void)
|
|
+{
|
|
+ ipt_unregister_match(&condition_match);
|
|
+ remove_proc_entry("ip6t_condition", proc_net);
|
|
+}
|
|
+
|
|
+module_init(init);
|
|
+module_exit(fini);
|