[NETFILTER]: nf_conntrack: split out protocol handling
[deliverable/linux.git] / net / netfilter / nf_conntrack_proto.c
CommitLineData
8f03dea5
MJ
1/* L3/L4 protocol support for nf_conntrack. */
2
3/* (C) 1999-2001 Paul `Rusty' Russell
4 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
5 * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/types.h>
13#include <linux/netfilter.h>
14#include <linux/module.h>
15#include <linux/skbuff.h>
16#include <linux/vmalloc.h>
17#include <linux/stddef.h>
18#include <linux/err.h>
19#include <linux/percpu.h>
20#include <linux/moduleparam.h>
21#include <linux/notifier.h>
22#include <linux/kernel.h>
23#include <linux/netdevice.h>
24
25#include <net/netfilter/nf_conntrack.h>
26#include <net/netfilter/nf_conntrack_l3proto.h>
27#include <net/netfilter/nf_conntrack_protocol.h>
28#include <net/netfilter/nf_conntrack_core.h>
29
30struct nf_conntrack_protocol **nf_ct_protos[PF_MAX] __read_mostly;
31struct nf_conntrack_l3proto *nf_ct_l3protos[PF_MAX] __read_mostly;
32
33struct nf_conntrack_protocol *
34__nf_ct_proto_find(u_int16_t l3proto, u_int8_t protocol)
35{
36 if (unlikely(l3proto >= AF_MAX || nf_ct_protos[l3proto] == NULL))
37 return &nf_conntrack_generic_protocol;
38
39 return nf_ct_protos[l3proto][protocol];
40}
41
42/* this is guaranteed to always return a valid protocol helper, since
43 * it falls back to generic_protocol */
44struct nf_conntrack_protocol *
45nf_ct_proto_find_get(u_int16_t l3proto, u_int8_t protocol)
46{
47 struct nf_conntrack_protocol *p;
48
49 preempt_disable();
50 p = __nf_ct_proto_find(l3proto, protocol);
51 if (!try_module_get(p->me))
52 p = &nf_conntrack_generic_protocol;
53 preempt_enable();
54
55 return p;
56}
57
58void nf_ct_proto_put(struct nf_conntrack_protocol *p)
59{
60 module_put(p->me);
61}
62
63struct nf_conntrack_l3proto *
64nf_ct_l3proto_find_get(u_int16_t l3proto)
65{
66 struct nf_conntrack_l3proto *p;
67
68 preempt_disable();
69 p = __nf_ct_l3proto_find(l3proto);
70 if (!try_module_get(p->me))
71 p = &nf_conntrack_generic_l3proto;
72 preempt_enable();
73
74 return p;
75}
76
77void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p)
78{
79 module_put(p->me);
80}
81
82int
83nf_ct_l3proto_try_module_get(unsigned short l3proto)
84{
85 int ret;
86 struct nf_conntrack_l3proto *p;
87
88retry: p = nf_ct_l3proto_find_get(l3proto);
89 if (p == &nf_conntrack_generic_l3proto) {
90 ret = request_module("nf_conntrack-%d", l3proto);
91 if (!ret)
92 goto retry;
93
94 return -EPROTOTYPE;
95 }
96
97 return 0;
98}
99
100void nf_ct_l3proto_module_put(unsigned short l3proto)
101{
102 struct nf_conntrack_l3proto *p;
103
104 preempt_disable();
105 p = __nf_ct_l3proto_find(l3proto);
106 preempt_enable();
107
108 module_put(p->me);
109}
110
111static int kill_l3proto(struct nf_conn *i, void *data)
112{
113 return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num ==
114 ((struct nf_conntrack_l3proto *)data)->l3proto);
115}
116
117static int kill_proto(struct nf_conn *i, void *data)
118{
119 struct nf_conntrack_protocol *proto;
120 proto = (struct nf_conntrack_protocol *)data;
121 return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum ==
122 proto->proto) &&
123 (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num ==
124 proto->l3proto);
125}
126
127int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
128{
129 int ret = 0;
130
131 write_lock_bh(&nf_conntrack_lock);
132 if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_generic_l3proto) {
133 ret = -EBUSY;
134 goto out;
135 }
136 nf_ct_l3protos[proto->l3proto] = proto;
137out:
138 write_unlock_bh(&nf_conntrack_lock);
139
140 return ret;
141}
142
143void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
144{
145 write_lock_bh(&nf_conntrack_lock);
146 nf_ct_l3protos[proto->l3proto] = &nf_conntrack_generic_l3proto;
147 write_unlock_bh(&nf_conntrack_lock);
148
149 /* Somebody could be still looking at the proto in bh. */
150 synchronize_net();
151
152 /* Remove all contrack entries for this protocol */
153 nf_ct_iterate_cleanup(kill_l3proto, proto);
154}
155
156/* FIXME: Allow NULL functions and sub in pointers to generic for
157 them. --RR */
158int nf_conntrack_protocol_register(struct nf_conntrack_protocol *proto)
159{
160 int ret = 0;
161
162retry:
163 write_lock_bh(&nf_conntrack_lock);
164 if (nf_ct_protos[proto->l3proto]) {
165 if (nf_ct_protos[proto->l3proto][proto->proto]
166 != &nf_conntrack_generic_protocol) {
167 ret = -EBUSY;
168 goto out_unlock;
169 }
170 } else {
171 /* l3proto may be loaded latter. */
172 struct nf_conntrack_protocol **proto_array;
173 int i;
174
175 write_unlock_bh(&nf_conntrack_lock);
176
177 proto_array = (struct nf_conntrack_protocol **)
178 kmalloc(MAX_NF_CT_PROTO *
179 sizeof(struct nf_conntrack_protocol *),
180 GFP_KERNEL);
181 if (proto_array == NULL) {
182 ret = -ENOMEM;
183 goto out;
184 }
185 for (i = 0; i < MAX_NF_CT_PROTO; i++)
186 proto_array[i] = &nf_conntrack_generic_protocol;
187
188 write_lock_bh(&nf_conntrack_lock);
189 if (nf_ct_protos[proto->l3proto]) {
190 /* bad timing, but no problem */
191 write_unlock_bh(&nf_conntrack_lock);
192 kfree(proto_array);
193 } else {
194 nf_ct_protos[proto->l3proto] = proto_array;
195 write_unlock_bh(&nf_conntrack_lock);
196 }
197
198 /*
199 * Just once because array is never freed until unloading
200 * nf_conntrack.ko
201 */
202 goto retry;
203 }
204
205 nf_ct_protos[proto->l3proto][proto->proto] = proto;
206
207out_unlock:
208 write_unlock_bh(&nf_conntrack_lock);
209out:
210 return ret;
211}
212
213void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto)
214{
215 write_lock_bh(&nf_conntrack_lock);
216 nf_ct_protos[proto->l3proto][proto->proto]
217 = &nf_conntrack_generic_protocol;
218 write_unlock_bh(&nf_conntrack_lock);
219
220 /* Somebody could be still looking at the proto in bh. */
221 synchronize_net();
222
223 /* Remove all contrack entries for this protocol */
224 nf_ct_iterate_cleanup(kill_proto, proto);
225}
This page took 0.064774 seconds and 5 git commands to generate.