diff options
author | Felix Fietkau <nbd@openwrt.org> | 2015-05-09 21:14:41 +0000 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2015-05-09 21:14:41 +0000 |
commit | 1b00bc68f976f0a9812bfe36cf3251d914ac62bb (patch) | |
tree | dd1e903f80aa822f4a341e1611bc9d36ffb7a5f0 /target/linux/generic/patches-4.0 | |
parent | 8b3aa19010b00466c946f1f6d3807d5d03327257 (diff) | |
download | upstream-1b00bc68f976f0a9812bfe36cf3251d914ac62bb.tar.gz upstream-1b00bc68f976f0a9812bfe36cf3251d914ac62bb.tar.bz2 upstream-1b00bc68f976f0a9812bfe36cf3251d914ac62bb.zip |
kernel: fix pppoe disconnect issues
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@45653 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/generic/patches-4.0')
2 files changed, 116 insertions, 0 deletions
diff --git a/target/linux/generic/patches-4.0/073-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch b/target/linux/generic/patches-4.0/073-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-4.0/073-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 { diff --git a/target/linux/generic/patches-4.0/100-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch b/target/linux/generic/patches-4.0/100-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch new file mode 100644 index 0000000000..c461b3e10c --- /dev/null +++ b/target/linux/generic/patches-4.0/100-pppoe-drop-pppoe-device-in-pppoe_unbind_sock_work.patch @@ -0,0 +1,27 @@ +From: Felix Fietkau <nbd@openwrt.org> +Date: Sat, 9 May 2015 23:03:47 +0200 +Subject: [PATCH] pppoe: drop pppoe device in pppoe_unbind_sock_work + +After receiving a PADT and the socket is closed, user space will no +longer drop the reference to the pppoe device. +This leads to errors like this: + +[ 488.570000] unregister_netdevice: waiting for eth0.2 to become free. Usage count = 2 + +Fixes: 287f3a943fe ("pppoe: Use workqueue to die properly when a PADT is received") +Signed-off-by: Felix Fietkau <nbd@openwrt.org> +--- + +--- a/drivers/net/ppp/pppoe.c ++++ b/drivers/net/ppp/pppoe.c +@@ -462,6 +462,10 @@ static void pppoe_unbind_sock_work(struc + struct sock *sk = sk_pppox(po); + + lock_sock(sk); ++ if (po->pppoe_dev) { ++ dev_put(po->pppoe_dev); ++ po->pppoe_dev = NULL; ++ } + pppox_unbind_sock(sk); + release_sock(sk); + sock_put(sk); |