Linux 2.2.0
[davej-history.git] / net / ipv4 / ip_masq_mod.c
blob0053549447536e07c4381bfe4a41abadd257f068
1 /*
2 * IP_MASQ_MOD masq modules support
5 * Author: Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
7 * $Id: ip_masq_mod.c,v 1.5 1998/08/29 23:51:09 davem Exp $
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
14 * Changes:
15 * Cyrus Durgin: fixed kerneld stuff for kmod.
18 #include <linux/config.h>
19 #include <linux/module.h>
20 #include <linux/types.h>
21 #include <linux/kernel.h>
22 #include <linux/errno.h>
23 #include <net/ip_masq.h>
24 #include <net/ip_masq_mod.h>
26 #include <linux/ip_masq.h>
27 #ifdef CONFIG_KMOD
28 #include <linux/kmod.h>
29 #endif
31 EXPORT_SYMBOL(register_ip_masq_mod);
32 EXPORT_SYMBOL(unregister_ip_masq_mod);
33 EXPORT_SYMBOL(ip_masq_mod_lkp_link);
34 EXPORT_SYMBOL(ip_masq_mod_lkp_unlink);
36 #ifdef __SMP__
37 static spinlock_t masq_mod_lock = SPIN_LOCK_UNLOCKED;
38 #endif
41 * Base pointer for registered modules
43 struct ip_masq_mod * ip_masq_mod_reg_base = NULL;
46 * Base pointer for lookup (subset of above, a module could be
47 * registered, but it could have no active rule); will avoid
48 * unnecessary lookups.
50 struct ip_masq_mod * ip_masq_mod_lkp_base = NULL;
52 int ip_masq_mod_register_proc(struct ip_masq_mod *mmod)
54 #ifdef CONFIG_PROC_FS
55 int ret;
57 struct proc_dir_entry *ent = mmod->mmod_proc_ent;
59 if (!ent)
60 return 0;
61 if (!ent->name) {
62 ent->name = mmod->mmod_name;
63 ent->namelen = strlen (mmod->mmod_name);
65 ret = ip_masq_proc_register(ent);
66 if (ret) mmod->mmod_proc_ent = NULL;
68 return ret;
69 #else
70 return 0;
71 #endif
74 void ip_masq_mod_unregister_proc(struct ip_masq_mod *mmod)
76 #ifdef CONFIG_PROC_FS
77 struct proc_dir_entry *ent = mmod->mmod_proc_ent;
78 if (!ent)
79 return;
80 ip_masq_proc_unregister(ent);
81 #endif
85 * Link/unlink object for lookups
88 int ip_masq_mod_lkp_unlink(struct ip_masq_mod *mmod)
90 struct ip_masq_mod **mmod_p;
92 write_lock_bh(&masq_mod_lock);
94 for (mmod_p = &ip_masq_mod_lkp_base; *mmod_p ; mmod_p = &(*mmod_p)->next)
95 if (mmod == (*mmod_p)) {
96 *mmod_p = mmod->next;
97 mmod->next = NULL;
98 write_unlock_bh(&masq_mod_lock);
99 return 0;
102 write_unlock_bh(&masq_mod_lock);
103 return -EINVAL;
106 int ip_masq_mod_lkp_link(struct ip_masq_mod *mmod)
108 write_lock_bh(&masq_mod_lock);
110 mmod->next = ip_masq_mod_lkp_base;
111 ip_masq_mod_lkp_base=mmod;
113 write_unlock_bh(&masq_mod_lock);
114 return 0;
117 int register_ip_masq_mod(struct ip_masq_mod *mmod)
119 if (!mmod) {
120 IP_MASQ_ERR("register_ip_masq_mod(): NULL arg\n");
121 return -EINVAL;
123 if (!mmod->mmod_name) {
124 IP_MASQ_ERR("register_ip_masq_mod(): NULL mmod_name\n");
125 return -EINVAL;
127 ip_masq_mod_register_proc(mmod);
129 mmod->next_reg = ip_masq_mod_reg_base;
130 ip_masq_mod_reg_base=mmod;
132 return 0;
135 int unregister_ip_masq_mod(struct ip_masq_mod *mmod)
137 struct ip_masq_mod **mmod_p;
139 if (!mmod) {
140 IP_MASQ_ERR( "unregister_ip_masq_mod(): NULL arg\n");
141 return -EINVAL;
145 * Only allow unregistration if it is not referenced
147 if (atomic_read(&mmod->refcnt)) {
148 IP_MASQ_ERR( "unregister_ip_masq_mod(): is in use by %d guys. failed\n",
149 atomic_read(&mmod->refcnt));
150 return -EINVAL;
154 * Must be already unlinked from lookup list
156 if (mmod->next) {
157 IP_MASQ_WARNING("MASQ: unregistering \"%s\" while in lookup list.fixed.",
158 mmod->mmod_name);
159 ip_masq_mod_lkp_unlink(mmod);
162 for (mmod_p = &ip_masq_mod_reg_base; *mmod_p ; mmod_p = &(*mmod_p)->next_reg)
163 if (mmod == (*mmod_p)) {
164 ip_masq_mod_unregister_proc(mmod);
165 *mmod_p = mmod->next_reg;
166 return 0;
169 IP_MASQ_ERR("unregister_ip_masq_mod(%s): not linked \n", mmod->mmod_name);
170 return -EINVAL;
173 int ip_masq_mod_in_rule(const struct sk_buff *skb, const struct iphdr *iph)
175 struct ip_masq_mod *mmod;
176 int ret = IP_MASQ_MOD_NOP;
178 for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
179 if (!mmod->mmod_in_rule) continue;
180 switch (ret=mmod->mmod_in_rule(skb, iph)) {
181 case IP_MASQ_MOD_NOP:
182 continue;
183 case IP_MASQ_MOD_ACCEPT:
184 case IP_MASQ_MOD_REJECT:
185 goto out;
188 out:
189 return ret;
192 int ip_masq_mod_out_rule(const struct sk_buff *skb, const struct iphdr *iph)
194 struct ip_masq_mod *mmod;
195 int ret = IP_MASQ_MOD_NOP;
197 for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
198 if (!mmod->mmod_out_rule) continue;
199 switch (ret=mmod->mmod_out_rule(skb, iph)) {
200 case IP_MASQ_MOD_NOP:
201 continue;
202 case IP_MASQ_MOD_ACCEPT:
203 case IP_MASQ_MOD_REJECT:
204 goto out;
207 out:
208 return ret;
211 struct ip_masq * ip_masq_mod_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
213 struct ip_masq_mod *mmod;
214 struct ip_masq *ms = NULL;
216 for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
217 if (!mmod->mmod_in_create) continue;
218 if ((ms=mmod->mmod_in_create(skb, iph, maddr))) {
219 goto out;
222 out:
223 return ms;
226 struct ip_masq * ip_masq_mod_out_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
228 struct ip_masq_mod *mmod;
229 struct ip_masq *ms = NULL;
231 for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
232 if (!mmod->mmod_out_create) continue;
233 if ((ms=mmod->mmod_out_create(skb, iph, maddr))) {
234 goto out;
237 out:
238 return ms;
241 int ip_masq_mod_in_update(const struct sk_buff *skb, const struct iphdr *iph, struct ip_masq *ms)
243 struct ip_masq_mod *mmod;
244 int ret = IP_MASQ_MOD_NOP;
246 for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
247 if (!mmod->mmod_in_update) continue;
248 switch (ret=mmod->mmod_in_update(skb, iph, ms)) {
249 case IP_MASQ_MOD_NOP:
250 continue;
251 case IP_MASQ_MOD_ACCEPT:
252 case IP_MASQ_MOD_REJECT:
253 goto out;
256 out:
257 return ret;
260 int ip_masq_mod_out_update(const struct sk_buff *skb, const struct iphdr *iph, struct ip_masq *ms)
262 struct ip_masq_mod *mmod;
263 int ret = IP_MASQ_MOD_NOP;
265 for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
266 if (!mmod->mmod_out_update) continue;
267 switch (ret=mmod->mmod_out_update(skb, iph, ms)) {
268 case IP_MASQ_MOD_NOP:
269 continue;
270 case IP_MASQ_MOD_ACCEPT:
271 case IP_MASQ_MOD_REJECT:
272 goto out;
275 out:
276 return ret;
279 struct ip_masq_mod * ip_masq_mod_getbyname(const char *mmod_name)
281 struct ip_masq_mod * mmod;
283 IP_MASQ_DEBUG(1, "searching mmod_name \"%s\"\n", mmod_name);
285 for (mmod=ip_masq_mod_reg_base; mmod ; mmod=mmod->next_reg) {
286 if (mmod->mmod_ctl && *(mmod_name)
287 && (strcmp(mmod_name, mmod->mmod_name)==0)) {
288 /* HIT */
289 return mmod;
292 return NULL;
296 * Module control entry
298 int ip_masq_mod_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
300 struct ip_masq_mod * mmod;
301 #ifdef CONFIG_KMOD
302 char kmod_name[IP_MASQ_TNAME_MAX+8];
303 #endif
304 /* tappo */
305 mctl->m_tname[IP_MASQ_TNAME_MAX-1] = 0;
307 mmod = ip_masq_mod_getbyname(mctl->m_tname);
308 if (mmod)
309 return mmod->mmod_ctl(optname, mctl, optlen);
310 #ifdef CONFIG_KMOD
311 sprintf(kmod_name,"ip_masq_%s", mctl->m_tname);
313 IP_MASQ_DEBUG(1, "About to request \"%s\" module\n", kmod_name);
316 * Let sleep for a while ...
318 request_module(kmod_name);
319 mmod = ip_masq_mod_getbyname(mctl->m_tname);
320 if (mmod)
321 return mmod->mmod_ctl(optname, mctl, optlen);
322 #endif
323 return ESRCH;