On Mon, Jun 08, 2020 at 12:49:05PM +0300, Vitaliy Makkoveev wrote:
>
>
> > On 8 Jun 2020, at 11:34, Martin Pieuchot <[email protected]> wrote:
> >
> > 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.
>
> Except "req->pr_timeout_sec !=0” checking all userland input checks
> were copypasted prom pipex_add_session(). But pppx_add_session()
> inserts pppx(4) related code between checks and session initialization.
> So I decided to keep all pipex(4) related code together for further
> deduplication. Also we want to initialise `ifnet’ before session
> linking.
>
> 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().
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);
+ 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);
+ }
/* 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();
+
+ 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 *);