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);
> 

Reply via email to