ledtrig-netdev: update base driver instead of patching it for every kernel
[openwrt/openwrt.git] / target / linux / generic / patches-3.18 / 081-pppoe-Use-workqueue-to-die-properly-when-a-PADT-is-r.patch
1 From: Simon Farnsworth <simon@farnz.org.uk>
2 Date: Sun, 1 Mar 2015 10:54:39 +0000
3 Subject: [PATCH] pppoe: Use workqueue to die properly when a PADT is received
4
5 When a PADT frame is received, the socket may not be in a good state to
6 close down the PPP interface. The current implementation handles this by
7 simply blocking all further PPP traffic, and hoping that the lack of traffic
8 will trigger the user to investigate.
9
10 Use schedule_work to get to a process context from which we clear down the
11 PPP interface, in a fashion analogous to hangup on a TTY-based PPP
12 interface. This causes pppd to disconnect immediately, and allows tools to
13 take immediate corrective action.
14
15 Note that pppd's rp_pppoe.so plugin has code in it to disable the session
16 when it disconnects; however, as a consequence of this patch, the session is
17 already disabled before rp_pppoe.so is asked to disable the session. The
18 result is a harmless error message:
19
20 Failed to disconnect PPPoE socket: 114 Operation already in progress
21
22 This message is safe to ignore, as long as the error is 114 Operation
23 already in progress; in that specific case, it means that the PPPoE session
24 has already been disabled before pppd tried to disable it.
25
26 Signed-off-by: Simon Farnsworth <simon@farnz.org.uk>
27 Tested-by: Dan Williams <dcbw@redhat.com>
28 Tested-by: Christoph Schulz <develop@kristov.de>
29 Signed-off-by: David S. Miller <davem@davemloft.net>
30 ---
31
32 --- a/drivers/net/ppp/pppoe.c
33 +++ b/drivers/net/ppp/pppoe.c
34 @@ -455,6 +455,18 @@ out:
35 return NET_RX_DROP;
36 }
37
38 +static void pppoe_unbind_sock_work(struct work_struct *work)
39 +{
40 + struct pppox_sock *po = container_of(work, struct pppox_sock,
41 + proto.pppoe.padt_work);
42 + struct sock *sk = sk_pppox(po);
43 +
44 + lock_sock(sk);
45 + pppox_unbind_sock(sk);
46 + release_sock(sk);
47 + sock_put(sk);
48 +}
49 +
50 /************************************************************************
51 *
52 * Receive a PPPoE Discovery frame.
53 @@ -500,7 +512,8 @@ static int pppoe_disc_rcv(struct sk_buff
54 }
55
56 bh_unlock_sock(sk);
57 - sock_put(sk);
58 + if (!schedule_work(&po->proto.pppoe.padt_work))
59 + sock_put(sk);
60 }
61
62 abort:
63 @@ -613,6 +626,8 @@ static int pppoe_connect(struct socket *
64
65 lock_sock(sk);
66
67 + INIT_WORK(&po->proto.pppoe.padt_work, pppoe_unbind_sock_work);
68 +
69 error = -EINVAL;
70 if (sp->sa_protocol != PX_PROTO_OE)
71 goto end;
72 --- a/include/linux/if_pppox.h
73 +++ b/include/linux/if_pppox.h
74 @@ -19,6 +19,7 @@
75 #include <linux/netdevice.h>
76 #include <linux/ppp_channel.h>
77 #include <linux/skbuff.h>
78 +#include <linux/workqueue.h>
79 #include <uapi/linux/if_pppox.h>
80
81 static inline struct pppoe_hdr *pppoe_hdr(const struct sk_buff *skb)
82 @@ -32,6 +33,7 @@ struct pppoe_opt {
83 struct pppoe_addr pa; /* what this socket is bound to*/
84 struct sockaddr_pppox relay; /* what socket data will be
85 relayed to (PPPoE relaying) */
86 + struct work_struct padt_work;/* Work item for handling PADT */
87 };
88
89 struct pptp_opt {