diff options
author | Patrick McHardy <kaber@trash.net> | 2006-11-28 20:35:17 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-03 00:31:17 -0500 |
commit | d62f9ed4a490309bd9e5df0b42ba5d096e7b5902 (patch) | |
tree | 8d0791c4e4d711c7ae0c259d80553a85dbfe62bd /net/netfilter | |
parent | f8eb24a89afa12b48fa7e39775faea6d64b8e538 (diff) |
[NETFILTER]: nf_conntrack: automatic sysctl registation for conntrack protocols
Add helper functions for sysctl registration with optional instantiating
of common path elements (like net/netfilter) and use it for support for
automatic registation of conntrack protocol sysctls.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto.c | 102 | ||||
-rw-r--r-- | net/netfilter/nf_sysctl.c | 134 |
3 files changed, 237 insertions, 0 deletions
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 627105df1040..84d529ded952 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -4,6 +4,7 @@ nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_exp | |||
4 | nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o | 4 | nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o |
5 | 5 | ||
6 | obj-$(CONFIG_NETFILTER) = netfilter.o | 6 | obj-$(CONFIG_NETFILTER) = netfilter.o |
7 | obj-$(CONFIG_SYSCTL) += nf_sysctl.o | ||
7 | 8 | ||
8 | obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o | 9 | obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o |
9 | obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o | 10 | obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o |
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index a6a3b1ddd00d..941b5c3754af 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
13 | #include <linux/netfilter.h> | 13 | #include <linux/netfilter.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/mutex.h> | ||
15 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
16 | #include <linux/vmalloc.h> | 17 | #include <linux/vmalloc.h> |
17 | #include <linux/stddef.h> | 18 | #include <linux/stddef.h> |
@@ -30,6 +31,34 @@ | |||
30 | struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly; | 31 | struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly; |
31 | struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly; | 32 | struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly; |
32 | 33 | ||
34 | #ifdef CONFIG_SYSCTL | ||
35 | static DEFINE_MUTEX(nf_ct_proto_sysctl_mutex); | ||
36 | |||
37 | static int | ||
38 | nf_ct_register_sysctl(struct ctl_table_header **header, struct ctl_table *path, | ||
39 | struct ctl_table *table, unsigned int *users) | ||
40 | { | ||
41 | if (*header == NULL) { | ||
42 | *header = nf_register_sysctl_table(path, table); | ||
43 | if (*header == NULL) | ||
44 | return -ENOMEM; | ||
45 | } | ||
46 | if (users != NULL) | ||
47 | (*users)++; | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static void | ||
52 | nf_ct_unregister_sysctl(struct ctl_table_header **header, | ||
53 | struct ctl_table *table, unsigned int *users) | ||
54 | { | ||
55 | if (users != NULL && --*users > 0) | ||
56 | return; | ||
57 | nf_unregister_sysctl_table(*header, table); | ||
58 | *header = NULL; | ||
59 | } | ||
60 | #endif | ||
61 | |||
33 | struct nf_conntrack_l4proto * | 62 | struct nf_conntrack_l4proto * |
34 | __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto) | 63 | __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto) |
35 | { | 64 | { |
@@ -124,6 +153,33 @@ static int kill_l4proto(struct nf_conn *i, void *data) | |||
124 | l4proto->l3proto); | 153 | l4proto->l3proto); |
125 | } | 154 | } |
126 | 155 | ||
156 | static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto) | ||
157 | { | ||
158 | int err = 0; | ||
159 | |||
160 | #ifdef CONFIG_SYSCTL | ||
161 | mutex_lock(&nf_ct_proto_sysctl_mutex); | ||
162 | if (l3proto->ctl_table != NULL) { | ||
163 | err = nf_ct_register_sysctl(&l3proto->ctl_table_header, | ||
164 | l3proto->ctl_table_path, | ||
165 | l3proto->ctl_table, NULL); | ||
166 | } | ||
167 | mutex_unlock(&nf_ct_proto_sysctl_mutex); | ||
168 | #endif | ||
169 | return err; | ||
170 | } | ||
171 | |||
172 | static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto) | ||
173 | { | ||
174 | #ifdef CONFIG_SYSCTL | ||
175 | mutex_lock(&nf_ct_proto_sysctl_mutex); | ||
176 | if (l3proto->ctl_table_header != NULL) | ||
177 | nf_ct_unregister_sysctl(&l3proto->ctl_table_header, | ||
178 | l3proto->ctl_table, NULL); | ||
179 | mutex_unlock(&nf_ct_proto_sysctl_mutex); | ||
180 | #endif | ||
181 | } | ||
182 | |||
127 | int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) | 183 | int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) |
128 | { | 184 | { |
129 | int ret = 0; | 185 | int ret = 0; |
@@ -139,6 +195,12 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) | |||
139 | goto out_unlock; | 195 | goto out_unlock; |
140 | } | 196 | } |
141 | nf_ct_l3protos[proto->l3proto] = proto; | 197 | nf_ct_l3protos[proto->l3proto] = proto; |
198 | write_unlock_bh(&nf_conntrack_lock); | ||
199 | |||
200 | ret = nf_ct_l3proto_register_sysctl(proto); | ||
201 | if (ret < 0) | ||
202 | nf_conntrack_l3proto_unregister(proto); | ||
203 | return ret; | ||
142 | 204 | ||
143 | out_unlock: | 205 | out_unlock: |
144 | write_unlock_bh(&nf_conntrack_lock); | 206 | write_unlock_bh(&nf_conntrack_lock); |
@@ -165,6 +227,8 @@ int nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto) | |||
165 | nf_ct_l3protos[proto->l3proto] = &nf_conntrack_l3proto_generic; | 227 | nf_ct_l3protos[proto->l3proto] = &nf_conntrack_l3proto_generic; |
166 | write_unlock_bh(&nf_conntrack_lock); | 228 | write_unlock_bh(&nf_conntrack_lock); |
167 | 229 | ||
230 | nf_ct_l3proto_unregister_sysctl(proto); | ||
231 | |||
168 | /* Somebody could be still looking at the proto in bh. */ | 232 | /* Somebody could be still looking at the proto in bh. */ |
169 | synchronize_net(); | 233 | synchronize_net(); |
170 | 234 | ||
@@ -175,6 +239,36 @@ out: | |||
175 | return ret; | 239 | return ret; |
176 | } | 240 | } |
177 | 241 | ||
242 | static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto) | ||
243 | { | ||
244 | int err = 0; | ||
245 | |||
246 | #ifdef CONFIG_SYSCTL | ||
247 | mutex_lock(&nf_ct_proto_sysctl_mutex); | ||
248 | if (l4proto->ctl_table != NULL) { | ||
249 | err = nf_ct_register_sysctl(l4proto->ctl_table_header, | ||
250 | nf_net_netfilter_sysctl_path, | ||
251 | l4proto->ctl_table, | ||
252 | l4proto->ctl_table_users); | ||
253 | } | ||
254 | mutex_unlock(&nf_ct_proto_sysctl_mutex); | ||
255 | #endif | ||
256 | return err; | ||
257 | } | ||
258 | |||
259 | static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto) | ||
260 | { | ||
261 | #ifdef CONFIG_SYSCTL | ||
262 | mutex_lock(&nf_ct_proto_sysctl_mutex); | ||
263 | if (l4proto->ctl_table_header != NULL && | ||
264 | *l4proto->ctl_table_header != NULL) | ||
265 | nf_ct_unregister_sysctl(l4proto->ctl_table_header, | ||
266 | l4proto->ctl_table, | ||
267 | l4proto->ctl_table_users); | ||
268 | mutex_unlock(&nf_ct_proto_sysctl_mutex); | ||
269 | #endif | ||
270 | } | ||
271 | |||
178 | /* FIXME: Allow NULL functions and sub in pointers to generic for | 272 | /* FIXME: Allow NULL functions and sub in pointers to generic for |
179 | them. --RR */ | 273 | them. --RR */ |
180 | int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto) | 274 | int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto) |
@@ -230,6 +324,12 @@ retry: | |||
230 | } | 324 | } |
231 | 325 | ||
232 | nf_ct_protos[l4proto->l3proto][l4proto->l4proto] = l4proto; | 326 | nf_ct_protos[l4proto->l3proto][l4proto->l4proto] = l4proto; |
327 | write_unlock_bh(&nf_conntrack_lock); | ||
328 | |||
329 | ret = nf_ct_l4proto_register_sysctl(l4proto); | ||
330 | if (ret < 0) | ||
331 | nf_conntrack_l4proto_unregister(l4proto); | ||
332 | return ret; | ||
233 | 333 | ||
234 | out_unlock: | 334 | out_unlock: |
235 | write_unlock_bh(&nf_conntrack_lock); | 335 | write_unlock_bh(&nf_conntrack_lock); |
@@ -257,6 +357,8 @@ int nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto) | |||
257 | = &nf_conntrack_l4proto_generic; | 357 | = &nf_conntrack_l4proto_generic; |
258 | write_unlock_bh(&nf_conntrack_lock); | 358 | write_unlock_bh(&nf_conntrack_lock); |
259 | 359 | ||
360 | nf_ct_l4proto_unregister_sysctl(l4proto); | ||
361 | |||
260 | /* Somebody could be still looking at the proto in bh. */ | 362 | /* Somebody could be still looking at the proto in bh. */ |
261 | synchronize_net(); | 363 | synchronize_net(); |
262 | 364 | ||
diff --git a/net/netfilter/nf_sysctl.c b/net/netfilter/nf_sysctl.c new file mode 100644 index 000000000000..06ddddb2911f --- /dev/null +++ b/net/netfilter/nf_sysctl.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* nf_sysctl.c netfilter sysctl registration/unregistation | ||
2 | * | ||
3 | * Copyright (c) 2006 Patrick McHardy <kaber@trash.net> | ||
4 | */ | ||
5 | #include <linux/module.h> | ||
6 | #include <linux/sysctl.h> | ||
7 | #include <linux/string.h> | ||
8 | #include <linux/slab.h> | ||
9 | |||
10 | static void | ||
11 | path_free(struct ctl_table *path, struct ctl_table *table) | ||
12 | { | ||
13 | struct ctl_table *t, *next; | ||
14 | |||
15 | for (t = path; t != NULL && t != table; t = next) { | ||
16 | next = t->child; | ||
17 | kfree(t); | ||
18 | } | ||
19 | } | ||
20 | |||
21 | static struct ctl_table * | ||
22 | path_dup(struct ctl_table *path, struct ctl_table *table) | ||
23 | { | ||
24 | struct ctl_table *t, *last = NULL, *tmp; | ||
25 | |||
26 | for (t = path; t != NULL; t = t->child) { | ||
27 | /* twice the size since path elements are terminated by an | ||
28 | * empty element */ | ||
29 | tmp = kmemdup(t, 2 * sizeof(*t), GFP_KERNEL); | ||
30 | if (tmp == NULL) { | ||
31 | if (last != NULL) | ||
32 | path_free(path, table); | ||
33 | return NULL; | ||
34 | } | ||
35 | |||
36 | if (last != NULL) | ||
37 | last->child = tmp; | ||
38 | else | ||
39 | path = tmp; | ||
40 | last = tmp; | ||
41 | } | ||
42 | |||
43 | if (last != NULL) | ||
44 | last->child = table; | ||
45 | else | ||
46 | path = table; | ||
47 | |||
48 | return path; | ||
49 | } | ||
50 | |||
51 | struct ctl_table_header * | ||
52 | nf_register_sysctl_table(struct ctl_table *path, struct ctl_table *table) | ||
53 | { | ||
54 | struct ctl_table_header *header; | ||
55 | |||
56 | path = path_dup(path, table); | ||
57 | if (path == NULL) | ||
58 | return NULL; | ||
59 | header = register_sysctl_table(path, 0); | ||
60 | if (header == NULL) | ||
61 | path_free(path, table); | ||
62 | return header; | ||
63 | } | ||
64 | EXPORT_SYMBOL_GPL(nf_register_sysctl_table); | ||
65 | |||
66 | void | ||
67 | nf_unregister_sysctl_table(struct ctl_table_header *header, | ||
68 | struct ctl_table *table) | ||
69 | { | ||
70 | struct ctl_table *path = header->ctl_table; | ||
71 | |||
72 | unregister_sysctl_table(header); | ||
73 | path_free(path, table); | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(nf_unregister_sysctl_table); | ||
76 | |||
77 | /* net/netfilter */ | ||
78 | static struct ctl_table nf_net_netfilter_table[] = { | ||
79 | { | ||
80 | .ctl_name = NET_NETFILTER, | ||
81 | .procname = "netfilter", | ||
82 | .mode = 0555, | ||
83 | }, | ||
84 | { | ||
85 | .ctl_name = 0 | ||
86 | } | ||
87 | }; | ||
88 | struct ctl_table nf_net_netfilter_sysctl_path[] = { | ||
89 | { | ||
90 | .ctl_name = CTL_NET, | ||
91 | .procname = "net", | ||
92 | .mode = 0555, | ||
93 | .child = nf_net_netfilter_table, | ||
94 | }, | ||
95 | { | ||
96 | .ctl_name = 0 | ||
97 | } | ||
98 | }; | ||
99 | EXPORT_SYMBOL_GPL(nf_net_netfilter_sysctl_path); | ||
100 | |||
101 | /* net/ipv4/netfilter */ | ||
102 | static struct ctl_table nf_net_ipv4_netfilter_table[] = { | ||
103 | { | ||
104 | .ctl_name = NET_IPV4_NETFILTER, | ||
105 | .procname = "netfilter", | ||
106 | .mode = 0555, | ||
107 | }, | ||
108 | { | ||
109 | .ctl_name = 0 | ||
110 | } | ||
111 | }; | ||
112 | static struct ctl_table nf_net_ipv4_table[] = { | ||
113 | { | ||
114 | .ctl_name = NET_IPV4, | ||
115 | .procname = "ipv4", | ||
116 | .mode = 0555, | ||
117 | .child = nf_net_ipv4_netfilter_table, | ||
118 | }, | ||
119 | { | ||
120 | .ctl_name = 0 | ||
121 | } | ||
122 | }; | ||
123 | struct ctl_table nf_net_ipv4_netfilter_sysctl_path[] = { | ||
124 | { | ||
125 | .ctl_name = CTL_NET, | ||
126 | .procname = "net", | ||
127 | .mode = 0555, | ||
128 | .child = nf_net_ipv4_table, | ||
129 | }, | ||
130 | { | ||
131 | .ctl_name = 0 | ||
132 | } | ||
133 | }; | ||
134 | EXPORT_SYMBOL_GPL(nf_net_ipv4_netfilter_sysctl_path); | ||