allow coexistance of N build and AC build.
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / drivers / net / imq.c
blob080c221d2838cfdc6d7ecf3f1c8f5ed7058a6ca2
1 /*
2 * Pseudo-driver for the intermediate queue device.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Patrick McHardy, <kaber@trash.net>
11 * The first version was written by Martin Devera, <devik@cdi.cz>
13 * Credits: Jan Rafaj <imq2t@cedric.vabo.cz>
14 * - Update patch to 2.4.21
15 * Sebastian Strollo <sstrollo@nortelnetworks.com>
16 * - Fix "Dead-loop on netdevice imq"-issue
17 * Marcel Sebek <sebek64@post.cz>
18 * - Update to 2.6.2-rc1
20 * After some time of inactivity there is a group taking care
21 * of IMQ again: http://www.linuximq.net
24 * 2004/06/30 - New version of IMQ patch to kernels <=2.6.7 including
25 * the following changes:
27 * - Correction of ipv6 support "+"s issue (Hasso Tepper)
28 * - Correction of imq_init_devs() issue that resulted in
29 * kernel OOPS unloading IMQ as module (Norbert Buchmuller)
30 * - Addition of functionality to choose number of IMQ devices
31 * during kernel config (Andre Correa)
32 * - Addition of functionality to choose how IMQ hooks on
33 * PRE and POSTROUTING (after or before NAT) (Andre Correa)
34 * - Cosmetic corrections (Norbert Buchmuller) (Andre Correa)
37 * 2005/12/16 - IMQ versions between 2.6.7 and 2.6.13 were
38 * released with almost no problems. 2.6.14-x was released
39 * with some important changes: nfcache was removed; After
40 * some weeks of trouble we figured out that some IMQ fields
41 * in skb were missing in skbuff.c - skb_clone and copy_skb_header.
42 * These functions are correctly patched by this new patch version.
44 * Thanks for all who helped to figure out all the problems with
45 * 2.6.14.x: Patrick McHardy, Rune Kock, VeNoMouS, Max CtRiX,
46 * Kevin Shanahan, Richard Lucassen, Valery Dachev (hopefully
47 * I didn't forget anybody). I apologize again for my lack of time.
49 * More info at: http://www.linuximq.net/ (Andre Correa)
52 #include <linux/module.h>
53 #include <linux/kernel.h>
54 #include <linux/moduleparam.h>
55 #include <linux/skbuff.h>
56 #include <linux/netdevice.h>
57 #include <linux/rtnetlink.h>
58 #include <linux/if_arp.h>
59 #include <linux/netfilter.h>
60 #include <linux/netfilter_ipv4.h>
61 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
62 #include <linux/netfilter_ipv6.h>
63 #endif
64 #include <linux/imq.h>
65 #include <net/pkt_sched.h>
67 extern int qdisc_restart1(struct net_device *dev);
69 static nf_hookfn imq_nf_hook;
71 static struct nf_hook_ops imq_ingress_ipv4 = {
72 .hook = imq_nf_hook,
73 .owner = THIS_MODULE,
74 .pf = PF_INET,
75 .hooknum = NF_IP_PRE_ROUTING,
76 .priority = NF_IP_PRI_MANGLE + 1
79 static struct nf_hook_ops imq_egress_ipv4 = {
80 .hook = imq_nf_hook,
81 .owner = THIS_MODULE,
82 .pf = PF_INET,
83 .hooknum = NF_IP_POST_ROUTING,
84 .priority = NF_IP_PRI_NAT_SRC - 1
87 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
88 static struct nf_hook_ops imq_ingress_ipv6 = {
89 .hook = imq_nf_hook,
90 .owner = THIS_MODULE,
91 .pf = PF_INET6,
92 .hooknum = NF_IP6_PRE_ROUTING,
93 .priority = NF_IP6_PRI_MANGLE + 1
96 static struct nf_hook_ops imq_egress_ipv6 = {
97 .hook = imq_nf_hook,
98 .owner = THIS_MODULE,
99 .pf = PF_INET6,
100 .hooknum = NF_IP6_POST_ROUTING,
101 .priority = NF_IP6_PRI_NAT_SRC - 1
103 #endif
105 #if defined(CONFIG_IMQ_NUM_DEVS)
106 static unsigned int numdevs = CONFIG_IMQ_NUM_DEVS;
107 #else
108 static unsigned int numdevs = IMQ_MAX_DEVS;
109 #endif
111 static char *behaviour;
113 #if defined(CONFIG_IMQ_BEHAVIOR_BB)
114 static int imq_behaviour = 0;
115 #elif defined(CONFIG_IMQ_BEHAVIOR_BA)
116 static int imq_behaviour = IMQ_BEHAV_EGRESS_AFTER;
117 #elif defined(CONFIG_IMQ_BEHAVIOR_AB)
118 static int imq_behaviour = IMQ_BEHAV_INGRESS_AFTER;
119 #elif defined(CONFIG_IMQ_BEHAVIOR_AA)
120 static int imq_behaviour = IMQ_BEHAV_INGRESS_AFTER | IMQ_BEHAV_EGRESS_AFTER;
121 #else
122 static int imq_behaviour = IMQ_BEHAV_EGRESS_AFTER;
123 #endif
125 static struct net_device *imq_devs;
127 static struct net_device_stats *imq_get_stats(struct net_device *dev)
129 return (struct net_device_stats *)dev->priv;
132 /* called for packets kfree'd in qdiscs at places other than enqueue */
133 static void imq_skb_destructor(struct sk_buff *skb)
135 struct nf_info *info = skb->nf_info;
137 if (info) {
138 if (info->indev)
139 dev_put(info->indev);
140 if (info->outdev)
141 dev_put(info->outdev);
142 kfree(info);
146 static int imq_dev_xmit(struct sk_buff *skb, struct net_device *dev)
148 struct net_device_stats *stats = (struct net_device_stats*) dev->priv;
150 stats->tx_bytes += skb->len;
151 stats->tx_packets++;
153 skb->imq_flags = 0;
154 skb->destructor = NULL;
156 dev->trans_start = jiffies;
157 nf_reinject(skb, skb->nf_info, NF_ACCEPT);
158 return 0;
161 static int imq_nf_queue(struct sk_buff *skb, struct nf_info *info, unsigned queue_num, void *data)
163 struct net_device *dev;
164 struct net_device_stats *stats;
165 struct sk_buff *skb2 = NULL;
166 struct Qdisc *q;
167 unsigned int index = skb->imq_flags & IMQ_F_IFMASK;
168 int ret = -EINVAL;
170 if (index > numdevs)
171 return ret;
173 dev = imq_devs + index;
174 if (!(dev->flags & IFF_UP)) {
175 skb->imq_flags = 0;
176 nf_reinject(skb, info, NF_ACCEPT);
177 return 0;
179 dev->last_rx = jiffies;
181 if (skb->destructor) {
182 skb2 = skb;
183 skb = skb_clone(skb, GFP_ATOMIC);
184 if (!skb)
185 return -ENOMEM;
187 skb->nf_info = info;
189 stats = (struct net_device_stats *)dev->priv;
190 stats->rx_bytes += skb->len;
191 stats->rx_packets++;
193 spin_lock_bh(&dev->queue_lock);
194 q = dev->qdisc;
195 if (q->enqueue) {
196 q->enqueue(skb_get(skb), q);
197 if (skb_shared(skb)) {
198 skb->destructor = imq_skb_destructor;
199 kfree_skb(skb);
200 ret = 0;
203 if (spin_is_locked(&dev->_xmit_lock))
204 netif_schedule(dev);
205 else
206 while (!netif_queue_stopped(dev) && qdisc_restart1(dev) < 0)
207 /* NOTHING */;
209 spin_unlock_bh(&dev->queue_lock);
211 if (skb2)
212 kfree_skb(ret ? skb : skb2);
214 return ret;
217 static struct nf_queue_handler nfqh = {
218 .name = "imq",
219 .outfn = imq_nf_queue,
222 static unsigned int imq_nf_hook(unsigned int hook, struct sk_buff *skb,
223 const struct net_device *indev,
224 const struct net_device *outdev,
225 int (*okfn)(struct sk_buff *))
227 if (skb->imq_flags & IMQ_F_ENQUEUE)
228 return NF_QUEUE;
230 return NF_ACCEPT;
234 static int __init imq_init_hooks(void)
236 int err;
238 if (behaviour) {
239 if (strlen(behaviour) == 2) {
240 if (behaviour[0] == 'b')
241 imq_behaviour &= ~IMQ_BEHAV_INGRESS_AFTER;
242 else if (behaviour[0] == 'a')
243 imq_behaviour |= IMQ_BEHAV_INGRESS_AFTER;
244 else
245 goto errp;
246 if (behaviour[1] == 'b')
247 imq_behaviour &= ~IMQ_BEHAV_EGRESS_AFTER;
248 else if (behaviour[1] == 'a')
249 imq_behaviour |= IMQ_BEHAV_EGRESS_AFTER;
250 else
251 goto errp;
253 else
254 goto errp;
257 if (imq_behaviour & IMQ_BEHAV_INGRESS_AFTER) {
258 imq_ingress_ipv4.priority = NF_IP_PRI_NAT_DST + 1;
259 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
260 imq_ingress_ipv6.priority = NF_IP6_PRI_NAT_DST + 1;
261 #endif
263 if (imq_behaviour & IMQ_BEHAV_EGRESS_AFTER) {
264 imq_egress_ipv4.priority = NF_IP_PRI_LAST;
265 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
266 imq_egress_ipv6.priority = NF_IP6_PRI_LAST;
267 #endif
270 err = nf_register_queue_handler(PF_INET, &nfqh);
271 if (err > 0)
272 goto err1;
273 if ((err = nf_register_hook(&imq_ingress_ipv4)))
274 goto err2;
275 if ((err = nf_register_hook(&imq_egress_ipv4)))
276 goto err3;
277 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
278 if ((err = nf_register_queue_handler(PF_INET6, &nfqh)))
279 goto err4;
280 if ((err = nf_register_hook(&imq_ingress_ipv6)))
281 goto err5;
282 if ((err = nf_register_hook(&imq_egress_ipv6)))
283 goto err6;
284 #endif
286 return 0;
288 errp:
289 printk(KERN_ERR "IMQ: behaviour must be one of these: \"bb\", \"ba\", \"ab\", \"aa\".\n");
290 return -EINVAL;
291 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
292 err6:
293 nf_unregister_hook(&imq_ingress_ipv6);
294 err5:
295 nf_unregister_queue_handler(PF_INET6);
296 err4:
297 nf_unregister_hook(&imq_egress_ipv4);
298 #endif
299 err3:
300 nf_unregister_hook(&imq_ingress_ipv4);
301 err2:
302 nf_unregister_queue_handler(PF_INET);
303 err1:
304 return err;
307 static void __exit imq_unhook(void)
309 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
310 nf_unregister_hook(&imq_ingress_ipv6);
311 nf_unregister_hook(&imq_egress_ipv6);
312 nf_unregister_queue_handler(PF_INET6);
313 #endif
314 nf_unregister_hook(&imq_ingress_ipv4);
315 nf_unregister_hook(&imq_egress_ipv4);
316 nf_unregister_queue_handler(PF_INET);
319 static int __init imq_dev_init(struct net_device *dev)
321 dev->hard_start_xmit = imq_dev_xmit;
322 dev->type = ARPHRD_VOID;
323 dev->mtu = 1500;
324 dev->tx_queue_len = 30;
325 dev->flags = IFF_NOARP;
326 dev->priv = kzalloc(sizeof(struct net_device_stats), GFP_KERNEL);
327 if (dev->priv == NULL)
328 return -ENOMEM;
329 dev->get_stats = imq_get_stats;
331 return 0;
334 static void imq_dev_uninit(struct net_device *dev)
336 kfree(dev->priv);
339 static int __init imq_init_devs(void)
341 struct net_device *dev;
342 int i,j;
343 j = numdevs;
345 if (numdevs < 1 || numdevs > IMQ_MAX_DEVS) {
346 printk(KERN_ERR "IMQ: numdevs has to be betweed 1 and %u\n",
347 IMQ_MAX_DEVS);
348 return -EINVAL;
351 imq_devs = kzalloc(sizeof(struct net_device) * numdevs, GFP_KERNEL);
352 if (!imq_devs)
353 return -ENOMEM;
355 /* we start counting at zero */
356 numdevs--;
358 for (i = 0, dev = imq_devs; i <= numdevs; i++, dev++) {
359 SET_MODULE_OWNER(dev);
360 strcpy(dev->name, "imq%d");
361 dev->init = imq_dev_init;
362 dev->uninit = imq_dev_uninit;
364 if (register_netdev(dev) < 0)
365 goto err_register;
367 printk(KERN_INFO "IMQ starting with %u devices...\n", j);
368 return 0;
370 err_register:
371 for (; i; i--)
372 unregister_netdev(--dev);
373 kfree(imq_devs);
374 return -EIO;
377 static void imq_cleanup_devs(void)
379 int i;
380 struct net_device *dev = imq_devs;
382 for (i = 0; i <= numdevs; i++)
383 unregister_netdev(dev++);
385 kfree(imq_devs);
388 static int __init imq_init_module(void)
390 int err;
392 if ((err = imq_init_devs())) {
393 printk(KERN_ERR "IMQ: Error trying imq_init_devs()\n");
394 return err;
396 if ((err = imq_init_hooks())) {
397 printk(KERN_ERR "IMQ: Error trying imq_init_hooks()\n");
398 imq_cleanup_devs();
399 return err;
402 printk(KERN_INFO "IMQ driver loaded successfully.\n");
404 if (imq_behaviour & IMQ_BEHAV_INGRESS_AFTER)
405 printk(KERN_INFO "\tHooking IMQ after NAT on PREROUTING.\n");
406 else
407 printk(KERN_INFO "\tHooking IMQ before NAT on PREROUTING.\n");
408 if (imq_behaviour & IMQ_BEHAV_EGRESS_AFTER)
409 printk(KERN_INFO "\tHooking IMQ after NAT on POSTROUTING.\n");
410 else
411 printk(KERN_INFO "\tHooking IMQ before NAT on POSTROUTING.\n");
413 return 0;
416 static void __exit imq_cleanup_module(void)
418 imq_unhook();
419 imq_cleanup_devs();
420 printk(KERN_INFO "IMQ driver unloaded successfully.\n");
424 module_init(imq_init_module);
425 module_exit(imq_cleanup_module);
427 module_param(numdevs, int, IMQ_MAX_DEVS);
428 MODULE_PARM_DESC(numdevs, "number of IMQ devices (how many imq* devices will be created)");
429 module_param(behaviour, charp, 0);
430 MODULE_PARM_DESC(behaviour, "where to hook in PREROUTING and POSTROUTING - before or after NAT (aa,ab,ba,bb)");
431 MODULE_AUTHOR("http://www.linuximq.net");
432 MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See http://www.linuximq.net/ for more information.");
433 MODULE_LICENSE("GPL");