-/* $OpenBSD: if_pppx.c,v 1.123 2022/11/19 15:12:38 mvs Exp $ */
+/* $OpenBSD: if_pppx.c,v 1.124 2022/11/26 17:50:26 mvs Exp $ */
/*
* Copyright (c) 2010 Claudio Jeker <claudio@openbsd.org>
#include <sys/ioctl.h>
#include <sys/vnode.h>
#include <sys/selinfo.h>
+#include <sys/refcnt.h>
#include <net/if.h>
#include <net/if_types.h>
/* queue of packets for userland to service - protected by splnet */
struct mbuf_queue pxd_svcq;
int pxd_waiting; /* [N] */
- LIST_HEAD(,pppx_if) pxd_pxis; /* [N] */
+ LIST_HEAD(,pppx_if) pxd_pxis; /* [K] */
};
LIST_HEAD(, pppx_dev) pppx_devs =
struct pppx_if {
struct pppx_if_key pxi_key; /* [I] must be first
in the struct */
+ struct refcnt pxi_refcnt;
- RBT_ENTRY(pppx_if) pxi_entry; /* [N] */
- LIST_ENTRY(pppx_if) pxi_list; /* [N] */
+ RBT_ENTRY(pppx_if) pxi_entry; /* [K] */
+ LIST_ENTRY(pppx_if) pxi_list; /* [K] */
- int pxi_ready; /* [N] */
+ int pxi_ready; /* [K] */
int pxi_unit; /* [I] */
struct ifnet pxi_if;
RBT_PROTOTYPE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);
int pppx_if_next_unit(void);
-struct pppx_if *pppx_if_find(struct pppx_dev *, int, int);
+struct pppx_if *pppx_if_find_locked(struct pppx_dev *, int, int);
+static inline struct pppx_if *pppx_if_find(struct pppx_dev *, int, int);
+static inline void pppx_if_rele(struct pppx_if *);
int pppx_add_session(struct pppx_dev *,
struct pipex_session_req *);
int pppx_del_session(struct pppx_dev *,
th = mtod(top, struct pppx_hdr *);
m_adj(top, sizeof(struct pppx_hdr));
- NET_LOCK();
-
pxi = pppx_if_find(pxd, th->pppx_id, th->pppx_proto);
if (pxi == NULL) {
- NET_UNLOCK();
m_freem(top);
return (EINVAL);
}
proto = ntohl(*(uint32_t *)(th + 1));
m_adj(top, sizeof(uint32_t));
+ NET_LOCK();
+
switch (proto) {
case AF_INET:
ipv4_input(&pxi->pxi_if, top);
NET_UNLOCK();
+ pppx_if_rele(pxi);
+
return (error);
}
break;
case PIPEXDSESSION:
- NET_LOCK();
error = pppx_del_session(pxd,
(struct pipex_session_close_req *)addr);
- NET_UNLOCK();
break;
case PIPEXSIFDESCR:
- NET_LOCK();
error = pppx_set_session_descr(pxd,
(struct pipex_session_descr_req *)addr);
- NET_UNLOCK();
break;
case FIONBIO:
pxd = pppx_dev_lookup(dev);
- /* XXX */
- NET_LOCK();
- while ((pxi = LIST_FIRST(&pxd->pxd_pxis)))
+ while ((pxi = LIST_FIRST(&pxd->pxd_pxis))) {
+ pxi->pxi_ready = 0;
pppx_if_destroy(pxd, pxi);
- NET_UNLOCK();
+ }
LIST_REMOVE(pxd, pxd_entry);
}
struct pppx_if *
-pppx_if_find(struct pppx_dev *pxd, int session_id, int protocol)
+pppx_if_find_locked(struct pppx_dev *pxd, int session_id, int protocol)
{
struct pppx_if_key key;
struct pppx_if *pxi;
return pxi;
}
+static inline struct pppx_if *
+pppx_if_find(struct pppx_dev *pxd, int session_id, int protocol)
+{
+ struct pppx_if *pxi;
+
+ if ((pxi = pppx_if_find_locked(pxd, session_id, protocol)))
+ refcnt_take(&pxi->pxi_refcnt);
+
+ return pxi;
+}
+
+static inline void
+pppx_if_rele(struct pppx_if *pxi)
+{
+ refcnt_rele_wake(&pxi->pxi_refcnt);
+}
+
int
pppx_add_session(struct pppx_dev *pxd, struct pipex_session_req *req)
{
pxi->pxi_session = session;
- NET_LOCK();
/* try to set the interface up */
unit = pppx_if_next_unit();
if (unit < 0) {
goto out;
}
+ refcnt_init(&pxi->pxi_refcnt);
pxi->pxi_unit = unit;
pxi->pxi_key.pxik_session_id = req->pr_session_id;
pxi->pxi_key.pxik_protocol = req->pr_protocol;
goto out;
}
LIST_INSERT_HEAD(&pxd->pxd_pxis, pxi, pxi_list);
- NET_UNLOCK();
snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", "pppx", unit);
ifp->if_mtu = req->pr_peer_mru; /* XXX */
NET_LOCK();
SET(ifp->if_flags, IFF_RUNNING);
- pxi->pxi_ready = 1;
NET_UNLOCK();
+ pxi->pxi_ready = 1;
return (error);
detach:
if_detach(ifp);
- NET_LOCK();
if (RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)
panic("%s: inconsistent RB tree", __func__);
LIST_REMOVE(pxi, pxi_list);
out:
- NET_UNLOCK();
-
pool_put(&pppx_if_pl, pxi);
pipex_rele_session(session);
{
struct pppx_if *pxi;
- pxi = pppx_if_find(pxd, req->pcr_session_id, req->pcr_protocol);
+ pxi = pppx_if_find_locked(pxd, req->pcr_session_id, req->pcr_protocol);
if (pxi == NULL)
return (EINVAL);
+ pxi->pxi_ready = 0;
pipex_export_session_stats(pxi->pxi_session, &req->pcr_stat);
pppx_if_destroy(pxd, pxi);
return (0);
if (pxi == NULL)
return (EINVAL);
+ NET_LOCK();
(void)memset(pxi->pxi_if.if_description, 0, IFDESCRSIZE);
strlcpy(pxi->pxi_if.if_description, req->pdr_descr, IFDESCRSIZE);
+ NET_UNLOCK();
+
+ pppx_if_rele(pxi);
return (0);
}
struct ifnet *ifp;
struct pipex_session *session;
- NET_ASSERT_LOCKED();
session = pxi->pxi_session;
ifp = &pxi->pxi_if;
- pxi->pxi_ready = 0;
- CLR(ifp->if_flags, IFF_RUNNING);
- pipex_unlink_session(session);
+ refcnt_finalize(&pxi->pxi_refcnt, "pxifinal");
- /* XXXSMP breaks atomicity */
+ NET_LOCK();
+ CLR(ifp->if_flags, IFF_RUNNING);
NET_UNLOCK();
+
+ pipex_unlink_session(session);
if_detach(ifp);
- NET_LOCK();
pipex_rele_session(session);
if (RBT_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)