On 29/05/20(Fri) 13:22, Vitaliy Makkoveev wrote: > 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.
The fact that you have to call if_detach() if a field isn't validated makes me wonder if this refactoring is better than the existing logic. > Also we cleaning `IFF_RUNNING' flag before pppx(4) session destruction > in pppx_if_destroy(). This seems unrelated. > Since we made `ifnet' and pipex(4) session initialization separately, we > are more close to remove duplicated code. Can't we do that directly? There are many blocks in this function: - Allocate a `pxi' - Attach an interface (`ifp') - Insert an address on the interface - Link the `pxi' with the interface - Setup the session Maybe user input validation should be done first. > 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); >