After net/ifq.c rev 1.38 was reverted pppac(4) still has this problem.
pppac_output() called under NET_LOCK(). pppac_output() calls if_enqueue()
which calls ifq_start(). But now ifq_start() can run pppac_input()
directly under NET_LOCK() and also is can enqueue work and pppac_input()
will be called without NET_LOCK(). pppac_input() calls pipex_output() which
requires NET_LOCK().
We can be sure what pppx_if_input() will be always called under
NET_LOCK() because it's `if_snd' queue size is 1. I guess to make this
restriction to pppac(4) just to be sure pppac_input() is always called under
NET_LOCK() as temporary solution. I guess it's better then unlock/lock
dances around if_enqueue().
Also 6.7 release has this problem. And I like to know, how to fix it too.
Index: sys/net/if_pppx.c
===================================================================
RCS file: /cvs/src/sys/net/if_pppx.c,v
retrieving revision 1.84
diff -u -p -r1.84 if_pppx.c
--- sys/net/if_pppx.c 18 Apr 2020 04:03:56 -0000 1.84
+++ sys/net/if_pppx.c 21 May 2020 12:31:49 -0000
@@ -1054,6 +1054,8 @@ pppx_if_start(struct ifnet *ifp)
struct mbuf *m;
int proto;
+ NET_ASSERT_LOCKED();
+
if (!ISSET(ifp->if_flags, IFF_RUNNING))
return;
@@ -1290,6 +1292,8 @@ pppacopen(dev_t dev, int flags, int mode
ifp->if_output = pppac_output;
ifp->if_start = pppac_start;
ifp->if_ioctl = pppac_ioctl;
+ /* XXX: To be sure pppac_input() is called under NET_LOCK() */
+ IFQ_SET_MAXLEN(&ifp->if_snd, 1);
if_counters_alloc(ifp);
if_attach(ifp);
@@ -1609,6 +1613,8 @@ pppac_output(struct ifnet *ifp, struct m
{
int error;
+ NET_ASSERT_LOCKED();
+
if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
error = EHOSTDOWN;
goto drop;
@@ -1639,6 +1645,8 @@ pppac_start(struct ifnet *ifp)
{
struct pppac_softc *sc = ifp->if_softc;
struct mbuf *m;
+
+ NET_ASSERT_LOCKED();
while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) {
#if NBPFILTER > 0