Well, since pipexintr() killing was rejected, I propose to implement
reference counters to protect pipex(4) session itself. Diff below does
this.

Index: sys/net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.266
diff -u -p -r1.266 if_ethersubr.c
--- sys/net/if_ethersubr.c      22 Jul 2020 02:16:01 -0000      1.266
+++ sys/net/if_ethersubr.c      31 Jul 2020 13:56:31 -0000
@@ -527,6 +527,7 @@ ether_input(struct ifnet *ifp, struct mb
 
                        if ((session = pipex_pppoe_lookup_session(m)) != NULL) {
                                pipex_pppoe_input(m, session);
+                               pipex_rele_session(session);
                                return;
                        }
                }
Index: sys/net/if_gre.c
===================================================================
RCS file: /cvs/src/sys/net/if_gre.c,v
retrieving revision 1.158
diff -u -p -r1.158 if_gre.c
--- sys/net/if_gre.c    10 Jul 2020 13:26:41 -0000      1.158
+++ sys/net/if_gre.c    31 Jul 2020 13:56:31 -0000
@@ -984,9 +984,15 @@ gre_input_1(struct gre_tunnel *key, stru
                        struct pipex_session *session;
 
                        session = pipex_pptp_lookup_session(m);
-                       if (session != NULL &&
-                           pipex_pptp_input(m, session) == NULL)
-                               return (NULL);
+                       if (session != NULL) {
+                               struct mbuf *m0;
+
+                               m0 = pipex_pptp_input(m, session);
+                               pipex_rele_session(session);
+
+                               if (m0 == NULL)
+                                       return NULL;
+                       }
                }
 #endif
                break;
