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