--- a/drivers/net/ppp_generic.c	2008-12-25 02:26:37.000000000 +0300
+++ b/drivers/net/ppp_generic.c	2009-03-01 14:54:45.000000000 +0300
@@ -45,6 +45,7 @@
 #include <linux/stddef.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
+#include <linux/workqueue.h>
 #include <net/slhc_vj.h>
 #include <asm/atomic.h>
 
@@ -117,6 +118,7 @@
 	unsigned long	last_recv;	/* jiffies when last pkt rcvd a0 */
 	struct net_device *dev;		/* network interface device a4 */
 	int		closing;	/* is device closing down? a8 */
+	struct work_struct xmit_work;
 #ifdef CONFIG_PPP_MULTILINK
 	int		nxchan;		/* next channel to send something on */
 	u32		nxseq;		/* next sequence number to send */
@@ -156,6 +158,10 @@
 	struct ppp	*ppp;		/* ppp unit we're connected to */
 	struct list_head clist;		/* link in list of channels per unit */
 	rwlock_t	upl;		/* protects `ppp' */
+
+	struct work_struct recv_work;
+	struct sk_buff_head rq;		/* receive queue for pppd */
+
 #ifdef CONFIG_PPP_MULTILINK
 	u8		avail;		/* flag used in multilink stuff */
 	u8		had_frag;	/* >= 1 fragments have been sent */
@@ -272,6 +278,7 @@
 static void ppp_destroy_channel(struct channel *pch);
 
 static struct class *ppp_class;
+static struct workqueue_struct *kpppd_workqueue;
 
 /* Translates a PPP protocol number to a NP index (NP == network protocol) */
 static inline int proto_to_npindex(int proto)
@@ -860,6 +867,13 @@
 	int err;
 
 	printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n");
+	
+	kpppd_workqueue = create_workqueue("kpppd");
+	if (!kpppd_workqueue){
+	    printk(KERN_ERR "failed to create workqueue\n");
+	    return -1;
+	}
+	    
 	err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops);
 	if (!err) {
 		ppp_class = class_create(THIS_MODULE, "ppp");
@@ -870,10 +884,12 @@
 		device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL,
 			      "ppp");
 	}
-
+	
 out:
-	if (err)
+	if (err) {
+		destroy_workqueue(kpppd_workqueue);
 		printk(KERN_ERR "failed to register PPP device (%d)\n", err);
+	}
 	return err;
 
 out_chrdev:
@@ -881,6 +897,12 @@
 	goto out;
 }
 
+static void ppp_xmit_work(struct work_struct *work)
+{
+    struct ppp *ppp=container_of(work,typeof(*ppp),xmit_work);
+    ppp_xmit_process(ppp);
+}
+
 /*
  * Network interface unit routines.
  */
@@ -920,7 +942,7 @@
 
 	netif_stop_queue(dev);
 	skb_queue_tail(&ppp->file.xq, skb);
-	ppp_xmit_process(ppp);
+	queue_work(kpppd_workqueue,&ppp->xmit_work);
 	return 0;
 
  outf:
@@ -1464,13 +1486,29 @@
 ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
 {
 	ppp_recv_lock(ppp);
-	if (!ppp->closing)
-		ppp_receive_frame(ppp, skb, pch);
-	else
+	if (!ppp->closing){
+		skb_queue_tail(&pch->rq, skb);
+		queue_work(kpppd_workqueue,&pch->recv_work);
+	}else
 		kfree_skb(skb);
 	ppp_recv_unlock(ppp);
 }
 
+static void ppp_recv_work(struct work_struct *work)
+{
+		struct channel *pch=container_of(work,typeof(*pch),recv_work);
+		struct sk_buff *skb;
+		
+		ppp_recv_lock(pch->ppp);
+		
+		while((skb=skb_dequeue(&pch->rq))){
+			if (pch->ppp->dev)
+			ppp_receive_frame(pch->ppp, skb, pch);
+		}
+
+		ppp_recv_unlock(pch->ppp);
+}
+
 void
 ppp_input(struct ppp_channel *chan, struct sk_buff *skb)
 {
@@ -2014,6 +2052,8 @@
 	chan->ppp = pch;
 	init_ppp_file(&pch->file, CHANNEL);
 	pch->file.hdrlen = chan->hdrlen;
+	INIT_WORK(&pch->recv_work,ppp_recv_work);
+	skb_queue_head_init(&pch->rq);
 #ifdef CONFIG_PPP_MULTILINK
 	pch->lastseq = -1;
 #endif /* CONFIG_PPP_MULTILINK */
@@ -2429,6 +2469,7 @@
 	INIT_LIST_HEAD(&ppp->channels);
 	spin_lock_init(&ppp->rlock);
 	spin_lock_init(&ppp->wlock);
+	INIT_WORK(&ppp->xmit_work,ppp_xmit_work);
 #ifdef CONFIG_PPP_MULTILINK
 	ppp->minseq = -1;
 	skb_queue_head_init(&ppp->mrq);
@@ -2537,6 +2578,7 @@
 		slhc_free(ppp->vj);
 		ppp->vj = NULL;
 	}
+	cancel_work_sync(&ppp->xmit_work);
 	skb_queue_purge(&ppp->file.xq);
 	skb_queue_purge(&ppp->file.rq);
 #ifdef CONFIG_PPP_MULTILINK
@@ -2672,6 +2714,8 @@
 	}
 	skb_queue_purge(&pch->file.xq);
 	skb_queue_purge(&pch->file.rq);
+	cancel_work_sync(&pch->recv_work);
+	skb_queue_purge(&pch->rq);
 	kfree(pch);
 }
 
@@ -2684,6 +2728,7 @@
 	unregister_chrdev(PPP_MAJOR, "ppp");
 	device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
 	class_destroy(ppp_class);
+	destroy_workqueue(kpppd_workqueue);
 }
 
 /*
