1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
- 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 (sockaddr_len != sizeof(struct sockaddr_pppox))
- --- 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 {
|