diff options
Diffstat (limited to 'target/linux/generic')
-rw-r--r-- | target/linux/generic/patches-3.18/081-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/target/linux/generic/patches-3.18/081-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch b/target/linux/generic/patches-3.18/081-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch new file mode 100644 index 0000000000..de8583058f --- /dev/null +++ b/target/linux/generic/patches-3.18/081-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch @@ -0,0 +1,89 @@ +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 +@@ -455,6 +455,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. +@@ -500,7 +512,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: +@@ -613,6 +626,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 { |