diff options
| author | Qingfang Deng <qingfang.deng@linux.dev> | 2026-08-11 11:53:10 +0800 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-08-17 14:00:30 -0700 |
| commit | 92c1bf630abf0af646562398eaa36f80b5ff677d (patch) | |
| tree | d8d714d827b0cf074ec785fc505af7baf52f285f | |
| parent | 4f1d06cf8aaa9d2cb18e5ee8835aff6177256bc6 (diff) | |
| download | linux-next-92c1bf630abf0af646562398eaa36f80b5ff677d.tar.gz linux-next-92c1bf630abf0af646562398eaa36f80b5ff677d.zip | |
pppox: drain queued packets on channel handoff
PPPIOCGCHAN both returns the channel index and marks a PPPOX socket as
bound to generic PPP, despite its getter semantic. Packets received
before that transition are queued on sk_receive_queue, but a bound
socket is no longer readable. Such packets therefore remain queued until
the socket is destroyed.
After marking a socket bound, wait for receive paths that observed the
old state to finish queueing packets, and then drain the queue into
generic PPP.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Qingfang Deng <qingfang.deng@linux.dev>
Link: https://patch.msgid.link/20260811035314.302878-1-qingfang.deng@linux.dev
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/net/ppp/pppox.c | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/drivers/net/ppp/pppox.c b/drivers/net/ppp/pppox.c index 5861a2f6ce3e..a6f72c813bef 100644 --- a/drivers/net/ppp/pppox.c +++ b/drivers/net/ppp/pppox.c @@ -74,7 +74,9 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) switch (cmd) { case PPPIOCGCHAN: { + struct sk_buff *skb; int index; + rc = -ENOTCONN; if (!(sk->sk_state & PPPOX_CONNECTED)) break; @@ -85,7 +87,22 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) break; rc = 0; + /* PPPIOCGCHAN historically marks the userspace handoff to + * generic PPP; pppd then attaches the returned channel to + * /dev/ppp. + */ sk->sk_state |= PPPOX_BOUND; + /* Let lockless receive paths finish queueing against the old + * state. + */ + synchronize_net(); + /* Drain packets queued before the handoff because a bound + * socket is no longer readable. + */ + while ((skb = skb_dequeue(&sk->sk_receive_queue))) { + skb_orphan(skb); + ppp_input(&po->chan, skb); + } break; } default: |
