<feed xmlns='http://www.w3.org/2005/Atom'>
<title>accel-ppp.git/drivers, branch master</title>
<subtitle>High performance PPTP/L2TP/SSTP/PPPoE/IPoE server for Linux (mirror of https://github.com/accel-ppp/accel-ppp.git)
</subtitle>
<id>https://git.amelek.net/accel-ppp/accel-ppp.git/atom?h=master</id>
<link rel='self' href='https://git.amelek.net/accel-ppp/accel-ppp.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.amelek.net/accel-ppp/accel-ppp.git/'/>
<updated>2026-08-31T15:30:54+00:00</updated>
<entry>
<title>Merge pull request #346 from nuclearcat/ipoe-stale-session-flush</title>
<updated>2026-08-31T15:30:54+00:00</updated>
<author>
<name>Denys Fedoryshchenko</name>
<email>denys.f@collabora.com</email>
</author>
<published>2026-08-31T15:30:54+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/accel-ppp/accel-ppp.git/commit/?id=40575b78b7bb043c7a0ff4dd29a048be056dee9f'/>
<id>urn:sha1:40575b78b7bb043c7a0ff4dd29a048be056dee9f</id>
<content type='text'>
Ipoe stale session flush fixes</content>
</entry>
<entry>
<title>pptp: drop the out-of-tree kernel driver</title>
<updated>2026-08-09T10:30:39+00:00</updated>
<author>
<name>Denys Fedoryshchenko</name>
<email>denys.f@collabora.com</email>
</author>
<published>2026-08-09T03:54:53+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/accel-ppp/accel-ppp.git/commit/?id=49a94430c090068ca96f1dc38ed24cd93c2e324d'/>
<id>urn:sha1:49a94430c090068ca96f1dc38ed24cd93c2e324d</id>
<content type='text'>
drivers/pptp is version 0.8.5 of the PPTP driver, the direct ancestor of mainline drivers/net/ppp/pptp.c. Mainline merged that code in 2.6.37 (2011) from the same author and has maintained it since; this copy received none of the subsequent fixes and is no longer worth carrying:

- It cannot be built. struct flowi's nl_u union, the 3-argument ip_route_output_key(), sock_no_poll, the old ip_select_ident() signature and nf_reset() all disappeared long ago, so nothing past roughly 2.6.36 compiles and -DBUILD_PPTP_DRIVER=TRUE is a build failure everywhere.

- It is not needed. The PPTP bits of accel-pppd/include/if_pppox.h are identical to the mainline UAPI header, so ctrl/pptp's socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_PPTP) reaches the in-kernel module (alias net-pf-24-proto-2) unchanged. The daemon uses no interface the bundled driver added. The deleted drivers/pptp/if_pppox.h was included only by drivers/pptp/pptp.c; all other if_pppox.h includes use either the kernel UAPI header or accel-pppd's userspace copy.

- It is unsafe. Among others: the pskb_may_pull() in pptp_rcv() is commented out, so the GRE header is parsed with no length validation at all; the skb-&gt;len - headersize comparison in pptp_rcv_core() underflows and leads to an out-of-bounds read and a negative skb_pull(); pptp_getname() copies uninitialised stack to userspace; and pptp_bind()/pptp_connect() never check sockaddr_len (CVE-2015-8569). Mainline fixed each of these years ago.

Remove the directory along with the BUILD_PPTP_DRIVER option, the accel-pptp-kmod package and the ip_gre conflict warning, which only existed because this module claimed IPPROTO_GRE. accel-pppd/ctrl/pptp and accel-pppd/include/if_pppox.h are unaffected. PPTP now requires the kernel's own pptp module; kernels older than 2.6.37 are no longer supported.
</content>
</entry>
<entry>
<title>ipoe: include net/rtnetlink.h, insert modules in ci even after a failure</title>
<updated>2026-08-08T16:12:49+00:00</updated>
<author>
<name>Denys Fedoryshchenko</name>
<email>denys.f@collabora.com</email>
</author>
<published>2026-08-08T16:12:49+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/accel-ppp/accel-ppp.git/commit/?id=9015abafb60f950a6b1a800f84cbf569b07828a1'/>
<id>urn:sha1:9015abafb60f950a6b1a800f84cbf569b07828a1</id>
<content type='text'>
rtnl_link_register() and struct rtnl_link_ops were reaching the driver
through some other header rather than through net/rtnetlink.h, which is
the kind of thing that only shows up when building against a different
kernel. Include it directly.

The workflows insert the kernel modules between two pytest runs, and the
runs that follow are marked 'if: always()' while the insmod steps are
not. A failure in an earlier, unrelated test therefore skips the insmod
but still runs the tests that need the module, which then report a
missing driver instead of the original problem. Mark the insmod steps
'if: always()' as well, so that the later runs test what they are
supposed to.
</content>
</entry>
<entry>
<title>ipoe: allow session interfaces to be removed with ip link del</title>
<updated>2026-08-08T15:12:56+00:00</updated>
<author>
<name>Denys Fedoryshchenko</name>
<email>denys.f@collabora.com</email>
</author>
<published>2026-08-08T15:12:56+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/accel-ppp/accel-ppp.git/commit/?id=4969b65c3f55c739a0c9178086f42ba3de906119'/>
<id>urn:sha1:4969b65c3f55c739a0c9178086f42ba3de906119</id>
<content type='text'>
Sessions left in the kernel by a dead daemon could only be got rid of by
restarting accel-pppd, which flushes all of them and so drops everyone
still online, or by unloading the module. Neither is of much use when a
single stale interface is holding an address and every subscriber that
is later handed it is refused with EEXIST.

Register rtnl_link_ops, so that RTM_DELLINK reaches the driver:

	ip link show type ipoe		enumerate them
	ip -d link show ipoe42		reports kind "ipoe"
	ip link del ipoe42		remove a single one

newlink returns EOPNOTSUPP rather than being left out. A session carries
private state that IPOE_CMD_CREATE sets up, and a kernel that falls back
to register_netdevice() when newlink is NULL would hand out a device
with zeroed private state and no percpu counters, which oopses on the
first packet or on ip -s link show.

dellink runs under rtnl and outside genl_mutex, and is therefore the
first writer in this driver that does not serialise against the genl
handlers: it can unlink a session that IPOE_CMD_DELETE is about to
unlink as well, since the device stays registered until both are done.
Add ipoe_session.dying, set under ipoe_wlock by whichever path starts
the teardown, and let the other one bail out.

That leaves rtnl nested inside ipoe_wlock, which is safe because no path
does it the other way round: ipoe_create() releases rtnl before taking
ipoe_wlock, ipoe_nl_cmd_delete() releases ipoe_wlock before calling
unregister_netdev(), and the interface commands use rtnl alone. dellink
does have to sleep in synchronize_rcu() and while draining the session
refcount with rtnl held, which the genl path avoids by deferring both
until after it has dropped everything.

A session left behind by a dead daemon is indistinguishable from one
that is still in use - same peer address, same lists, same flags - so
the removal cannot be refused on state alone. Warn instead, and only
when somebody is still subscribed to the packet multicast group, so that
clearing stale interfaces on a box where accel-pppd is not running stays
quiet.
</content>
</entry>
<entry>
<title>ipoe: flush sessions left by a previous instance with a single command</title>
<updated>2026-08-08T14:47:49+00:00</updated>
<author>
<name>Denys Fedoryshchenko</name>
<email>denys.f@collabora.com</email>
</author>
<published>2026-08-08T14:47:49+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/accel-ppp/accel-ppp.git/commit/?id=6693d18ae0232da2c6febc0decf099e4fd064381'/>
<id>urn:sha1:6693d18ae0232da2c6febc0decf099e4fd064381</id>
<content type='text'>
On startup accel-pppd is expected to drop everything a previous instance
left behind in the kernel. For sessions it did so by dumping them with
IPOE_CMD_GET and sending one IPOE_CMD_DELETE per ifindex. That dump was
written for the session backup code removed in 1972a7e5c and was never
adapted to its new, destructive role:

 - it was issued on the socket subscribed to the packet multicast group,
   so it competed with the notifications that the still attached stale
   rx handlers keep generating; on a loaded box the receive buffer
   overruns and rtnl_dump_filter() gives up with ENOBUFS,
 - its return value was discarded, so such a failure was silent,
 - it ran before the interfaces were detached, which is what produces
   those notifications in the first place,
 - it was skipped entirely when the multicast group could not be
   resolved, again with nothing but a warning about packet handling,
 - and every session cost a socket, a round trip, a grace period and a
   full unregister_netdev().

Whatever it missed stays in the kernel forever: the daemon has no record
of those sessions, so nothing ever deletes them, and every subscriber
later assigned one of their addresses is refused with EEXIST by
IPOE_CMD_MODIFY.

Add IPOE_CMD_FLUSH, which unlinks all sessions in one go, waits for a
single grace period and unregisters the devices with
unregister_netdevice_many(), and use it instead. The old path is kept as
a fallback for a module predating the command, which is reported as
EOPNOTSUPP, and now checks its return value and uses a private socket.

Reorder init() so the interfaces are detached before the multicast group
is joined, and so the flush also runs when only the group lookup failed.
</content>
</entry>
<entry>
<title>ipoe: do not skip a session when a dump spans several messages</title>
<updated>2026-08-08T14:46:44+00:00</updated>
<author>
<name>Denys Fedoryshchenko</name>
<email>denys.f@collabora.com</email>
</author>
<published>2026-08-08T14:46:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/accel-ppp/accel-ppp.git/commit/?id=4fb21bfd967ee834d2b5d5ea11d0838002d6ac1a'/>
<id>urn:sha1:4fb21bfd967ee834d2b5d5ea11d0838002d6ac1a</id>
<content type='text'>
ipoe_nl_cmd_dump_sessions() increments idx before calling fill_info(),
so once fill_info() fails because the skb is full, idx already points
past the session that did not fit. cb-&gt;args[0] is set to that value and
the next round resumes one entry too far, dropping the session from the
dump entirely - one lost session per message boundary, roughly one in
every 90 at the current record size.

Step idx back before leaving the loop.
</content>
</entry>
<entry>
<title>ipoe: fix ipoe_wlock double release in IPOE_CMD_DELETE</title>
<updated>2026-08-08T14:20:32+00:00</updated>
<author>
<name>Denys Fedoryshchenko</name>
<email>denys.f@collabora.com</email>
</author>
<published>2026-08-08T14:20:32+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/accel-ppp/accel-ppp.git/commit/?id=59124bbc26bf0211723b3eb5b5186d3dc7b72b0c'/>
<id>urn:sha1:59124bbc26bf0211723b3eb5b5186d3dc7b72b0c</id>
<content type='text'>
ipoe_nl_cmd_delete() drops ipoe_wlock before sleeping in
synchronize_rcu() and taking rtnl via unregister_netdev(), then falls
through into the out_unlock label and releases it a second time. Every
successful session delete therefore increments the semaphore count by
one.

Since the count only ever grows, ipoe_wlock stops providing mutual
exclusion after a handful of teardowns: with the count at N, up to N+1
writers may hold it simultaneously. This is currently masked because
ipoe_nl_family does not set parallel_ops, so genetlink serialises every
.doit/.dumpit under genl_mutex and no two writers can overlap in
practice. It turns into a real race on the session hash lists as soon as
that changes, or as soon as a writer is introduced outside the genl
handlers.

It also silently defeats the barrier in ipoe_fini(): the down()/up()
pair meant to wait for an in-flight writer is satisfied immediately by
the leaked count and waits for nothing.

Return directly after unregister_netdev() so the success path releases
the lock exactly once. The early up() is deliberate and stays where it
is - holding a sleeping semaphore across unregister_netdev() would nest
ipoe_wlock inside rtnl, while ipoe_create() takes rtnl first and
ipoe_wlock afterwards. Error paths, return values and lock ordering are
unchanged.
</content>
</entry>
<entry>
<title>sstp: add ppposeq transport to avoid userspace HDLC framing</title>
<updated>2026-08-04T20:41:46+00:00</updated>
<author>
<name>Vladislav Grishenko</name>
<email>themiron@mail.ru</email>
</author>
<published>2026-07-30T10:48:55+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/accel-ppp/accel-ppp.git/commit/?id=3b08133ee131bca35b10bcc133f6adaf5d125c21'/>
<id>urn:sha1:3b08133ee131bca35b10bcc133f6adaf5d125c21</id>
<content type='text'>
A pty is a byte stream, so the tty flip buffer merges frames written
back to back and sstp has to re-delimit them with async HDLC escaping
and a CRC-16 FCS. On a 1452-byte payload that is ~3600 ns per frame,
most of it spent on the FCS.

PPPOSEQ is a pppox protocol whose socket is the ppp endpoint itself,
so one datagram is one frame and no framing is needed at all. The
same payload takes ~380 ns per frame, about 9 times less. Requires
kernel 2.6.37, the first with PX_MAX_PROTO 3, whose remaining slot
it claims.
Supported kernels are from 2.6.37 to 7.2.

The new ppp-mode option selects the transport; auto, the default,
falls back to async when the module is unavailable, so hosts with
prebuilt kernels are unaffected.

PPP_SYNC is removed, being disabled and unfixable over a pty: frame
boundaries cannot be recovered from the stream, and coalescing cannot
be prevented since frames arrive from the network stack.
</content>
</entry>
<entry>
<title>ipoe: Fix OOPS if ipv6.disable=1</title>
<updated>2026-07-06T08:07:00+00:00</updated>
<author>
<name>Denys Fedoryshchenko</name>
<email>denys.f@collabora.com</email>
</author>
<published>2026-07-06T08:04:10+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/accel-ppp/accel-ppp.git/commit/?id=6930d048efe7be06cd36e7413914be0bec4a45b5'/>
<id>urn:sha1:6930d048efe7be06cd36e7413914be0bec4a45b5</id>
<content type='text'>
ipoe_recv() handles every ETH_P_IPV6 frame arriving on an IPoE
by calling ipoe_lookup_rt6()/ip6_route_output().
On ipv6.disable=1 IPv6 FIB is not initialized.
We can detect that by ipv6_mod_enabled() since kernel 4.8,
and return RX_HANDLER_PASS, so packet falls thru normal stack and get discarded.

Fixes: https://github.com/accel-ppp/accel-ppp/issues/313

Signed-off-by: Denys Fedoryshchenko &lt;denys.f@collabora.com&gt;
</content>
</entry>
<entry>
<title>vlan_mon: bind ETH_P_ALL packet handler to init_net on kernels &gt;= 6.6</title>
<updated>2026-05-02T11:56:26+00:00</updated>
<author>
<name>Denys Fedoryshchenko</name>
<email>denys.f@collabora.com</email>
</author>
<published>2026-05-02T11:56:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.amelek.net/accel-ppp/accel-ppp.git/commit/?id=ca68d8c427d6654a73e018ab85d6191d6bfb191e'/>
<id>urn:sha1:ca68d8c427d6654a73e018ab85d6191d6bfb191e</id>
<content type='text'>
The vlan_mon driver registers a global packet_type with type=ETH_P_ALL
to intercept PADI/IP/ARP frames before they reach the protocol stack.
Since Linux 6.6 the per-net-namespace ptype_all conversion (commit
"net: af_packet: switch ptype_all to per-net-namespace lists") requires
every ETH_P_ALL packet_type to have either -&gt;dev or -&gt;af_packet_net
set; ptype_head() now does:

    WARN_ON_ONCE(!pt-&gt;af_packet_net &amp;&amp; !pt-&gt;dev);
    return pt-&gt;dev ? &amp;pt-&gt;dev-&gt;ptype_all
                   : &amp;pt-&gt;af_packet_net-&gt;ptype_all;

With both fields NULL on our static vlan_pt, dev_add_pack() trips the
WARN at module load and the handler is never linked into any usable
list, so vlan_pt_recv() is never invoked. Userspace sets up the
genetlink subscription correctly and gets a clean ACK from
VLAN_MON_CMD_ADD, but no notifications ever arrive because the kernel
side never sees the PADI. PPPoE-over-VLAN tests time out waiting for
PADO.

This was visible on Ubuntu's 6.17 azure kernel as a backtrace from
vlan_mon_init -&gt; dev_add_pack at net/core/dev.c:609 in dmesg, and as
a silent failure of tests/accel-pppd/pppoe/test_pppoe_vlan_mon.

Set vlan_pt.af_packet_net = &amp;init_net before dev_add_pack() on kernels
new enough to require it. The driver only operates in init_net anyway
(all dev_get_by_index() calls are against &amp;init_net), so this matches
existing behaviour.

Signed-off-by: Denys Fedoryshchenko &lt;denys.f@collabora.com&gt;
</content>
</entry>
</feed>
