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