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

Reply via email to