This time pppx_add_session() has mixed initialisation order. It starts
to initialise pipex(4) session, then initialises `ifnet', then links
pipex(4) session, then continue to initialize `ifnet'.
pppx_add_session() can sleep and pppx_if_start() can start to work with
unlinked pipex(4) session.

Also pppx_if_destroy() can sleep and pppx_if_start() can access to this
`pxi' with unlinked session. pppx_if_start() has checking of
`IFF_RUNNING' flag but it's usesless.

Diff below does pppx_add_session() reordering. At first we initilize
and attach `ifnet', at second we initialize and link pipex(4) session
and at last we set `IFF_RUNNING' flag on `ifnet.

Also we cleaning `IFF_RUNNING' flag before pppx(4) session destruction
in pppx_if_destroy().

Since we made `ifnet' and pipex(4) session initialization separately, we
are more close to remove duplicated code.


Index: sys/net/if_pppx.c
===================================================================
RCS file: /cvs/src/sys/net/if_pppx.c,v
retrieving revision 1.87
diff -u -p -r1.87 if_pppx.c
--- sys/net/if_pppx.c   29 May 2020 06:51:52 -0000      1.87
+++ sys/net/if_pppx.c   29 May 2020 09:27:47 -0000
@@ -674,16 +674,111 @@ pppx_add_session(struct pppx_dev *pxd, s
         *      the timeout feature until this is fixed.
         */
        if (req->pr_timeout_sec != 0)
-               return (EINVAL);
+               return EINVAL;
+
+       pxi = pool_get(pppx_if_pl, PR_WAITOK | PR_ZERO);
+
+       /* try to set the interface up */
+       unit = pppx_if_next_unit();
+       if (unit < 0) {
+               error = ENOMEM;
+               goto out;
+       }
+
+       pxi->pxi_unit = unit;
+       pxi->pxi_key.pxik_session_id = req->pr_session_id;
+       pxi->pxi_key.pxik_protocol = req->pr_protocol;
+       pxi->pxi_dev = pxd;
+
+       /* this is safe without splnet since we're not modifying it */
+       if (RBT_FIND(pppx_ifs, &pppx_ifs, pxi) != NULL) {
+               error = EADDRINUSE;
+               goto out;
+       }
+
+       if (RBT_INSERT(pppx_ifs, &pppx_ifs, pxi) != NULL)
+               panic("%s: pppx_ifs modified while lock was held", __func__);
+       LIST_INSERT_HEAD(&pxd->pxd_pxis, pxi, pxi_list);
+
+       ifp = &pxi->pxi_if;
+       snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", "pppx", unit);
+       ifp->if_mtu = req->pr_peer_mru; /* XXX */
+       ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST | IFF_UP;
+       ifp->if_start = pppx_if_start;
+       ifp->if_output = pppx_if_output;
+       ifp->if_ioctl = pppx_if_ioctl;
+       ifp->if_rtrequest = p2p_rtrequest;
+       ifp->if_type = IFT_PPP;
+       IFQ_SET_MAXLEN(&ifp->if_snd, 1);
+       ifp->if_softc = pxi;
+       /* ifp->if_rdomain = req->pr_rdomain; */
+
+       /* XXXSMP breaks atomicity */
+       NET_UNLOCK();
+       if_attach(ifp);
+       NET_LOCK();
+
+       if_addgroup(ifp, "pppx");
+       if_alloc_sadl(ifp);
+
+#if NBPFILTER > 0
+       bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
+#endif
+
+       /* XXX ipv6 support?  how does the caller indicate it wants ipv6
+        * instead of ipv4?
+        */
+       memset(&ifaddr, 0, sizeof(ifaddr));
+       ifaddr.sin_family = AF_INET;
+       ifaddr.sin_len = sizeof(ifaddr);
+       ifaddr.sin_addr = req->pr_ip_srcaddr;
+
+       ia = malloc(sizeof (*ia), M_IFADDR, M_WAITOK | M_ZERO);
+
+       ia->ia_addr.sin_family = AF_INET;
+       ia->ia_addr.sin_len = sizeof(struct sockaddr_in);
+       ia->ia_addr.sin_addr = req->pr_ip_srcaddr;
+
+       ia->ia_dstaddr.sin_family = AF_INET;
+       ia->ia_dstaddr.sin_len = sizeof(struct sockaddr_in);
+       ia->ia_dstaddr.sin_addr = req->pr_ip_address;
+
+       ia->ia_sockmask.sin_family = AF_INET;
+       ia->ia_sockmask.sin_len = sizeof(struct sockaddr_in);
+       ia->ia_sockmask.sin_addr = req->pr_ip_netmask;
+
+       ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
+       ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
+       ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
+       ia->ia_ifa.ifa_ifp = ifp;
+
+       ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr;
+
+       error = in_ifinit(ifp, ia, &ifaddr, 1);
+       if (error) {
+               printf("pppx: unable to set addresses for %s, error=%d\n",
+                   ifp->if_xname, error);
+               goto out_detach;
+       }
+
+       if_addrhooks_run(ifp);
+
+       /* fake a pipex interface context */
+       pxi->pxi_ifcontext.ifnet_this = ifp;
+       pxi->pxi_ifcontext.pipexmode = PIPEX_ENABLED;
 
        switch (req->pr_protocol) {
 #ifdef PIPEX_PPPOE
        case PIPEX_PROTO_PPPOE:
                over_ifp = ifunit(req->pr_proto.pppoe.over_ifname);
-               if (over_ifp == NULL)
-                       return (EINVAL);
-               if (req->pr_peer_address.ss_family != AF_UNSPEC)
-                       return (EINVAL);
+               if (over_ifp == NULL) {
+                       error = EINVAL;
+                       goto out_detach;
+               }
+               if (req->pr_peer_address.ss_family != AF_UNSPEC) {
+                       error = EINVAL;
+                       goto out_detach;
+               }
                break;
 #endif
 #if defined(PIPEX_PPTP) || defined(PIPEX_L2TP)
@@ -691,45 +786,49 @@ pppx_add_session(struct pppx_dev *pxd, s
        case PIPEX_PROTO_L2TP:
                switch (req->pr_peer_address.ss_family) {
                case AF_INET:
-                       if (req->pr_peer_address.ss_len != sizeof(struct 
sockaddr_in))
-                               return (EINVAL);
+                       if (req->pr_peer_address.ss_len !=
+                           sizeof(struct sockaddr_in)) {
+                               error = EINVAL;
+                               goto out_detach;
+                       }
                        break;
 #ifdef INET6
                case AF_INET6:
-                       if (req->pr_peer_address.ss_len != sizeof(struct 
sockaddr_in6))
-                               return (EINVAL);
+                       if (req->pr_peer_address.ss_len !=
+                           sizeof(struct sockaddr_in6)) {
+                               error = EINVAL;
+                               goto out_detach;
+                       }
                        break;
 #endif
                default:
-                       return (EPROTONOSUPPORT);
+                       error = EPROTONOSUPPORT;
+                       goto out_detach;
                }
                if (req->pr_peer_address.ss_family !=
                    req->pr_local_address.ss_family ||
                    req->pr_peer_address.ss_len !=
-                   req->pr_local_address.ss_len)
-                       return (EINVAL);
+                   req->pr_local_address.ss_len) {
+                       error = EINVAL;
+                       goto out_detach;
+               }
                break;
 #endif /* defined(PIPEX_PPTP) || defined(PIPEX_L2TP) */
        default:
-               return (EPROTONOSUPPORT);
+               error = EPROTONOSUPPORT;
+               goto out_detach;
        }
 
        session = pipex_lookup_by_session_id(req->pr_protocol,
            req->pr_session_id);
-       if (session)
-               return (EEXIST);
-
-       pxi = pool_get(pppx_if_pl, PR_WAITOK | PR_ZERO);
+       if (session) {
+               error = EEXIST;
+               goto out_detach;
+       }
 
+       /* setup session */
        session = &pxi->pxi_session;
-       ifp = &pxi->pxi_if;
-
-       /* fake a pipex interface context */
        session->pipex_iface = &pxi->pxi_ifcontext;
-       session->pipex_iface->ifnet_this = ifp;
-       session->pipex_iface->pipexmode = PIPEX_ENABLED;
-
-       /* setup session */
        session->state = PIPEX_STATE_OPENED;
        session->protocol = req->pr_protocol;
        session->session_id = req->pr_session_id;
@@ -816,48 +915,12 @@ pppx_add_session(struct pppx_dev *pxd, s
        if (pipex_session_is_mppe_required(session)) {
                if (!pipex_session_is_mppe_enabled(session) ||
                    !pipex_session_is_mppe_accepted(session)) {
-                       pool_put(pppx_if_pl, pxi);
-                       return (EINVAL);
+                       error = EINVAL;
+                       goto out_detach;
                }
        }
 #endif
 
-       /* try to set the interface up */
-       unit = pppx_if_next_unit();
-       if (unit < 0) {
-               pool_put(pppx_if_pl, pxi);
-               error = ENOMEM;
-               goto out;
-       }
-
-       pxi->pxi_unit = unit;
-       pxi->pxi_key.pxik_session_id = req->pr_session_id;
-       pxi->pxi_key.pxik_protocol = req->pr_protocol;
-       pxi->pxi_dev = pxd;
-
-       /* this is safe without splnet since we're not modifying it */
-       if (RBT_FIND(pppx_ifs, &pppx_ifs, pxi) != NULL) {
-               pool_put(pppx_if_pl, pxi);
-               error = EADDRINUSE;
-               goto out;
-       }
-
-       if (RBT_INSERT(pppx_ifs, &pppx_ifs, pxi) != NULL)
-               panic("%s: pppx_ifs modified while lock was held", __func__);
-       LIST_INSERT_HEAD(&pxd->pxd_pxis, pxi, pxi_list);
-
-       snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", "pppx", unit);
-       ifp->if_mtu = req->pr_peer_mru; /* XXX */
-       ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST | IFF_UP;
-       ifp->if_start = pppx_if_start;
-       ifp->if_output = pppx_if_output;
-       ifp->if_ioctl = pppx_if_ioctl;
-       ifp->if_rtrequest = p2p_rtrequest;
-       ifp->if_type = IFT_PPP;
-       IFQ_SET_MAXLEN(&ifp->if_snd, 1);
-       ifp->if_softc = pxi;
-       /* ifp->if_rdomain = req->pr_rdomain; */
-
        /* hook up pipex context */
        chain = PIPEX_ID_HASHTABLE(session->session_id);
        LIST_INSERT_HEAD(chain, session, id_chain);
@@ -877,58 +940,21 @@ pppx_add_session(struct pppx_dev *pxd, s
        if (LIST_NEXT(session, session_list) == NULL)
                pipex_timer_start();
 
-       /* XXXSMP breaks atomicity */
-       NET_UNLOCK();
-       if_attach(ifp);
-       NET_LOCK();
-
-       if_addgroup(ifp, "pppx");
-       if_alloc_sadl(ifp);
-
-#if NBPFILTER > 0
-       bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
-#endif
        SET(ifp->if_flags, IFF_RUNNING);
+       pxi->pxi_ready = 1;
 
-       /* XXX ipv6 support?  how does the caller indicate it wants ipv6
-        * instead of ipv4?
-        */
-       memset(&ifaddr, 0, sizeof(ifaddr));
-       ifaddr.sin_family = AF_INET;
-       ifaddr.sin_len = sizeof(ifaddr);
-       ifaddr.sin_addr = req->pr_ip_srcaddr;
-
-       ia = malloc(sizeof (*ia), M_IFADDR, M_WAITOK | M_ZERO);
-
-       ia->ia_addr.sin_family = AF_INET;
-       ia->ia_addr.sin_len = sizeof(struct sockaddr_in);
-       ia->ia_addr.sin_addr = req->pr_ip_srcaddr;
-
-       ia->ia_dstaddr.sin_family = AF_INET;
-       ia->ia_dstaddr.sin_len = sizeof(struct sockaddr_in);
-       ia->ia_dstaddr.sin_addr = req->pr_ip_address;
-
-       ia->ia_sockmask.sin_family = AF_INET;
-       ia->ia_sockmask.sin_len = sizeof(struct sockaddr_in);
-       ia->ia_sockmask.sin_addr = req->pr_ip_netmask;
-
-       ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
-       ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
-       ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
-       ia->ia_ifa.ifa_ifp = ifp;
-
-       ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr;
+       return 0;
 
-       error = in_ifinit(ifp, ia, &ifaddr, 1);
-       if (error) {
-               printf("pppx: unable to set addresses for %s, error=%d\n",
-                   ifp->if_xname, error);
-       } else {
-               if_addrhooks_run(ifp);
-       }
-       pxi->pxi_ready = 1;
+out_detach:
+       /* XXXSMP breaks atomicity */
+       NET_UNLOCK();
+       if_detach(ifp);
+       NET_LOCK();
 
+       KASSERT(RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) != NULL);
+       LIST_REMOVE(pxi, pxi_list);
 out:
+       pool_put(pppx_if_pl, pxi);
        return (error);
 }
 
@@ -1004,9 +1030,11 @@ pppx_if_destroy(struct pppx_dev *pxd, st
        struct pipex_session *session;
 
        NET_ASSERT_LOCKED();
-       pxi->pxi_ready = 0;
-       session = &pxi->pxi_session;
        ifp = &pxi->pxi_if;
+       session = &pxi->pxi_session;
+
+       pxi->pxi_ready = 0;
+       CLR(ifp->if_flags, IFF_RUNNING);
 
        LIST_REMOVE(session, id_chain);
        LIST_REMOVE(session, session_list);

Reply via email to