On 08/06/20(Mon) 15:09, Vitaliy Makkoveev wrote: > On Mon, Jun 08, 2020 at 12:49:05PM +0300, Vitaliy Makkoveev wrote: > > [...] > > There is another way to rewrite pppx_add_session() and > > pipex_add_session(). We can split pipex_add_session() to two > > functions: pipex_init_session() and pipex_setup_session(). The first > > will do checks and insert new session with PIPEX_STATE_INITIAL state. > > The second will do the rest. So we can do checks before `ifnet’ > > dances in ppppx_add_session(). This time PIPEX_STATE_INITIAL declared > > but not used, at least pipex_lookup_by_session_id() should be > > refactored before. > > > > Is this direction more acceptable? > > Diff below illustrates this. > > 1. New function pipex_init_session() validates request and if it's > accepted creates new pipex session but keeps it unlinked. This session > is only inserted to `session_list'. Unlinked session can't be accessed > by stack. > 2. New function pipex_link_session() connects session to stack. > 3. New function pipex_unlink_session() disconnects session from the > stack. > > Duplicated pipex(4) code from pppx_add_session was replaced by > pipex_init_session() and pipex_link_session(). pppx(4) related code is > not reordered. > > Duplicated pipex(4) code from pppx_if_destroy() was replaced by > pipex_unlink_session().
Awesome! Comments below. > 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 8 Jun 2020 12:07:09 -0000 > @@ -659,14 +659,10 @@ pppx_add_session(struct pppx_dev *pxd, s > { > struct pppx_if *pxi; > struct pipex_session *session; > - struct pipex_hash_head *chain; > struct ifnet *ifp; > int unit, error = 0; > struct in_ifaddr *ia; > struct sockaddr_in ifaddr; > -#ifdef PIPEX_PPPOE > - struct ifnet *over_ifp = NULL; > -#endif > > /* > * XXX: As long as `session' is allocated as part of a `pxi' > @@ -676,151 +672,20 @@ pppx_add_session(struct pppx_dev *pxd, s > if (req->pr_timeout_sec != 0) > return (EINVAL); > > - 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); > - break; > -#endif > -#if defined(PIPEX_PPTP) || defined(PIPEX_L2TP) > - case PIPEX_PROTO_PPTP: > - 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); > - break; > -#ifdef INET6 > - case AF_INET6: > - if (req->pr_peer_address.ss_len != sizeof(struct > sockaddr_in6)) > - return (EINVAL); > - break; > -#endif > - default: > - return (EPROTONOSUPPORT); > - } > - 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); > - break; > -#endif /* defined(PIPEX_PPTP) || defined(PIPEX_L2TP) */ > - default: > - return (EPROTONOSUPPORT); > - } > - > - 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); > > 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; > - session->peer_session_id = req->pr_peer_session_id; > - session->peer_mru = req->pr_peer_mru; > - session->timeout_sec = req->pr_timeout_sec; > - session->ppp_flags = req->pr_ppp_flags; > - session->ppp_id = req->pr_ppp_id; > - > - session->ip_forward = 1; > - > - session->ip_address.sin_family = AF_INET; > - session->ip_address.sin_len = sizeof(struct sockaddr_in); > - session->ip_address.sin_addr = req->pr_ip_address; > - > - session->ip_netmask.sin_family = AF_INET; > - session->ip_netmask.sin_len = sizeof(struct sockaddr_in); > - session->ip_netmask.sin_addr = req->pr_ip_netmask; > - > - if (session->ip_netmask.sin_addr.s_addr == 0L) > - session->ip_netmask.sin_addr.s_addr = 0xffffffffL; > - session->ip_address.sin_addr.s_addr &= > - session->ip_netmask.sin_addr.s_addr; > - > - if (req->pr_peer_address.ss_len > 0) > - memcpy(&session->peer, &req->pr_peer_address, > - MIN(req->pr_peer_address.ss_len, sizeof(session->peer))); > - if (req->pr_local_address.ss_len > 0) > - memcpy(&session->local, &req->pr_local_address, > - MIN(req->pr_local_address.ss_len, sizeof(session->local))); > -#ifdef PIPEX_PPPOE > - if (req->pr_protocol == PIPEX_PROTO_PPPOE) > - session->proto.pppoe.over_ifidx = over_ifp->if_index; > -#endif > -#ifdef PIPEX_PPTP > - if (req->pr_protocol == PIPEX_PROTO_PPTP) { > - struct pipex_pptp_session *sess_pptp = &session->proto.pptp; > - > - sess_pptp->snd_gap = 0; > - sess_pptp->rcv_gap = 0; > - sess_pptp->snd_una = req->pr_proto.pptp.snd_una; > - sess_pptp->snd_nxt = req->pr_proto.pptp.snd_nxt; > - sess_pptp->rcv_nxt = req->pr_proto.pptp.rcv_nxt; > - sess_pptp->rcv_acked = req->pr_proto.pptp.rcv_acked; > - > - sess_pptp->winsz = req->pr_proto.pptp.winsz; > - sess_pptp->maxwinsz = req->pr_proto.pptp.maxwinsz; > - sess_pptp->peer_maxwinsz = req->pr_proto.pptp.peer_maxwinsz; > - /* last ack number */ > - sess_pptp->ul_snd_una = sess_pptp->snd_una - 1; > - } > -#endif > -#ifdef PIPEX_L2TP > - if (req->pr_protocol == PIPEX_PROTO_L2TP) { > - struct pipex_l2tp_session *sess_l2tp = &session->proto.l2tp; > - > - /* session keys */ > - sess_l2tp->tunnel_id = req->pr_proto.l2tp.tunnel_id; > - sess_l2tp->peer_tunnel_id = req->pr_proto.l2tp.peer_tunnel_id; > - > - /* protocol options */ > - sess_l2tp->option_flags = req->pr_proto.l2tp.option_flags; > - > - /* initial state of dynamic context */ > - sess_l2tp->ns_gap = sess_l2tp->nr_gap = 0; > - sess_l2tp->ns_nxt = req->pr_proto.l2tp.ns_nxt; > - sess_l2tp->nr_nxt = req->pr_proto.l2tp.nr_nxt; > - sess_l2tp->ns_una = req->pr_proto.l2tp.ns_una; > - sess_l2tp->nr_acked = req->pr_proto.l2tp.nr_acked; > - /* last ack number */ > - sess_l2tp->ul_ns_una = sess_l2tp->ns_una - 1; > - } > -#endif > -#ifdef PIPEX_MPPE > - if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED) != 0) > - pipex_session_init_mppe_recv(session, > - req->pr_mppe_recv.stateless, req->pr_mppe_recv.keylenbits, > - req->pr_mppe_recv.master_key); > - if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED) != 0) > - pipex_session_init_mppe_send(session, > - req->pr_mppe_send.stateless, req->pr_mppe_send.keylenbits, > - req->pr_mppe_send.master_key); > - > - 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); > - } > + pxi->pxi_ifcontext.ifnet_this = ifp; > + pxi->pxi_ifcontext.pipexmode = PIPEX_ENABLED; > + > + error = pipex_init_session(session, req, &pxi->pxi_ifcontext); Can you make pipex_init_session() not require an `iface' argument? This way you don't need to do a pool_get/put(9) in case of error. > + if (error) { > + pool_put(pppx_if_pl, pxi); > + goto out; > } > -#endif > > /* try to set the interface up */ > unit = pppx_if_next_unit(); > @@ -837,6 +702,7 @@ pppx_add_session(struct pppx_dev *pxd, s > > /* this is safe without splnet since we're not modifying it */ > if (RBT_FIND(pppx_ifs, &pppx_ifs, pxi) != NULL) { > + pipex_unlink_session(session); > pool_put(pppx_if_pl, pxi); > error = EADDRINUSE; > goto out; > @@ -858,24 +724,7 @@ pppx_add_session(struct pppx_dev *pxd, s > 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); > - LIST_INSERT_HEAD(&pipex_session_list, session, session_list); > -#if defined(PIPEX_PPTP) || defined(PIPEX_L2TP) > - switch (req->pr_protocol) { > - case PIPEX_PROTO_PPTP: > - case PIPEX_PROTO_L2TP: > - chain = PIPEX_PEER_ADDR_HASHTABLE( > - pipex_sockaddr_hash_key(&session->peer.sa)); > - LIST_INSERT_HEAD(chain, session, peer_addr_chain); > - break; > - } > -#endif > - > - /* if first session is added, start timer */ > - if (LIST_NEXT(session, session_list) == NULL) > - pipex_timer_start(); > + pipex_link_session(session); > > /* XXXSMP breaks atomicity */ > NET_UNLOCK(); > @@ -1008,20 +857,7 @@ pppx_if_destroy(struct pppx_dev *pxd, st > session = &pxi->pxi_session; > ifp = &pxi->pxi_if; > > - LIST_REMOVE(session, id_chain); > - LIST_REMOVE(session, session_list); > -#if defined(PIPEX_PPTP) || defined(PIPEX_L2TP) > - switch (session->protocol) { > - case PIPEX_PROTO_PPTP: > - case PIPEX_PROTO_L2TP: > - LIST_REMOVE(session, peer_addr_chain); > - break; > - } > -#endif > - > - /* if final session is destroyed, stop timer */ > - if (LIST_EMPTY(&pipex_session_list)) > - pipex_timer_stop(); > + pipex_unlink_session(session); > > /* XXXSMP breaks atomicity */ > NET_UNLOCK(); > Index: sys/net/pipex.c > =================================================================== > RCS file: /cvs/src/sys/net/pipex.c,v > retrieving revision 1.114 > diff -u -p -r1.114 pipex.c > --- sys/net/pipex.c 31 May 2020 03:14:59 -0000 1.114 > +++ sys/net/pipex.c 8 Jun 2020 12:07:09 -0000 > @@ -258,13 +258,11 @@ pipex_ioctl(struct pipex_iface_context * > /************************************************************************ > * Session management functions > ************************************************************************/ > -Static int > -pipex_add_session(struct pipex_session_req *req, > - struct pipex_iface_context *iface) > +int > +pipex_init_session(struct pipex_session *session, > + struct pipex_session_req *req, struct pipex_iface_context *iface) > { > - struct pipex_session *session; > - struct pipex_hash_head *chain; > - struct radix_node *rn; > + struct pipex_session *session_tmp; > #ifdef PIPEX_PPPOE > struct ifnet *over_ifp = NULL; > #endif > @@ -312,14 +310,14 @@ pipex_add_session(struct pipex_session_r > return (EPROTONOSUPPORT); > } > > - session = pipex_lookup_by_session_id(req->pr_protocol, > - req->pr_session_id); > - if (session) > - return (EEXIST); > + LIST_FOREACH(session_tmp, &pipex_session_list, session_list) { > + if (session_tmp->protocol == req->pr_protocol && > + session_tmp->session_id == req->pr_session_id) > + return (EEXIST); > + } Why can't we keep pipex_lookup_by_session_id() here? > > /* prepare a new session */ > - session = pool_get(&pipex_session_pool, PR_WAITOK | PR_ZERO); > - session->state = PIPEX_STATE_OPENED; > + session->state = PIPEX_STATE_INITIAL; > session->protocol = req->pr_protocol; > session->session_id = req->pr_session_id; > session->peer_session_id = req->pr_peer_session_id; > @@ -396,19 +394,15 @@ pipex_add_session(struct pipex_session_r > #endif > #ifdef PIPEX_MPPE > if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED) != 0) { > - if (req->pr_mppe_recv.keylenbits <= 0) { > - pool_put(&pipex_session_pool, session); > + if (req->pr_mppe_recv.keylenbits <= 0) > return (EINVAL); > - } > pipex_session_init_mppe_recv(session, > req->pr_mppe_recv.stateless, req->pr_mppe_recv.keylenbits, > req->pr_mppe_recv.master_key); > } > if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED) != 0) { > - if (req->pr_mppe_send.keylenbits <= 0) { > - pool_put(&pipex_session_pool, session); > + if (req->pr_mppe_send.keylenbits <= 0) > return (EINVAL); > - } > pipex_session_init_mppe_send(session, > req->pr_mppe_send.stateless, req->pr_mppe_send.keylenbits, > req->pr_mppe_send.master_key); > @@ -416,56 +410,112 @@ pipex_add_session(struct pipex_session_r > > if (pipex_session_is_mppe_required(session)) { > if (!pipex_session_is_mppe_enabled(session) || > - !pipex_session_is_mppe_accepted(session)) { > - pool_put(&pipex_session_pool, session); > + !pipex_session_is_mppe_accepted(session)) > return (EINVAL); > - } > } > #endif > > - NET_ASSERT_LOCKED(); > + LIST_INSERT_HEAD(&pipex_session_list, session, session_list); > + > + /* if first session is added, start timer */ > + if (LIST_NEXT(session, session_list) == NULL) > + pipex_timer_start(); Adding `session' to the list and starting the timer should be in link_session(), no? Their counterpart operation are done in unlink_session(). > + > + return 0; > +} > + > +void > +pipex_link_session(struct pipex_session *session) > +{ > + struct pipex_hash_head *chain; > + > + chain = PIPEX_ID_HASHTABLE(session->session_id); > + LIST_INSERT_HEAD(chain, session, id_chain); > +#if defined(PIPEX_PPTP) || defined(PIPEX_L2TP) > + switch (session->protocol) { > + case PIPEX_PROTO_PPTP: > + case PIPEX_PROTO_L2TP: > + chain = PIPEX_PEER_ADDR_HASHTABLE( > + pipex_sockaddr_hash_key(&session->peer.sa)); > + LIST_INSERT_HEAD(chain, session, peer_addr_chain); > + } > +#endif > + > + session->state = PIPEX_STATE_OPENED; > +} > + > +void > +pipex_unlink_session(struct pipex_session *session) > +{ > + if (session->state != PIPEX_STATE_INITIAL) { > + LIST_REMOVE(session, id_chain); > +#if defined(PIPEX_PPTP) || defined(PIPEX_L2TP) > + switch (session->protocol) { > + case PIPEX_PROTO_PPTP: > + case PIPEX_PROTO_L2TP: > + LIST_REMOVE(session, peer_addr_chain); > + break; > + } > +#endif > + } > + > + LIST_REMOVE(session, session_list); > + > + /* if final session is destroyed, stop timer */ > + if (LIST_EMPTY(&pipex_session_list)) > + pipex_timer_stop(); > + > + if (session->mppe_recv.old_session_keys) > + pool_put(&mppe_key_pool, session->mppe_recv.old_session_keys); > +} > + > +Static int > +pipex_add_session(struct pipex_session_req *req, > + struct pipex_iface_context *iface) > +{ > + struct pipex_session *session; > + struct radix_node *rn; > + int error; > + > + session = pool_get(&pipex_session_pool, PR_WAITOK | PR_ZERO); > + error = pipex_init_session(session, req, iface); > + if (error) > + goto out; > + > /* commit the session */ > if (!in_nullhost(session->ip_address.sin_addr)) { > if (pipex_lookup_by_ip_address(session->ip_address.sin_addr) > != NULL) { > - pool_put(&pipex_session_pool, session); > - return (EADDRINUSE); > + error = EADDRINUSE; > + goto unlink; > } > > rn = rn_addroute(&session->ip_address, &session->ip_netmask, > pipex_rd_head4, session->ps4_rn, RTP_STATIC); > if (rn == NULL) { > - pool_put(&pipex_session_pool, session); > - return (ENOMEM); > + error = ENOMEM; > + goto unlink; > } > } > if (0) { /* NOT YET */ > rn = rn_addroute(&session->ip6_address, &session->ip6_prefixlen, > pipex_rd_head6, session->ps6_rn, RTP_STATIC); > if (rn == NULL) { > - pool_put(&pipex_session_pool, session); > - return (ENOMEM); > + error = ENOMEM; > + goto unlink; > } > } > > - chain = PIPEX_ID_HASHTABLE(session->session_id); > - LIST_INSERT_HEAD(chain, session, id_chain); > - LIST_INSERT_HEAD(&pipex_session_list, session, session_list); > -#if defined(PIPEX_PPTP) || defined(PIPEX_L2TP) > - switch (req->pr_protocol) { > - case PIPEX_PROTO_PPTP: > - case PIPEX_PROTO_L2TP: > - chain = PIPEX_PEER_ADDR_HASHTABLE( > - pipex_sockaddr_hash_key(&session->peer.sa)); > - LIST_INSERT_HEAD(chain, session, peer_addr_chain); > - } > -#endif > + pipex_link_session(session); > + pipex_session_log(session, LOG_INFO, "PIPEX is ready."); > > - /* if first session is added, start timer */ > - if (LIST_NEXT(session, session_list) == NULL) > - pipex_timer_start(); > + return 0; > > - pipex_session_log(session, LOG_INFO, "PIPEX is ready."); > +unlink: > + pipex_unlink_session(session); > +out: > + pool_put(&pipex_session_pool, session); > + return error; > > return (0); > } > @@ -593,23 +643,7 @@ pipex_destroy_session(struct pipex_sessi > KASSERT(rn != NULL); > } > > - LIST_REMOVE(session, id_chain); > - LIST_REMOVE(session, session_list); > -#if defined(PIPEX_PPTP) || defined(PIPEX_L2TP) > - switch (session->protocol) { > - case PIPEX_PROTO_PPTP: > - case PIPEX_PROTO_L2TP: > - LIST_REMOVE(session, peer_addr_chain); > - break; > - } > -#endif > - > - /* if final session is destroyed, stop timer */ > - if (LIST_EMPTY(&pipex_session_list)) > - pipex_timer_stop(); > - > - if (session->mppe_recv.old_session_keys) > - pool_put(&mppe_key_pool, session->mppe_recv.old_session_keys); > + pipex_unlink_session(session); > pool_put(&pipex_session_pool, session); > > return (0); > Index: sys/net/pipex_local.h > =================================================================== > RCS file: /cvs/src/sys/net/pipex_local.h,v > retrieving revision 1.34 > diff -u -p -r1.34 pipex_local.h > --- sys/net/pipex_local.h 26 May 2020 07:06:37 -0000 1.34 > +++ sys/net/pipex_local.h 8 Jun 2020 12:07:09 -0000 > @@ -376,6 +376,11 @@ extern struct pipex_hash_head pipex_id_h > > void pipex_iface_start (struct pipex_iface_context *); > void pipex_iface_stop (struct pipex_iface_context *); > +int pipex_init_session(struct pipex_session *, > + struct pipex_session_req *, > + struct pipex_iface_context *); > +void pipex_link_session(struct pipex_session *); > +void pipex_unlink_session(struct pipex_session *); > int pipex_add_session (struct pipex_session_req *, struct > pipex_iface_context *); > int pipex_close_session (struct pipex_session_close_req *, > struct pipex_iface_context *);