int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb);
 int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type);
 int xfrm_input_resume(struct sk_buff *skb, int nexthdr);
+int xfrm_trans_queue(struct sk_buff *skb,
+                    int (*finish)(struct net *, struct sock *,
+                                  struct sk_buff *));
 int xfrm_output_resume(struct sk_buff *skb, int err);
 int xfrm_output(struct sock *sk, struct sk_buff *skb);
 int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb);
 
 }
 EXPORT_SYMBOL(xfrm6_rcv_spi);
 
+static int xfrm6_transport_finish2(struct net *net, struct sock *sk,
+                                  struct sk_buff *skb)
+{
+       if (xfrm_trans_queue(skb, ip6_rcv_finish))
+               __kfree_skb(skb);
+       return -1;
+}
+
 int xfrm6_transport_finish(struct sk_buff *skb, int async)
 {
        struct xfrm_offload *xo = xfrm_offload(skb);
 
        NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING,
                dev_net(skb->dev), NULL, skb, skb->dev, NULL,
-               ip6_rcv_finish);
+               xfrm6_transport_finish2);
        return -1;
 }
 
 
  *
  */
 
+#include <linux/bottom_half.h>
+#include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
+#include <linux/percpu.h>
 #include <net/dst.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 #include <net/ip_tunnels.h>
 #include <net/ip6_tunnel.h>
 
+struct xfrm_trans_tasklet {
+       struct tasklet_struct tasklet;
+       struct sk_buff_head queue;
+};
+
+struct xfrm_trans_cb {
+       int (*finish)(struct net *net, struct sock *sk, struct sk_buff *skb);
+};
+
+#define XFRM_TRANS_SKB_CB(__skb) ((struct xfrm_trans_cb *)&((__skb)->cb[0]))
+
 static struct kmem_cache *secpath_cachep __read_mostly;
 
 static DEFINE_SPINLOCK(xfrm_input_afinfo_lock);
 static struct gro_cells gro_cells;
 static struct net_device xfrm_napi_dev;
 
+static DEFINE_PER_CPU(struct xfrm_trans_tasklet, xfrm_trans_tasklet);
+
 int xfrm_input_register_afinfo(const struct xfrm_input_afinfo *afinfo)
 {
        int err = 0;
 }
 EXPORT_SYMBOL(xfrm_input_resume);
 
+static void xfrm_trans_reinject(unsigned long data)
+{
+       struct xfrm_trans_tasklet *trans = (void *)data;
+       struct sk_buff_head queue;
+       struct sk_buff *skb;
+
+       __skb_queue_head_init(&queue);
+       skb_queue_splice_init(&trans->queue, &queue);
+
+       while ((skb = __skb_dequeue(&queue)))
+               XFRM_TRANS_SKB_CB(skb)->finish(dev_net(skb->dev), NULL, skb);
+}
+
+int xfrm_trans_queue(struct sk_buff *skb,
+                    int (*finish)(struct net *, struct sock *,
+                                  struct sk_buff *))
+{
+       struct xfrm_trans_tasklet *trans;
+
+       trans = this_cpu_ptr(&xfrm_trans_tasklet);
+
+       if (skb_queue_len(&trans->queue) >= netdev_max_backlog)
+               return -ENOBUFS;
+
+       XFRM_TRANS_SKB_CB(skb)->finish = finish;
+       skb_queue_tail(&trans->queue, skb);
+       tasklet_schedule(&trans->tasklet);
+       return 0;
+}
+EXPORT_SYMBOL(xfrm_trans_queue);
+
 void __init xfrm_input_init(void)
 {
        int err;
+       int i;
 
        init_dummy_netdev(&xfrm_napi_dev);
        err = gro_cells_init(&gro_cells, &xfrm_napi_dev);
                                           sizeof(struct sec_path),
                                           0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
                                           NULL);
+
+       for_each_possible_cpu(i) {
+               struct xfrm_trans_tasklet *trans;
+
+               trans = &per_cpu(xfrm_trans_tasklet, i);
+               __skb_queue_head_init(&trans->queue);
+               tasklet_init(&trans->tasklet, xfrm_trans_reinject,
+                            (unsigned long)trans);
+       }
 }