mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-03 22:44:27 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			90 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			90 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From: Simon Farnsworth <simon@farnz.org.uk>
 | 
						|
Date: Sun, 1 Mar 2015 10:54:39 +0000
 | 
						|
Subject: [PATCH] pppoe: Use workqueue to die properly when a PADT is received
 | 
						|
 | 
						|
When a PADT frame is received, the socket may not be in a good state to
 | 
						|
close down the PPP interface. The current implementation handles this by
 | 
						|
simply blocking all further PPP traffic, and hoping that the lack of traffic
 | 
						|
will trigger the user to investigate.
 | 
						|
 | 
						|
Use schedule_work to get to a process context from which we clear down the
 | 
						|
PPP interface, in a fashion analogous to hangup on a TTY-based PPP
 | 
						|
interface. This causes pppd to disconnect immediately, and allows tools to
 | 
						|
take immediate corrective action.
 | 
						|
 | 
						|
Note that pppd's rp_pppoe.so plugin has code in it to disable the session
 | 
						|
when it disconnects; however, as a consequence of this patch, the session is
 | 
						|
already disabled before rp_pppoe.so is asked to disable the session. The
 | 
						|
result is a harmless error message:
 | 
						|
 | 
						|
Failed to disconnect PPPoE socket: 114 Operation already in progress
 | 
						|
 | 
						|
This message is safe to ignore, as long as the error is 114 Operation
 | 
						|
already in progress; in that specific case, it means that the PPPoE session
 | 
						|
has already been disabled before pppd tried to disable it.
 | 
						|
 | 
						|
Signed-off-by: Simon Farnsworth <simon@farnz.org.uk>
 | 
						|
Tested-by: Dan Williams <dcbw@redhat.com>
 | 
						|
Tested-by: Christoph Schulz <develop@kristov.de>
 | 
						|
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
						|
---
 | 
						|
 | 
						|
--- a/drivers/net/ppp/pppoe.c
 | 
						|
+++ b/drivers/net/ppp/pppoe.c
 | 
						|
@@ -454,6 +454,18 @@ out:
 | 
						|
 	return NET_RX_DROP;
 | 
						|
 }
 | 
						|
 
 | 
						|
+static void pppoe_unbind_sock_work(struct work_struct *work)
 | 
						|
+{
 | 
						|
+	struct pppox_sock *po = container_of(work, struct pppox_sock,
 | 
						|
+					     proto.pppoe.padt_work);
 | 
						|
+	struct sock *sk = sk_pppox(po);
 | 
						|
+
 | 
						|
+	lock_sock(sk);
 | 
						|
+	pppox_unbind_sock(sk);
 | 
						|
+	release_sock(sk);
 | 
						|
+	sock_put(sk);
 | 
						|
+}
 | 
						|
+
 | 
						|
 /************************************************************************
 | 
						|
  *
 | 
						|
  * Receive a PPPoE Discovery frame.
 | 
						|
@@ -499,7 +511,8 @@ static int pppoe_disc_rcv(struct sk_buff
 | 
						|
 		}
 | 
						|
 
 | 
						|
 		bh_unlock_sock(sk);
 | 
						|
-		sock_put(sk);
 | 
						|
+		if (!schedule_work(&po->proto.pppoe.padt_work))
 | 
						|
+			sock_put(sk);
 | 
						|
 	}
 | 
						|
 
 | 
						|
 abort:
 | 
						|
@@ -612,6 +625,8 @@ static int pppoe_connect(struct socket *
 | 
						|
 
 | 
						|
 	lock_sock(sk);
 | 
						|
 
 | 
						|
+	INIT_WORK(&po->proto.pppoe.padt_work, pppoe_unbind_sock_work);
 | 
						|
+
 | 
						|
 	error = -EINVAL;
 | 
						|
 	if (sp->sa_protocol != PX_PROTO_OE)
 | 
						|
 		goto end;
 | 
						|
--- a/include/linux/if_pppox.h
 | 
						|
+++ b/include/linux/if_pppox.h
 | 
						|
@@ -19,6 +19,7 @@
 | 
						|
 #include <linux/netdevice.h>
 | 
						|
 #include <linux/ppp_channel.h>
 | 
						|
 #include <linux/skbuff.h>
 | 
						|
+#include <linux/workqueue.h>
 | 
						|
 #include <uapi/linux/if_pppox.h>
 | 
						|
 
 | 
						|
 static inline struct pppoe_hdr *pppoe_hdr(const struct sk_buff *skb)
 | 
						|
@@ -32,6 +33,7 @@ struct pppoe_opt {
 | 
						|
 	struct pppoe_addr	pa;	  /* what this socket is bound to*/
 | 
						|
 	struct sockaddr_pppox	relay;	  /* what socket data will be
 | 
						|
 					     relayed to (PPPoE relaying) */
 | 
						|
+	struct work_struct      padt_work;/* Work item for handling PADT */
 | 
						|
 };
 | 
						|
 
 | 
						|
 struct pptp_opt {
 |