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