Skip to content

Commit 287f3a9

Browse files
farnzdavem330
authored andcommitted
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 <[email protected]> Tested-by: Dan Williams <[email protected]> Tested-by: Christoph Schulz <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 26caa34 commit 287f3a9

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

drivers/net/ppp/pppoe.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,18 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev,
455455
return NET_RX_DROP;
456456
}
457457

458+
static void pppoe_unbind_sock_work(struct work_struct *work)
459+
{
460+
struct pppox_sock *po = container_of(work, struct pppox_sock,
461+
proto.pppoe.padt_work);
462+
struct sock *sk = sk_pppox(po);
463+
464+
lock_sock(sk);
465+
pppox_unbind_sock(sk);
466+
release_sock(sk);
467+
sock_put(sk);
468+
}
469+
458470
/************************************************************************
459471
*
460472
* Receive a PPPoE Discovery frame.
@@ -500,7 +512,8 @@ static int pppoe_disc_rcv(struct sk_buff *skb, struct net_device *dev,
500512
}
501513

502514
bh_unlock_sock(sk);
503-
sock_put(sk);
515+
if (!schedule_work(&po->proto.pppoe.padt_work))
516+
sock_put(sk);
504517
}
505518

506519
abort:
@@ -613,6 +626,8 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
613626

614627
lock_sock(sk);
615628

629+
INIT_WORK(&po->proto.pppoe.padt_work, pppoe_unbind_sock_work);
630+
616631
error = -EINVAL;
617632
if (sp->sa_protocol != PX_PROTO_OE)
618633
goto end;

include/linux/if_pppox.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/netdevice.h>
2020
#include <linux/ppp_channel.h>
2121
#include <linux/skbuff.h>
22+
#include <linux/workqueue.h>
2223
#include <uapi/linux/if_pppox.h>
2324

2425
static inline struct pppoe_hdr *pppoe_hdr(const struct sk_buff *skb)
@@ -32,6 +33,7 @@ struct pppoe_opt {
3233
struct pppoe_addr pa; /* what this socket is bound to*/
3334
struct sockaddr_pppox relay; /* what socket data will be
3435
relayed to (PPPoE relaying) */
36+
struct work_struct padt_work;/* Work item for handling PADT */
3537
};
3638

3739
struct pptp_opt {

0 commit comments

Comments
 (0)