-diff -uNr linux-2.6.39/drivers/net/imq.c linux-2.6.39-imqmq/drivers/net/imq.c
---- linux-2.6.39/drivers/net/imq.c 1970-01-01 02:00:00.000000000 +0200
-+++ linux-2.6.39-imqmq/drivers/net/imq.c 2011-05-19 11:08:03.838522212 +0300
-@@ -0,0 +1,777 @@
+diff -uNr linux-3.0/drivers/net/imq.c linux-3.0-imq/drivers/net/imq.c
+--- linux-3.0/drivers/net/imq.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-3.0-imq/drivers/net/imq.c 2011-07-26 07:24:09.843279145 +0300
+@@ -0,0 +1,820 @@
+/*
+ * Pseudo-driver for the intermediate queue device.
+ *
+ * 2011/03/18 - (Jussi Kivilinna)
+ * - Port to 2.6.38
+ *
++ * 2011/07/12 - (syoder89@gmail.com)
++ * - Crash fix that happens when the receiving interface has more
++ * than one queue (add missing skb_set_queue_mapping in
++ * imq_select_queue).
++ *
++ * 2011/07/26 - (Jussi Kivilinna)
++ * - Add queue mapping checks for packets exiting IMQ.
++ * - Port to 3.0
++ *
+ * Also, many thanks to pablo Sebastian Greco for making the initial
+ * patch and to those who helped the testing.
+ *
+static int numdevs = IMQ_MAX_DEVS;
+#endif
+
-+#define IMQ_MAX_QUEUES 32
-+static int numqueues = 1;
-+
-+/*static DEFINE_SPINLOCK(imq_nf_queue_lock);*/
-+
+static struct net_device *imq_devs_cache[IMQ_MAX_DEVS];
+
-+
-+static struct net_device_stats *imq_get_stats(struct net_device *dev)
-+{
-+ return &dev->stats;
-+}
-+
-+/* called for packets kfree'd in qdiscs at places other than enqueue */
-+static void imq_skb_destructor(struct sk_buff *skb)
-+{
-+ struct nf_queue_entry *entry = skb->nf_queue_entry;
-+
-+ skb->nf_queue_entry = NULL;
-+
-+ if (entry) {
-+ nf_queue_entry_release_refs(entry);
-+ kfree(entry);
-+ }
-+
-+ skb_restore_cb(skb); /* kfree backup */
-+}
-+
-+static netdev_tx_t imq_dev_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+ struct nf_queue_entry *entry = skb->nf_queue_entry;
-+
-+ skb->nf_queue_entry = NULL;
-+ dev->trans_start = jiffies;
-+
-+ dev->stats.tx_bytes += skb->len;
-+ dev->stats.tx_packets++;
-+
-+ if (entry == NULL) {
-+ /* We don't know what is going on here.. packet is queued for
-+ * imq device, but (probably) not by us.
-+ *
-+ * If this packet was not send here by imq_nf_queue(), then
-+ * skb_save_cb() was not used and skb_free() should not show:
-+ * WARNING: IMQ: kfree_skb: skb->cb_next:..
-+ * and/or
-+ * WARNING: IMQ: kfree_skb: skb->nf_queue_entry...
-+ *
-+ * However if this message is shown, then IMQ is somehow broken
-+ * and you should report this to linuximq.net.
-+ */
-+
-+ /* imq_dev_xmit is black hole that eats all packets, report that
-+ * we eat this packet happily and increase dropped counters.
-+ */
-+
-+ dev->stats.tx_dropped++;
-+ dev_kfree_skb(skb);
-+
-+ return NETDEV_TX_OK;
-+ }
-+
-+ skb_restore_cb(skb); /* restore skb->cb */
-+
-+ skb->imq_flags = 0;
-+ skb->destructor = NULL;
-+
-+ nf_reinject(entry, NF_ACCEPT);
-+
-+ return NETDEV_TX_OK;
-+}
-+
++#define IMQ_MAX_QUEUES 32
++static int numqueues = 1;
+static u32 imq_hashrnd;
+
+static inline __be16 pppoe_proto(const struct sk_buff *skb)
+ if (unlikely(queue_index >= dev->real_num_tx_queues))
+ queue_index = (u16)((u32)queue_index % dev->real_num_tx_queues);
+
++ skb_set_queue_mapping(skb, queue_index);
+ return netdev_get_tx_queue(dev, queue_index);
+}
+
++static struct net_device_stats *imq_get_stats(struct net_device *dev)
++{
++ return &dev->stats;
++}
++
++/* called for packets kfree'd in qdiscs at places other than enqueue */
++static void imq_skb_destructor(struct sk_buff *skb)
++{
++ struct nf_queue_entry *entry = skb->nf_queue_entry;
++
++ skb->nf_queue_entry = NULL;
++
++ if (entry) {
++ nf_queue_entry_release_refs(entry);
++ kfree(entry);
++ }
++
++ skb_restore_cb(skb); /* kfree backup */
++}
++
++static void imq_done_check_queue_mapping(struct sk_buff *skb,
++ struct net_device *dev)
++{
++ unsigned int queue_index;
++
++ /* Don't let queue_mapping be left too large after exiting IMQ */
++ if (likely(skb->dev != dev && skb->dev != NULL)) {
++ queue_index = skb_get_queue_mapping(skb);
++ if (unlikely(queue_index >= skb->dev->real_num_tx_queues)) {
++ queue_index = (u16)((u32)queue_index %
++ skb->dev->real_num_tx_queues);
++ skb_set_queue_mapping(skb, queue_index);
++ }
++ } else {
++ /* skb->dev was IMQ device itself or NULL, be on safe side and
++ * just clear queue mapping.
++ */
++ skb_set_queue_mapping(skb, 0);
++ }
++}
++
++static netdev_tx_t imq_dev_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct nf_queue_entry *entry = skb->nf_queue_entry;
++
++ skb->nf_queue_entry = NULL;
++ dev->trans_start = jiffies;
++
++ dev->stats.tx_bytes += skb->len;
++ dev->stats.tx_packets++;
++
++ if (unlikely(entry == NULL)) {
++ /* We don't know what is going on here.. packet is queued for
++ * imq device, but (probably) not by us.
++ *
++ * If this packet was not send here by imq_nf_queue(), then
++ * skb_save_cb() was not used and skb_free() should not show:
++ * WARNING: IMQ: kfree_skb: skb->cb_next:..
++ * and/or
++ * WARNING: IMQ: kfree_skb: skb->nf_queue_entry...
++ *
++ * However if this message is shown, then IMQ is somehow broken
++ * and you should report this to linuximq.net.
++ */
++
++ /* imq_dev_xmit is black hole that eats all packets, report that
++ * we eat this packet happily and increase dropped counters.
++ */
++
++ dev->stats.tx_dropped++;
++ dev_kfree_skb(skb);
++
++ return NETDEV_TX_OK;
++ }
++
++ skb_restore_cb(skb); /* restore skb->cb */
++
++ skb->imq_flags = 0;
++ skb->destructor = NULL;
++
++ imq_done_check_queue_mapping(skb, dev);
++
++ nf_reinject(entry, NF_ACCEPT);
++
++ return NETDEV_TX_OK;
++}
++
+static int imq_nf_queue(struct nf_queue_entry *entry, unsigned queue_num)
+{
+ struct net_device *dev;
+ spinlock_t *root_lock;
+ int users, index;
+ int retval = -EINVAL;
++ unsigned int orig_queue_index;
+
+ index = entry->skb->imq_flags & IMQ_F_IFMASK;
+ if (unlikely(index > numdevs - 1)) {
+ dev->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+
++ if (!skb->dev) {
++ /* skb->dev == NULL causes problems, try the find cause. */
++ if (net_ratelimit()) {
++ dev_warn(&dev->dev,
++ "received packet with skb->dev == NULL\n");
++ dump_stack();
++ }
++
++ skb->dev = dev;
++ }
++
+ /* Disables softirqs for lock below */
+ rcu_read_lock_bh();
+
+ /* Multi-queue selection */
++ orig_queue_index = skb_get_queue_mapping(skb);
+ txq = imq_select_queue(dev, skb);
+
+ q = rcu_dereference(txq->qdisc);
+ }
+
+packet_not_eaten_by_imq_dev:
++ skb_set_queue_mapping(skb, orig_queue_index);
+ rcu_read_unlock_bh();
+
+ /* cloned? restore original */
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_RTNL_LINK("imq");
+
-diff -uNr linux-2.6.39/drivers/net/Kconfig linux-2.6.39-imqmq/drivers/net/Kconfig
---- linux-2.6.39/drivers/net/Kconfig 2011-05-19 07:06:34.000000000 +0300
-+++ linux-2.6.39-imqmq/drivers/net/Kconfig 2011-05-19 11:08:04.281864473 +0300
-@@ -124,6 +124,129 @@
+diff -uNr linux-3.0/drivers/net/Kconfig linux-3.0-imq/drivers/net/Kconfig
+--- linux-3.0/drivers/net/Kconfig 2011-07-22 05:17:23.000000000 +0300
++++ linux-3.0-imq/drivers/net/Kconfig 2011-07-26 06:31:36.176747906 +0300
+@@ -124,6 +124,125 @@
To compile this driver as a module, choose M here: the module
will be called eql. If unsure, say N.
+ depends on IMQ
+ default IMQ_BEHAVIOR_AB
+ help
++ This setting defines how IMQ behaves in respect to its
++ hooking in PREROUTING and POSTROUTING.
+
-+ This settings defines how IMQ behaves in respect to its
-+ hooking in PREROUTING and POSTROUTING.
-+
-+ IMQ can work in any of the following ways:
++ IMQ can work in any of the following ways:
+
-+ PREROUTING | POSTROUTING
-+ -----------------|-------------------
-+ #1 After NAT | After NAT
-+ #2 After NAT | Before NAT
-+ #3 Before NAT | After NAT
-+ #4 Before NAT | Before NAT
++ PREROUTING | POSTROUTING
++ -----------------|-------------------
++ #1 After NAT | After NAT
++ #2 After NAT | Before NAT
++ #3 Before NAT | After NAT
++ #4 Before NAT | Before NAT
+
-+ The default behavior is to hook before NAT on PREROUTING
-+ and after NAT on POSTROUTING (#3).
++ The default behavior is to hook before NAT on PREROUTING
++ and after NAT on POSTROUTING (#3).
+
-+ This settings are specially usefull when trying to use IMQ
-+ to shape NATed clients.
++ This settings are specially usefull when trying to use IMQ
++ to shape NATed clients.
+
-+ More information can be found at: www.linuximq.net
++ More information can be found at: www.linuximq.net
+
-+ If not sure leave the default settings alone.
++ If not sure leave the default settings alone.
+
+config IMQ_BEHAVIOR_AA
+ bool "IMQ AA"
+ help
-+ This settings defines how IMQ behaves in respect to its
-+ hooking in PREROUTING and POSTROUTING.
++ This setting defines how IMQ behaves in respect to its
++ hooking in PREROUTING and POSTROUTING.
+
-+ Choosing this option will make IMQ hook like this:
++ Choosing this option will make IMQ hook like this:
+
-+ PREROUTING: After NAT
-+ POSTROUTING: After NAT
++ PREROUTING: After NAT
++ POSTROUTING: After NAT
+
-+ More information can be found at: www.linuximq.net
++ More information can be found at: www.linuximq.net
+
-+ If not sure leave the default settings alone.
++ If not sure leave the default settings alone.
+
+config IMQ_BEHAVIOR_AB
+ bool "IMQ AB"
+ help
-+ This settings defines how IMQ behaves in respect to its
-+ hooking in PREROUTING and POSTROUTING.
++ This setting defines how IMQ behaves in respect to its
++ hooking in PREROUTING and POSTROUTING.
+
-+ Choosing this option will make IMQ hook like this:
++ Choosing this option will make IMQ hook like this:
+
-+ PREROUTING: After NAT
-+ POSTROUTING: Before NAT
++ PREROUTING: After NAT
++ POSTROUTING: Before NAT
+
-+ More information can be found at: www.linuximq.net
++ More information can be found at: www.linuximq.net
+
-+ If not sure leave the default settings alone.
++ If not sure leave the default settings alone.
+
+config IMQ_BEHAVIOR_BA
+ bool "IMQ BA"
+ help
-+ This settings defines how IMQ behaves in respect to its
-+ hooking in PREROUTING and POSTROUTING.
++ This setting defines how IMQ behaves in respect to its
++ hooking in PREROUTING and POSTROUTING.
+
-+ Choosing this option will make IMQ hook like this:
++ Choosing this option will make IMQ hook like this:
+
-+ PREROUTING: Before NAT
-+ POSTROUTING: After NAT
++ PREROUTING: Before NAT
++ POSTROUTING: After NAT
+
-+ More information can be found at: www.linuximq.net
++ More information can be found at: www.linuximq.net
+
-+ If not sure leave the default settings alone.
++ If not sure leave the default settings alone.
+
+config IMQ_BEHAVIOR_BB
+ bool "IMQ BB"
+ help
-+ This settings defines how IMQ behaves in respect to its
-+ hooking in PREROUTING and POSTROUTING.
++ This setting defines how IMQ behaves in respect to its
++ hooking in PREROUTING and POSTROUTING.
+
-+ Choosing this option will make IMQ hook like this:
++ Choosing this option will make IMQ hook like this:
+
-+ PREROUTING: Before NAT
-+ POSTROUTING: Before NAT
++ PREROUTING: Before NAT
++ POSTROUTING: Before NAT
+
-+ More information can be found at: www.linuximq.net
++ More information can be found at: www.linuximq.net
+
-+ If not sure leave the default settings alone.
++ If not sure leave the default settings alone.
+
+endchoice
+
+config IMQ_NUM_DEVS
-+
+ int "Number of IMQ devices"
+ range 2 16
+ depends on IMQ
+ default "16"
+ help
++ This setting defines how many IMQ devices will be created.
+
-+ This settings defines how many IMQ devices will be
-+ created.
++ The default value is 16.
+
-+ The default value is 16.
++ More information can be found at: www.linuximq.net
+
-+ More information can be found at: www.linuximq.net
-+
-+ If not sure leave the default settings alone.
++ If not sure leave the default settings alone.
+
config TUN
tristate "Universal TUN/TAP device driver support"
select CRC32
-diff -uNr linux-2.6.39/drivers/net/Makefile linux-2.6.39-imqmq/drivers/net/Makefile
---- linux-2.6.39/drivers/net/Makefile 2011-05-19 07:06:34.000000000 +0300
-+++ linux-2.6.39-imqmq/drivers/net/Makefile 2011-05-19 11:08:04.281864473 +0300
-@@ -175,6 +175,7 @@
+diff -uNr linux-3.0/drivers/net/Makefile linux-3.0-imq/drivers/net/Makefile
+--- linux-3.0/drivers/net/Makefile 2011-07-22 05:17:23.000000000 +0300
++++ linux-3.0-imq/drivers/net/Makefile 2011-07-24 12:06:25.922003276 +0300
+@@ -176,6 +176,7 @@
obj-$(CONFIG_XEN_NETDEV_BACKEND) += xen-netback/
obj-$(CONFIG_DUMMY) += dummy.o
obj-$(CONFIG_IFB) += ifb.o
obj-$(CONFIG_MACVLAN) += macvlan.o
obj-$(CONFIG_MACVTAP) += macvtap.o
-diff -uNr linux-2.6.39/include/linux/imq.h linux-2.6.39-imqmq/include/linux/imq.h
---- linux-2.6.39/include/linux/imq.h 1970-01-01 02:00:00.000000000 +0200
-+++ linux-2.6.39-imqmq/include/linux/imq.h 2011-05-19 11:08:04.281864473 +0300
+diff -uNr linux-3.0/include/linux/imq.h linux-3.0-imq/include/linux/imq.h
+--- linux-3.0/include/linux/imq.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-3.0-imq/include/linux/imq.h 2011-07-24 12:06:25.932003270 +0300
@@ -0,0 +1,13 @@
+#ifndef _IMQ_H
+#define _IMQ_H
+
+#endif /* _IMQ_H */
+
-diff -uNr linux-2.6.39/include/linux/netfilter/xt_IMQ.h linux-2.6.39-imqmq/include/linux/netfilter/xt_IMQ.h
---- linux-2.6.39/include/linux/netfilter/xt_IMQ.h 1970-01-01 02:00:00.000000000 +0200
-+++ linux-2.6.39-imqmq/include/linux/netfilter/xt_IMQ.h 2011-05-19 11:08:04.281864473 +0300
+diff -uNr linux-3.0/include/linux/netfilter/xt_IMQ.h linux-3.0-imq/include/linux/netfilter/xt_IMQ.h
+--- linux-3.0/include/linux/netfilter/xt_IMQ.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-3.0-imq/include/linux/netfilter/xt_IMQ.h 2011-07-24 12:06:25.932003270 +0300
@@ -0,0 +1,9 @@
+#ifndef _XT_IMQ_H
+#define _XT_IMQ_H
+
+#endif /* _XT_IMQ_H */
+
-diff -uNr linux-2.6.39/include/linux/netfilter.h linux-2.6.39-imqmq/include/linux/netfilter.h
---- linux-2.6.39/include/linux/netfilter.h 2011-05-19 07:06:34.000000000 +0300
-+++ linux-2.6.39-imqmq/include/linux/netfilter.h 2011-05-19 11:08:04.285197874 +0300
-@@ -21,7 +21,8 @@
+diff -uNr linux-3.0/include/linux/netfilter.h linux-3.0-imq/include/linux/netfilter.h
+--- linux-3.0/include/linux/netfilter.h 2011-07-22 05:17:23.000000000 +0300
++++ linux-3.0-imq/include/linux/netfilter.h 2011-07-24 12:06:25.955336605 +0300
+@@ -22,7 +22,8 @@
#define NF_QUEUE 3
#define NF_REPEAT 4
#define NF_STOP 5
/* we overload the higher bits for encoding auxiliary data such as the queue
* number or errno values. Not nice, but better than additional function
-diff -uNr linux-2.6.39/include/linux/netfilter_ipv4/ipt_IMQ.h linux-2.6.39-imqmq/include/linux/netfilter_ipv4/ipt_IMQ.h
---- linux-2.6.39/include/linux/netfilter_ipv4/ipt_IMQ.h 1970-01-01 02:00:00.000000000 +0200
-+++ linux-2.6.39-imqmq/include/linux/netfilter_ipv4/ipt_IMQ.h 2011-05-19 11:08:04.285197874 +0300
+diff -uNr linux-3.0/include/linux/netfilter_ipv4/ipt_IMQ.h linux-3.0-imq/include/linux/netfilter_ipv4/ipt_IMQ.h
+--- linux-3.0/include/linux/netfilter_ipv4/ipt_IMQ.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-3.0-imq/include/linux/netfilter_ipv4/ipt_IMQ.h 2011-07-24 12:06:25.955336605 +0300
@@ -0,0 +1,10 @@
+#ifndef _IPT_IMQ_H
+#define _IPT_IMQ_H
+
+#endif /* _IPT_IMQ_H */
+
-diff -uNr linux-2.6.39/include/linux/netfilter_ipv6/ip6t_IMQ.h linux-2.6.39-imqmq/include/linux/netfilter_ipv6/ip6t_IMQ.h
---- linux-2.6.39/include/linux/netfilter_ipv6/ip6t_IMQ.h 1970-01-01 02:00:00.000000000 +0200
-+++ linux-2.6.39-imqmq/include/linux/netfilter_ipv6/ip6t_IMQ.h 2011-05-19 11:08:04.285197874 +0300
+diff -uNr linux-3.0/include/linux/netfilter_ipv6/ip6t_IMQ.h linux-3.0-imq/include/linux/netfilter_ipv6/ip6t_IMQ.h
+--- linux-3.0/include/linux/netfilter_ipv6/ip6t_IMQ.h 1970-01-01 02:00:00.000000000 +0200
++++ linux-3.0-imq/include/linux/netfilter_ipv6/ip6t_IMQ.h 2011-07-24 12:06:25.955336605 +0300
@@ -0,0 +1,10 @@
+#ifndef _IP6T_IMQ_H
+#define _IP6T_IMQ_H
+
+#endif /* _IP6T_IMQ_H */
+
-diff -uNr linux-2.6.39/include/linux/skbuff.h linux-2.6.39-imqmq/include/linux/skbuff.h
---- linux-2.6.39/include/linux/skbuff.h 2011-05-19 07:06:34.000000000 +0300
-+++ linux-2.6.39-imqmq/include/linux/skbuff.h 2011-05-19 11:08:04.288531274 +0300
+diff -uNr linux-3.0/include/linux/skbuff.h linux-3.0-imq/include/linux/skbuff.h
+--- linux-3.0/include/linux/skbuff.h 2011-07-22 05:17:23.000000000 +0300
++++ linux-3.0-imq/include/linux/skbuff.h 2011-07-24 12:06:25.968669945 +0300
@@ -29,6 +29,9 @@
#include <linux/rcupdate.h>
#include <linux/dmaengine.h>
extern void kfree_skb(struct sk_buff *skb);
extern void consume_skb(struct sk_buff *skb);
extern void __kfree_skb(struct sk_buff *skb);
-@@ -2129,6 +2148,10 @@
+@@ -2134,6 +2153,10 @@
dst->nfct_reasm = src->nfct_reasm;
nf_conntrack_get_reasm(src->nfct_reasm);
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
dst->nf_bridge = src->nf_bridge;
nf_bridge_get(src->nf_bridge);
-diff -uNr linux-2.6.39/include/net/netfilter/nf_queue.h linux-2.6.39-imqmq/include/net/netfilter/nf_queue.h
---- linux-2.6.39/include/net/netfilter/nf_queue.h 2011-05-19 07:06:34.000000000 +0300
-+++ linux-2.6.39-imqmq/include/net/netfilter/nf_queue.h 2011-05-19 11:08:04.288531274 +0300
+diff -uNr linux-3.0/include/net/netfilter/nf_queue.h linux-3.0-imq/include/net/netfilter/nf_queue.h
+--- linux-3.0/include/net/netfilter/nf_queue.h 2011-07-22 05:17:23.000000000 +0300
++++ linux-3.0-imq/include/net/netfilter/nf_queue.h 2011-07-24 12:06:25.975336612 +0300
@@ -30,5 +30,11 @@
const struct nf_queue_handler *qh);
extern void nf_unregister_queue_handlers(const struct nf_queue_handler *qh);
+#endif
#endif /* _NF_QUEUE_H */
-diff -uNr linux-2.6.39/net/core/dev.c linux-2.6.39-imqmq/net/core/dev.c
---- linux-2.6.39/net/core/dev.c 2011-05-19 07:06:34.000000000 +0300
-+++ linux-2.6.39-imqmq/net/core/dev.c 2011-05-19 11:08:04.288531274 +0300
+diff -uNr linux-3.0/net/core/dev.c linux-3.0-imq/net/core/dev.c
+--- linux-3.0/net/core/dev.c 2011-07-22 05:17:23.000000000 +0300
++++ linux-3.0-imq/net/core/dev.c 2011-07-26 07:52:00.513207402 +0300
@@ -98,6 +98,9 @@
#include <net/net_namespace.h>
#include <net/sock.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
-@@ -2099,12 +2102,21 @@
+@@ -2108,7 +2111,12 @@
if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
skb_dst_drop(skb);
dev_queue_xmit_nit(skb, dev);
skb_orphan_try(skb);
-
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+ features = skb->dev ? netif_skb_features(skb) : dev->features;
-+#else
- features = netif_skb_features(skb);
-+#endif
-
- if (vlan_tx_tag_present(skb) &&
- !(features & NETIF_F_HW_VLAN_TX)) {
-@@ -2269,8 +2281,7 @@
- #endif
- }
-
--static struct netdev_queue *dev_pick_tx(struct net_device *dev,
-- struct sk_buff *skb)
-+static struct netdev_queue *dev_pick_tx(struct net_device *dev, struct sk_buff *skb)
- {
- int queue_index;
- const struct net_device_ops *ops = dev->netdev_ops;
-diff -uNr linux-2.6.39/net/core/skbuff.c linux-2.6.39-imqmq/net/core/skbuff.c
---- linux-2.6.39/net/core/skbuff.c 2011-05-19 07:06:34.000000000 +0300
-+++ linux-2.6.39-imqmq/net/core/skbuff.c 2011-05-19 11:08:04.288531274 +0300
-@@ -72,6 +72,9 @@
+diff -uNr linux-3.0/net/core/skbuff.c linux-3.0-imq/net/core/skbuff.c
+--- linux-3.0/net/core/skbuff.c 2011-07-22 05:17:23.000000000 +0300
++++ linux-3.0-imq/net/core/skbuff.c 2011-07-24 12:06:26.008669943 +0300
+@@ -73,6 +73,9 @@
static struct kmem_cache *skbuff_head_cache __read_mostly;
static struct kmem_cache *skbuff_fclone_cache __read_mostly;
static void sock_pipe_buf_release(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
-@@ -91,6 +94,82 @@
+@@ -92,6 +95,82 @@
return 1;
}
/* Pipe buffer operations for a socket. */
static const struct pipe_buf_operations sock_pipe_buf_ops = {
-@@ -379,6 +458,26 @@
+@@ -380,6 +459,26 @@
WARN_ON(in_irq());
skb->destructor(skb);
}
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
nf_conntrack_put(skb->nfct);
#endif
-@@ -517,6 +616,9 @@
+@@ -518,6 +617,9 @@
new->sp = secpath_get(old->sp);
#endif
memcpy(new->cb, old->cb, sizeof(old->cb));
new->csum = old->csum;
new->local_df = old->local_df;
new->pkt_type = old->pkt_type;
-@@ -2780,6 +2882,13 @@
+@@ -2781,6 +2883,13 @@
0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC,
NULL);
}
/**
-diff -uNr linux-2.6.39/net/netfilter/core.c linux-2.6.39-imqmq/net/netfilter/core.c
---- linux-2.6.39/net/netfilter/core.c 2011-05-19 07:06:34.000000000 +0300
-+++ linux-2.6.39-imqmq/net/netfilter/core.c 2011-05-19 11:13:19.891558119 +0300
-@@ -191,6 +191,20 @@
- kfree_skb(skb);
- }
- ret = 0;
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+ } else if ((verdict & NF_VERDICT_MASK) == NF_IMQ_QUEUE) {
-+ ret = nf_imq_queue(skb, elem, pf, hook, indev, outdev, okfn,
-+ verdict >> NF_VERDICT_QBITS);
-+ if (ret < 0) {
-+ if (ret == -ECANCELED)
-+ goto next_hook;
-+ if (ret == -ESRCH &&
-+ (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS))
-+ goto next_hook;
-+ kfree_skb(skb);
-+ }
-+ ret = 0;
-+#endif
+diff -uNr linux-3.0/net/ipv6/ip6_output.c linux-3.0-imq/net/ipv6/ip6_output.c
+--- linux-3.0/net/ipv6/ip6_output.c 2011-07-22 05:17:23.000000000 +0300
++++ linux-3.0-imq/net/ipv6/ip6_output.c 2011-07-24 16:46:04.789482257 +0300
+@@ -101,9 +101,6 @@
+ struct dst_entry *dst = skb_dst(skb);
+ struct net_device *dev = dst->dev;
+
+- skb->protocol = htons(ETH_P_IPV6);
+- skb->dev = dev;
+-
+ if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
+ struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
+
+@@ -165,6 +162,11 @@
+ return 0;
}
- rcu_read_unlock();
- return ret;
-diff -uNr linux-2.6.39/net/netfilter/Kconfig linux-2.6.39-imqmq/net/netfilter/Kconfig
---- linux-2.6.39/net/netfilter/Kconfig 2011-05-19 07:06:34.000000000 +0300
-+++ linux-2.6.39-imqmq/net/netfilter/Kconfig 2011-05-19 11:08:04.288531274 +0300
+
++ /* IMQ-patch: moved setting skb->dev and skb->protocol from
++ * ip6_finish_output2 to fix crashing at netif_skb_features(). */
++ skb->protocol = htons(ETH_P_IPV6);
++ skb->dev = dev;
++
+ return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, dev,
+ ip6_finish_output,
+ !(IP6CB(skb)->flags & IP6SKB_REROUTED));
+diff -uNr linux-3.0/net/netfilter/core.c linux-3.0-imq/net/netfilter/core.c
+--- linux-3.0/net/netfilter/core.c 2011-07-22 05:17:23.000000000 +0300
++++ linux-3.0-imq/net/netfilter/core.c 2011-07-24 12:53:52.972141108 +0300
+@@ -179,9 +179,11 @@
+ ret = NF_DROP_GETERR(verdict);
+ if (ret == 0)
+ ret = -EPERM;
+- } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
++ } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE ||
++ (verdict & NF_VERDICT_MASK) == NF_IMQ_QUEUE) {
+ ret = nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
+- verdict >> NF_VERDICT_QBITS);
++ verdict >> NF_VERDICT_QBITS,
++ verdict & NF_VERDICT_MASK);
+ if (ret < 0) {
+ if (ret == -ECANCELED)
+ goto next_hook;
+diff -uNr linux-3.0/net/netfilter/Kconfig linux-3.0-imq/net/netfilter/Kconfig
+--- linux-3.0/net/netfilter/Kconfig 2011-07-22 05:17:23.000000000 +0300
++++ linux-3.0-imq/net/netfilter/Kconfig 2011-07-24 12:06:26.035336611 +0300
@@ -507,6 +507,18 @@
For more information on the LEDs available on your system, see
Documentation/leds-class.txt
config NETFILTER_XT_TARGET_MARK
tristate '"MARK" target support'
depends on NETFILTER_ADVANCED
-diff -uNr linux-2.6.39/net/netfilter/Makefile linux-2.6.39-imqmq/net/netfilter/Makefile
---- linux-2.6.39/net/netfilter/Makefile 2011-05-19 07:06:34.000000000 +0300
-+++ linux-2.6.39-imqmq/net/netfilter/Makefile 2011-05-19 11:08:04.291864674 +0300
+diff -uNr linux-3.0/net/netfilter/Makefile linux-3.0-imq/net/netfilter/Makefile
+--- linux-3.0/net/netfilter/Makefile 2011-07-22 05:17:23.000000000 +0300
++++ linux-3.0-imq/net/netfilter/Makefile 2011-07-24 12:06:26.042003277 +0300
@@ -56,6 +56,7 @@
obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o
obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
-diff -uNr linux-2.6.39/net/netfilter/nf_internals.h linux-2.6.39-imqmq/net/netfilter/nf_internals.h
---- linux-2.6.39/net/netfilter/nf_internals.h 2011-05-19 07:06:34.000000000 +0300
-+++ linux-2.6.39-imqmq/net/netfilter/nf_internals.h 2011-05-19 11:08:04.291864674 +0300
-@@ -30,6 +30,15 @@
+diff -uNr linux-3.0/net/netfilter/nf_internals.h linux-3.0-imq/net/netfilter/nf_internals.h
+--- linux-3.0/net/netfilter/nf_internals.h 2011-07-22 05:17:23.000000000 +0300
++++ linux-3.0-imq/net/netfilter/nf_internals.h 2011-07-24 12:54:17.615475634 +0300
+@@ -29,7 +29,7 @@
+ struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *),
- unsigned int queuenum);
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+extern int nf_imq_queue(struct sk_buff *skb,
-+ struct list_head *elem,
-+ u_int8_t pf, unsigned int hook,
-+ struct net_device *indev,
-+ struct net_device *outdev,
-+ int (*okfn)(struct sk_buff *),
-+ unsigned int queuenum);
-+#endif
+- unsigned int queuenum);
++ unsigned int queuenum, unsigned int queuetype);
extern int __init netfilter_queue_init(void);
/* nf_log.c */
-diff -uNr linux-2.6.39/net/netfilter/nf_queue.c linux-2.6.39-imqmq/net/netfilter/nf_queue.c
---- linux-2.6.39/net/netfilter/nf_queue.c 2011-05-19 07:06:34.000000000 +0300
-+++ linux-2.6.39-imqmq/net/netfilter/nf_queue.c 2011-05-19 11:22:38.189467462 +0300
+diff -uNr linux-3.0/net/netfilter/nf_queue.c linux-3.0-imq/net/netfilter/nf_queue.c
+--- linux-3.0/net/netfilter/nf_queue.c 2011-07-22 05:17:23.000000000 +0300
++++ linux-3.0-imq/net/netfilter/nf_queue.c 2011-07-24 13:05:00.682173434 +0300
@@ -22,6 +22,26 @@
static DEFINE_MUTEX(queue_handler_mutex);
int (*okfn)(struct sk_buff *),
- unsigned int queuenum)
+ unsigned int queuenum,
-+ bool imq_queue)
++ unsigned int queuetype)
{
int status = -ENOENT;
struct nf_queue_entry *entry = NULL;
-@@ -137,7 +159,14 @@
+@@ -137,7 +159,17 @@
/* QUEUE == DROP if no one is waiting, to be safe. */
rcu_read_lock();
- qh = rcu_dereference(queue_handler[pf]);
++ if (queuetype == NF_IMQ_QUEUE) {
+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+ if (imq_queue)
+ qh = rcu_dereference(queue_imq_handler);
-+ else
-+ qh = rcu_dereference(queue_handler[pf]);
+#else
-+ qh = rcu_dereference(queue_handler[pf]);
++ BUG();
++ goto err_unlock;
+#endif
++ } else {
++ qh = rcu_dereference(queue_handler[pf]);
++ }
++
if (!qh) {
status = -ESRCH;
goto err_unlock;
-@@ -203,13 +232,14 @@
- return status;
- }
-
--int nf_queue(struct sk_buff *skb,
-- struct list_head *elem,
-- u_int8_t pf, unsigned int hook,
-- struct net_device *indev,
-- struct net_device *outdev,
-- int (*okfn)(struct sk_buff *),
+@@ -209,7 +241,8 @@
+ struct net_device *indev,
+ struct net_device *outdev,
+ int (*okfn)(struct sk_buff *),
- unsigned int queuenum)
-+static int _nf_queue(struct sk_buff *skb,
-+ struct list_head *elem,
-+ u_int8_t pf, unsigned int hook,
-+ struct net_device *indev,
-+ struct net_device *outdev,
-+ int (*okfn)(struct sk_buff *),
-+ unsigned int queuenum,
-+ bool imq_queue)
++ unsigned int queuenum,
++ unsigned int queuetype)
{
struct sk_buff *segs;
int err;
-@@ -217,7 +247,7 @@
+@@ -217,7 +250,7 @@
if (!skb_is_gso(skb))
return __nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
- queuenum);
-+ queuenum, imq_queue);
++ queuenum, queuetype);
switch (pf) {
case NFPROTO_IPV4:
-@@ -244,7 +274,7 @@
+@@ -244,7 +277,7 @@
segs->next = NULL;
if (err == 0)
err = __nf_queue(segs, elem, pf, hook, indev,
- outdev, okfn, queuenum);
-+ outdev, okfn, queuenum, imq_queue);
++ outdev, okfn, queuenum, queuetype);
if (err == 0)
queued++;
else
-@@ -260,6 +290,32 @@
- return err;
- }
-
-+int nf_queue(struct sk_buff *skb,
-+ struct list_head *elem,
-+ u_int8_t pf, unsigned int hook,
-+ struct net_device *indev,
-+ struct net_device *outdev,
-+ int (*okfn)(struct sk_buff *),
-+ unsigned int queuenum)
-+{
-+ return _nf_queue(skb, elem, pf, hook, indev, outdev, okfn, queuenum,
-+ false);
-+}
-+
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+int nf_imq_queue(struct sk_buff *skb,
-+ struct list_head *elem,
-+ u_int8_t pf, unsigned int hook,
-+ struct net_device *indev,
-+ struct net_device *outdev,
-+ int (*okfn)(struct sk_buff *),
-+ unsigned int queuenum)
-+{
-+ return _nf_queue(skb, elem, pf, hook, indev, outdev, okfn, queuenum,
-+ true);
-+}
-+#endif
-+
- void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
- {
- struct sk_buff *skb = entry->skb;
-@@ -301,7 +357,7 @@
+@@ -299,9 +332,11 @@
+ local_bh_enable();
+ break;
case NF_QUEUE:
++ case NF_IMQ_QUEUE:
err = __nf_queue(skb, elem, entry->pf, entry->hook,
entry->indev, entry->outdev, entry->okfn,
- verdict >> NF_VERDICT_QBITS);
-+ verdict >> NF_VERDICT_QBITS, false);
++ verdict >> NF_VERDICT_QBITS,
++ verdict & NF_VERDICT_MASK);
if (err < 0) {
if (err == -ECANCELED)
goto next_hook;
-@@ -311,6 +367,21 @@
- kfree_skb(skb);
- }
- break;
-+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
-+ case NF_IMQ_QUEUE:
-+ err = __nf_queue(skb, elem, entry->pf, entry->hook,
-+ entry->indev, entry->outdev, entry->okfn,
-+ verdict >> NF_VERDICT_QBITS, true);
-+ if (err < 0) {
-+ if (err == -ECANCELED)
-+ goto next_hook;
-+ if (err == -ESRCH &&
-+ (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS))
-+ goto next_hook;
-+ kfree_skb(skb);
-+ }
-+ break;
-+#endif
- case NF_STOLEN:
- default:
- kfree_skb(skb);
-diff -uNr linux-2.6.39/net/netfilter/xt_IMQ.c linux-2.6.39-imqmq/net/netfilter/xt_IMQ.c
---- linux-2.6.39/net/netfilter/xt_IMQ.c 1970-01-01 02:00:00.000000000 +0200
-+++ linux-2.6.39-imqmq/net/netfilter/xt_IMQ.c 2011-05-19 11:08:04.308531677 +0300
+diff -uNr linux-3.0/net/netfilter/xt_IMQ.c linux-3.0-imq/net/netfilter/xt_IMQ.c
+--- linux-3.0/net/netfilter/xt_IMQ.c 1970-01-01 02:00:00.000000000 +0200
++++ linux-3.0-imq/net/netfilter/xt_IMQ.c 2011-07-24 12:06:26.062003279 +0300
@@ -0,0 +1,74 @@
+/*
+ * This target marks packets to be enqueued to an imq device