Index: sys/net/pipex.c
===================================================================
RCS file: /cvs/src/sys/net/pipex.c,v
retrieving revision 1.122
diff -u -p -r1.122 pipex.c
--- sys/net/pipex.c     29 Jul 2020 12:09:31 -0000      1.122
+++ sys/net/pipex.c     31 Jul 2020 13:56:32 -0000
@@ -165,6 +165,7 @@ pipex_iface_init(struct pipex_iface_cont
 
        /* virtual pipex_session entry for multicast */
        session = pool_get(&pipex_session_pool, PR_WAITOK | PR_ZERO);
+       session->refs = 1;
        session->is_multicast = 1;
        session->pipex_iface = pipex_iface;
        session->ifindex = ifindex;
@@ -197,9 +198,9 @@ pipex_iface_stop(struct pipex_iface_cont
 void
 pipex_iface_fini(struct pipex_iface_context *pipex_iface)
 {
-       pool_put(&pipex_session_pool, pipex_iface->multicast_session);
        NET_LOCK();
        pipex_iface_stop(pipex_iface);
+       pipex_rele_session(pipex_iface->multicast_session);
        NET_UNLOCK();
 }
 
@@ -329,6 +330,7 @@ pipex_init_session(struct pipex_session 
 
        /* prepare a new session */
        session = pool_get(&pipex_session_pool, PR_WAITOK | PR_ZERO);
+       session->refs = 1;
        session->state = PIPEX_STATE_INITIAL;
        session->protocol = req->pr_protocol;
        session->session_id = req->pr_session_id;
@@ -421,9 +423,20 @@ pipex_init_session(struct pipex_session 
        return 0;
 }
 
+void pipex_ref_session(struct pipex_session *session)
+{
+       atomic_inc_int_nv(&session->refs);
+       KASSERT(session->refs != 0);
+}
+
 void
 pipex_rele_session(struct pipex_session *session)
 {
+       KASSERT(session->refs > 0);
+
+       if (atomic_dec_int_nv(&session->refs) > 0)
+               return;
+
        if (session->mppe_recv.old_session_keys)
                pool_put(&mppe_key_pool, session->mppe_recv.old_session_keys);
        pool_put(&pipex_session_pool, session);
@@ -439,10 +452,12 @@ pipex_link_session(struct pipex_session 
 
        if (!iface->pipexmode)
                return (ENXIO);
-       if (pipex_lookup_by_session_id(session->protocol,
+       if (pipex_lookup_by_session_id_nonref(session->protocol,
            session->session_id))
                return (EEXIST);
 
+       pipex_ref_session(session);
+
        session->pipex_iface = iface;
        session->ifindex = iface->ifindex;
 
@@ -490,6 +505,8 @@ pipex_unlink_session(struct pipex_sessio
        /* if final session is destroyed, stop timer */
        if (LIST_EMPTY(&pipex_session_list))
                pipex_timer_stop();
+
+       pipex_rele_session(session);
 }
 
 Static int
@@ -505,8 +522,8 @@ pipex_add_session(struct pipex_session_r
 
        /* commit the session */
        if (!in_nullhost(session->ip_address.sin_addr)) {
-               if (pipex_lookup_by_ip_address(session->ip_address.sin_addr)
-                   != NULL) {
+               if (pipex_lookup_by_ip_address_nonref(
+                   session->ip_address.sin_addr) != NULL) {
                        error = EADDRINUSE;
                        goto free;
                }
@@ -568,6 +585,7 @@ pipex_close_session(struct pipex_session
     struct pipex_iface_context *iface)
 {
        struct pipex_session *session;
+       int error = 0;
 
        NET_ASSERT_LOCKED();
        session = pipex_lookup_by_session_id(req->pcr_protocol,
@@ -575,17 +593,20 @@ pipex_close_session(struct pipex_session
        if (session == NULL)
                return (EINVAL);
        if (session->pipex_iface != iface)
-               return (EINVAL);
-
-       /* remove from close_wait list */
-       if (session->state == PIPEX_STATE_CLOSE_WAIT)
-               LIST_REMOVE(session, state_list);
+               error = EINVAL;
+       else {
+               /* remove from close_wait list */
+               if (session->state == PIPEX_STATE_CLOSE_WAIT)
+                       LIST_REMOVE(session, state_list);
+
+               /* get statistics before destroy the session */
+               req->pcr_stat = session->stat;
+               session->state = PIPEX_STATE_CLOSED;
+       }
 
-       /* get statistics before destroy the session */
-       req->pcr_stat = session->stat;
-       session->state = PIPEX_STATE_CLOSED;
+       pipex_rele_session(session);
 
-       return (0);
+       return (error);
 }
 
 Static int
@@ -593,6 +614,7 @@ pipex_config_session(struct pipex_sessio
     struct pipex_iface_context *iface)
 {
        struct pipex_session *session;
+       int error = 0;
 
        NET_ASSERT_LOCKED();
        session = pipex_lookup_by_session_id(req->pcr_protocol,
@@ -600,10 +622,13 @@ pipex_config_session(struct pipex_sessio
        if (session == NULL)
                return (EINVAL);
        if (session->pipex_iface != iface)
-               return (EINVAL);
-       session->ip_forward = req->pcr_ip_forward;
+               error = EINVAL;
+       else
+               session->ip_forward = req->pcr_ip_forward;
 
-       return (0);
+       pipex_rele_session(session);
+
+       return (error);
 }
 
 Static int
@@ -611,6 +636,7 @@ pipex_get_stat(struct pipex_session_stat
     struct pipex_iface_context *iface)
 {
        struct pipex_session *session;
+       int error = 0;
 
        NET_ASSERT_LOCKED();
        session = pipex_lookup_by_session_id(req->psr_protocol,
@@ -618,10 +644,13 @@ pipex_get_stat(struct pipex_session_stat
        if (session == NULL)
                return (EINVAL);
        if (session->pipex_iface != iface)
-               return (EINVAL);
-       req->psr_stat = session->stat;
+               error = EINVAL;
+       else
+               req->psr_stat = session->stat;
 
-       return (0);
+       pipex_rele_session(session);
+
+       return (error);
 }
 
 Static int
@@ -670,7 +699,7 @@ pipex_destroy_session(struct pipex_sessi
 }
 
 Static struct pipex_session *
-pipex_lookup_by_ip_address(struct in_addr addr)
+pipex_lookup_by_ip_address_nonref(struct in_addr addr)
 {
        struct pipex_session *session;
        struct sockaddr_in pipex_in4, pipex_in4mask;
@@ -700,8 +729,20 @@ pipex_lookup_by_ip_address(struct in_add
        return (session);
 }
 
+struct pipex_session *
+pipex_lookup_by_ip_address(struct in_addr addr)
+{
+       struct pipex_session *session;
+
+       session = pipex_lookup_by_ip_address_nonref(addr);
+       if (session != NULL)
+               pipex_ref_session(session);
+
+       return (session);
+}
+
 Static struct pipex_session *
-pipex_lookup_by_session_id(int protocol, int session_id)
+pipex_lookup_by_session_id_nonref(int protocol, int session_id)
 {
        struct pipex_hash_head *list;
        struct pipex_session *session;
@@ -724,6 +765,18 @@ pipex_lookup_by_session_id(int protocol,
        return (session);
 }
 
+struct pipex_session *
+pipex_lookup_by_session_id(int protocol, int session_id)
+{
+       struct pipex_session *session;
+
+       session = pipex_lookup_by_session_id_nonref(protocol, session_id);
+       if (session != NULL)
+               pipex_ref_session(session);
+
+       return (session);
+}
+
 /***********************************************************************
  * Queue and Software Interrupt Handler
  ***********************************************************************/
@@ -743,6 +796,7 @@ pipexintr(void)
                        m_freem(m);
                        continue;
                }
+
                proto = m->m_pkthdr.ph_ppp_proto;
 
                m->m_pkthdr.ph_cookie = NULL;
@@ -752,6 +806,12 @@ pipexintr(void)
                        struct pipex_session *session;
                        struct mbuf *m0;
 
+                       if (pkt_session->state != PIPEX_STATE_OPENED) {
+                               m_freem(m);
+                               pipex_rele_session(pkt_session);
+                               continue;
+                       }
+
                        LIST_FOREACH(session, &pipex_session_list,
                            session_list) {
                                if (session->pipex_iface !=
@@ -770,6 +830,8 @@ pipexintr(void)
                        m_freem(m);
                } else
                        pipex_ppp_output(m, pkt_session, proto);
+
+               pipex_rele_session(pkt_session);
        }
 
        /* ppp input */
@@ -780,7 +842,9 @@ pipexintr(void)
                        m_freem(m);
                        continue;
                }
+
                pipex_ppp_input(m, pkt_session, 0);
+               pipex_rele_session(pkt_session);
        }
 }
 
@@ -788,6 +852,7 @@ Static int
 pipex_ppp_enqueue(struct mbuf *m0, struct pipex_session *session,
     struct mbuf_queue *mq)
 {
+       pipex_ref_session(session);
        m0->m_pkthdr.ph_cookie = session;
        /* XXX need to support other protocols */
        m0->m_pkthdr.ph_ppp_proto = PPP_IP;
@@ -852,13 +917,6 @@ pipex_timer(void *ignored_arg)
                        /* FALLTHROUGH */
 
                case PIPEX_STATE_CLOSED:
-                       /*
-                        * mbuf queued in pipexinq or pipexoutq may have a
-                        * refererce to this session.
-                        */
-                       if (!mq_empty(&pipexinq) || !mq_empty(&pipexoutq))
-                               continue;
-
                        pipex_destroy_session(session);
                        break;
 
@@ -888,9 +946,10 @@ pipex_output(struct mbuf *m0, int af, in
        case AF_INET:
                if (m0->m_pkthdr.len >= sizeof(struct ip) + off) {
                        m_copydata(m0, off, sizeof(struct ip), (caddr_t)&ip);
-                       if (IN_MULTICAST(ip.ip_dst.s_addr))
+                       if (IN_MULTICAST(ip.ip_dst.s_addr)) {
                                session = pipex_iface->multicast_session;
-                       else
+                               pipex_ref_session(session);
+                       } else
                                session = pipex_lookup_by_ip_address(ip.ip_dst);
                }
                if (session != NULL) {
@@ -908,6 +967,7 @@ pipex_output(struct mbuf *m0, int af, in
                                m_adj(m0, off);
 
                        pipex_ip_output(m0, session);
+                       pipex_rele_session(session);
                        return (mret);
                }
                break;
@@ -917,8 +977,11 @@ pipex_output(struct mbuf *m0, int af, in
 
 drop:
        m_freem(m0);
-       if (session != NULL)
+       if (session != NULL) {
                session->stat.oerrors++;
+               pipex_rele_session(session);
+       }
+
        return(NULL);
 }
 
@@ -1377,8 +1440,11 @@ pipex_pppoe_lookup_session(struct mbuf *
                PIPEX_DBG((NULL, LOG_DEBUG, "<%s> session not found (id=%d)",
                    __func__, pppoe.session_id));
 #endif
-       if (session && session->proto.pppoe.over_ifidx != m0->m_pkthdr.ph_ifidx)
+       if (session && session->proto.pppoe.over_ifidx !=
+           m0->m_pkthdr.ph_ifidx) {
+               pipex_rele_session(session);
                session = NULL;
+       }
 
        return (session);
 }
@@ -1817,8 +1883,10 @@ pipex_pptp_userland_lookup_session(struc
        LIST_FOREACH(session, list, peer_addr_chain) {
                if (pipex_sockaddr_compar_addr(&session->peer.sa, sa) != 0)
                        continue;
-               if (session->peer_session_id == id)
+               if (session->peer_session_id == id) {
+                       pipex_ref_session(session);
                        break;
+               }
        }
 #ifdef PIPEX_DEBUG
        if (session == NULL) {
@@ -2250,8 +2318,10 @@ pipex_l2tp_userland_lookup_session(struc
                        continue;
                if (session->proto.l2tp.peer_tunnel_id != tunnel_id)
                        continue;
-               if (session->peer_session_id == session_id)
+               if (session->peer_session_id == session_id) {
+                       pipex_ref_session(session);
                        break;
+               }
        }
 #ifdef PIPEX_DEBUG
        if (session == NULL) {
Index: sys/net/pipex.h
===================================================================
RCS file: /cvs/src/sys/net/pipex.h,v
retrieving revision 1.26
diff -u -p -r1.26 pipex.h
--- sys/net/pipex.h     29 Jul 2020 12:09:31 -0000      1.26
+++ sys/net/pipex.h     31 Jul 2020 13:56:32 -0000
@@ -201,6 +201,7 @@ void                  pipex_init (void);
 void                  pipex_iface_init (struct pipex_iface_context *, u_int);
 void                  pipex_iface_fini (struct pipex_iface_context *);
 
+void                  pipex_rele_session(struct pipex_session *);
 int                   pipex_notify_close_session(struct pipex_session 
*session);
 int                   pipex_notify_close_session_all(void);
 
Index: sys/net/pipex_local.h
===================================================================
RCS file: /cvs/src/sys/net/pipex_local.h,v
retrieving revision 1.38
diff -u -p -r1.38 pipex_local.h
--- sys/net/pipex_local.h       29 Jul 2020 12:09:31 -0000      1.38
+++ sys/net/pipex_local.h       31 Jul 2020 13:56:32 -0000
@@ -159,6 +159,8 @@ struct pipex_session {
        LIST_ENTRY(pipex_session) id_chain;     /* [N] id hash chain */
        LIST_ENTRY(pipex_session) peer_addr_chain;
                                        /* [N] peer's address hash chain */
+       u_int           refs;           /* reference counter for this
+                                               session */
        uint16_t        state;          /* [N] pipex session state */
 #define PIPEX_STATE_INITIAL            0x0000
 #define PIPEX_STATE_OPENED             0x0001
@@ -379,7 +381,7 @@ void                  pipex_iface_start 
 void                  pipex_iface_stop (struct pipex_iface_context *);
 int                   pipex_init_session(struct pipex_session **,
                                              struct pipex_session_req *);
-void                  pipex_rele_session(struct pipex_session *);
+void                  pipex_ref_session(struct pipex_session *);
 int                   pipex_link_session(struct pipex_session *,
                                              struct pipex_iface_context *);
 void                  pipex_unlink_session(struct pipex_session *);
@@ -393,7 +395,9 @@ int                   pipex_get_stat (st
 int                   pipex_get_closed (struct pipex_session_list_req *,
                           struct pipex_iface_context *);
 int                   pipex_destroy_session (struct pipex_session *);
+struct pipex_session  *pipex_lookup_by_ip_address_nonref (struct in_addr);
 struct pipex_session  *pipex_lookup_by_ip_address (struct in_addr);
+struct pipex_session  *pipex_lookup_by_session_id_nonref (int, int);
 struct pipex_session  *pipex_lookup_by_session_id (int, int);
 void                  pipex_ip_output (struct mbuf *, struct pipex_session *);
 void                  pipex_ppp_output (struct mbuf *, struct pipex_session *, 
int);
Index: sys/netinet/ip_gre.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_gre.c,v
retrieving revision 1.71
diff -u -p -r1.71 ip_gre.c
--- sys/netinet/ip_gre.c        7 Feb 2018 22:30:59 -0000       1.71
+++ sys/netinet/ip_gre.c        31 Jul 2020 13:56:32 -0000
@@ -81,10 +81,15 @@ gre_usrreq(struct socket *so, int req, s
                        if (in_nam2sin(nam, &sin4) == 0)
                                ina_dst = &sin4->sin_addr;
                }
-               if (ina_dst != NULL &&
-                   (session = pipex_pptp_userland_lookup_session_ipv4(m,
-                           *ina_dst)))
-                       m = pipex_pptp_userland_output(m, session);
+               if (ina_dst != NULL) {
+                       session = pipex_pptp_userland_lookup_session_ipv4(m,
+                           *ina_dst);
+
+                       if (session != NULL) {
+                               m = pipex_pptp_userland_output(m, session);
+                               pipex_rele_session(session);
+                       }
+               }
 
                if (m == NULL)
                        return (ENOMEM);
Index: sys/netinet/udp_usrreq.c
===================================================================
RCS file: /cvs/src/sys/netinet/udp_usrreq.c,v
retrieving revision 1.259
diff -u -p -r1.259 udp_usrreq.c
--- sys/netinet/udp_usrreq.c    21 Jun 2020 05:19:27 -0000      1.259
+++ sys/netinet/udp_usrreq.c    31 Jul 2020 13:56:32 -0000
@@ -565,8 +565,11 @@ udp_input(struct mbuf **mp, int *offp, i
                struct pipex_session *session;
                int off = iphlen + sizeof(struct udphdr);
                if ((session = pipex_l2tp_lookup_session(m, off)) != NULL) {
-                       if ((m = *mp = pipex_l2tp_input(m, off, session,
-                           ipsecflowinfo)) == NULL) {
+                       m = *mp = pipex_l2tp_input(m, off, session,
+                           ipsecflowinfo);
+                       pipex_rele_session(session);
+
+                       if (m == NULL) {
                                /* the packet is handled by PIPEX */
                                return IPPROTO_DONE;
                        }
@@ -1149,12 +1152,15 @@ udp_usrreq(struct socket *so, int req, s
                                session =
                                    pipex_l2tp_userland_lookup_session_ipv4(
                                        m, inp->inp_faddr);
-                       if (session != NULL)
-                               if ((m = pipex_l2tp_userland_output(
-                                   m, session)) == NULL) {
+                       if (session != NULL) {
+                               m = pipex_l2tp_userland_output(m, session);
+                               pipex_rele_session(session);
+
+                               if(m == NULL) {
                                        error = ENOMEM;
                                        goto release;
                                }
+                       }
                }
 #endif
 

Reply via email to