#include <sys/param.h>
#include <sys/socket.h>
#include <sys/protosw.h>
#include <sys/domain.h>
#include <sys/mcache.h>
#include <sys/mbuf.h>
#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/proc_internal.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <sys/queue.h>
#include <net/dlil.h>
#include <mach/boolean.h>
#include <pexpert/pexpert.h>
static void pr_init_old(struct protosw *, struct domain *);
static void init_proto(struct protosw *, struct domain *);
static void attach_proto(struct protosw *, struct domain *);
static void detach_proto(struct protosw *, struct domain *);
static void dom_init_old(struct domain *);
static void init_domain(struct domain *);
static void attach_domain(struct domain *);
static void detach_domain(struct domain *);
static struct protosw *pffindprotonotype_locked(int, int, int);
static struct domain *pffinddomain_locked(int);
static boolean_t domain_timeout_run;
static boolean_t domain_draining;
static void domain_sched_timeout(void);
static void domain_timeout(void *);
lck_grp_t *domain_proto_mtx_grp;
lck_attr_t *domain_proto_mtx_attr;
static lck_grp_attr_t *domain_proto_mtx_grp_attr;
decl_lck_mtx_data(static, domain_proto_mtx);
decl_lck_mtx_data(static, domain_timeout_mtx);
static u_int64_t _net_uptime;
#if (DEVELOPMENT || DEBUG)
SYSCTL_DECL(_kern_ipc);
static int sysctl_do_drain_domains SYSCTL_HANDLER_ARGS;
SYSCTL_PROC(_kern_ipc, OID_AUTO, do_drain_domains,
CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_LOCKED,
0, 0,
sysctl_do_drain_domains, "I", "force manual drain domains");
#endif
static void
pr_init_old(struct protosw *pp, struct domain *dp)
{
#pragma unused(dp)
VERIFY(pp->pr_flags & PR_OLD);
VERIFY(pp->pr_old != NULL);
if (pp->pr_old->pr_init != NULL)
pp->pr_old->pr_init();
}
static void
init_proto(struct protosw *pp, struct domain *dp)
{
VERIFY(pp->pr_flags & PR_ATTACHED);
if (!(pp->pr_flags & PR_INITIALIZED)) {
TAILQ_INIT(&pp->pr_filter_head);
if (pp->pr_init != NULL)
pp->pr_init(pp, dp);
pp->pr_flags |= PR_INITIALIZED;
}
}
static void
attach_proto(struct protosw *pp, struct domain *dp)
{
domain_proto_mtx_lock_assert_held();
VERIFY(!(pp->pr_flags & PR_ATTACHED));
VERIFY(pp->pr_domain == NULL);
VERIFY(pp->pr_protosw == NULL);
TAILQ_INSERT_TAIL(&dp->dom_protosw, pp, pr_entry);
pp->pr_flags |= PR_ATTACHED;
pp->pr_domain = dp;
pp->pr_protosw = pp;
pru_sanitize(pp->pr_usrreqs);
}
static void
detach_proto(struct protosw *pp, struct domain *dp)
{
domain_proto_mtx_lock_assert_held();
VERIFY(pp->pr_flags & PR_ATTACHED);
VERIFY(pp->pr_domain == dp);
VERIFY(pp->pr_protosw == pp);
TAILQ_REMOVE(&dp->dom_protosw, pp, pr_entry);
pp->pr_flags &= ~PR_ATTACHED;
pp->pr_domain = NULL;
pp->pr_protosw = NULL;
}
static void
dom_init_old(struct domain *dp)
{
VERIFY(dp->dom_flags & DOM_OLD);
VERIFY(dp->dom_old != NULL);
if (dp->dom_old->dom_init != NULL)
dp->dom_old->dom_init();
}
static void
init_domain(struct domain *dp)
{
VERIFY(dp->dom_flags & DOM_ATTACHED);
if (!(dp->dom_flags & DOM_INITIALIZED)) {
lck_mtx_init(&dp->dom_mtx_s, domain_proto_mtx_grp,
domain_proto_mtx_attr);
dp->dom_mtx = &dp->dom_mtx_s;
TAILQ_INIT(&dp->dom_protosw);
if (dp->dom_init != NULL)
dp->dom_init(dp);
dp->dom_flags |= DOM_INITIALIZED;
}
if (_max_linkhdr < 16)
_max_linkhdr = 16;
_max_linkhdr = max_linkhdr;
if (dp->dom_protohdrlen > _max_protohdr)
_max_protohdr = dp->dom_protohdrlen;
_max_protohdr = max_protohdr;
max_hdr = max_linkhdr + max_protohdr;
max_datalen = MHLEN - max_hdr;
}
static void
attach_domain(struct domain *dp)
{
domain_proto_mtx_lock_assert_held();
VERIFY(!(dp->dom_flags & DOM_ATTACHED));
TAILQ_INSERT_TAIL(&domains, dp, dom_entry);
dp->dom_flags |= DOM_ATTACHED;
}
static void
detach_domain(struct domain *dp)
{
domain_proto_mtx_lock_assert_held();
VERIFY(dp->dom_flags & DOM_ATTACHED);
TAILQ_REMOVE(&domains, dp, dom_entry);
dp->dom_flags &= ~DOM_ATTACHED;
if (dp->dom_flags & DOM_OLD) {
struct domain_old *odp = dp->dom_old;
VERIFY(odp != NULL);
odp->dom_next = NULL;
odp->dom_mtx = NULL;
}
}
void
net_add_domain_old(struct domain_old *odp)
{
struct domain *dp;
domain_guard_t guard;
VERIFY(odp != NULL);
guard = domain_guard_deploy();
if ((dp = pffinddomain_locked(odp->dom_family)) != NULL) {
panic("%s: domain (%d,%s) already exists for %s\n", __func__,
dp->dom_family, dp->dom_name, odp->dom_name);
}
TAILQ_FOREACH(dp, &domains, dom_entry) {
if (dp->dom_old == odp) {
panic("%s: domain %p (%d,%s) is already "
"associated with %p (%d,%s)\n", __func__,
odp, odp->dom_family, odp->dom_name, dp,
dp->dom_family, dp->dom_name);
}
}
if (odp->dom_protosw != NULL) {
panic("%s: domain (%d,%s) protocols need to added "
"via net_add_proto\n", __func__, odp->dom_family,
odp->dom_name);
}
dp = _MALLOC(sizeof (*dp), M_TEMP, M_WAITOK | M_ZERO);
if (dp == NULL) {
panic("%s: unable to allocate memory for domain family "
"%d (%s)\n", __func__, odp->dom_family, odp->dom_name);
}
dp->dom_family = odp->dom_family;
dp->dom_flags = (odp->dom_flags & DOMF_USERFLAGS) | DOM_OLD;
dp->dom_name = odp->dom_name;
dp->dom_init = dom_init_old;
dp->dom_externalize = odp->dom_externalize;
dp->dom_dispose = odp->dom_dispose;
dp->dom_rtattach = odp->dom_rtattach;
dp->dom_rtoffset = odp->dom_rtoffset;
dp->dom_maxrtkey = odp->dom_maxrtkey;
dp->dom_protohdrlen = odp->dom_protohdrlen;
dp->dom_old = odp;
attach_domain(dp);
init_domain(dp);
odp->dom_mtx = dp->dom_mtx;
domain_guard_release(guard);
}
int
net_del_domain_old(struct domain_old *odp)
{
struct domain *dp1, *dp2;
int error = 0;
domain_guard_t guard;
VERIFY(odp != NULL);
guard = domain_guard_deploy();
if (odp->dom_refs != 0) {
error = EBUSY;
goto done;
}
TAILQ_FOREACH_SAFE(dp1, &domains, dom_entry, dp2) {
if (!(dp1->dom_flags & DOM_OLD))
continue;
VERIFY(dp1->dom_old != NULL);
if (odp == dp1->dom_old)
break;
}
if (dp1 != NULL) {
struct protosw *pp1, *pp2;
VERIFY(dp1->dom_flags & DOM_OLD);
VERIFY(dp1->dom_old == odp);
TAILQ_FOREACH_SAFE(pp1, &dp1->dom_protosw, pr_entry, pp2) {
detach_proto(pp1, dp1);
if (pp1->pr_usrreqs->pru_flags & PRUF_OLD)
FREE(pp1->pr_usrreqs, M_TEMP);
if (pp1->pr_flags & PR_OLD)
FREE(pp1, M_TEMP);
}
detach_domain(dp1);
FREE(dp1, M_TEMP);
} else {
error = EPFNOSUPPORT;
}
done:
domain_guard_release(guard);
return (error);
}
int
net_add_proto(struct protosw *pp, struct domain *dp, int doinit)
{
struct protosw *pp1;
domain_proto_mtx_lock_assert_held();
VERIFY(!(pp->pr_flags & PR_ATTACHED));
if (pp->pr_domain != NULL) {
panic("%s: domain (%d,%s), proto %d has non-NULL pr_domain!\n",
__func__, dp->dom_family, dp->dom_name, pp->pr_protocol);
}
if (pp->pr_usrreqs == NULL) {
panic("%s: domain (%d,%s), proto %d has no usrreqs!\n",
__func__, dp->dom_family, dp->dom_name, pp->pr_protocol);
}
TAILQ_FOREACH(pp1, &dp->dom_protosw, pr_entry) {
if (pp1->pr_type == pp->pr_type &&
pp1->pr_protocol == pp->pr_protocol)
return (EEXIST);
}
attach_proto(pp, dp);
if (doinit)
net_init_proto(pp, dp);
return (0);
}
void
net_init_proto(struct protosw *pp, struct domain *dp)
{
domain_proto_mtx_lock_assert_held();
VERIFY(pp->pr_flags & PR_ATTACHED);
init_proto(pp, dp);
}
int
net_add_proto_old(struct protosw_old *opp, struct domain_old *odp)
{
struct pr_usrreqs_old *opru;
struct pr_usrreqs *pru = NULL;
struct protosw *pp = NULL, *pp1;
int error = 0;
struct domain *dp;
domain_guard_t guard;
guard = domain_guard_deploy();
TAILQ_FOREACH(dp, &domains, dom_entry) {
if (!(dp->dom_flags & DOM_OLD))
continue;
if (dp->dom_old == odp)
break;
}
if (dp == NULL) {
error = EINVAL;
goto done;
}
TAILQ_FOREACH(pp1, &dp->dom_protosw, pr_entry) {
if (pp1->pr_type == opp->pr_type &&
pp1->pr_protocol == opp->pr_protocol) {
error = EEXIST;
goto done;
}
}
if ((opru = opp->pr_usrreqs) == NULL) {
panic("%s: domain (%d,%s), proto %d has no usrreqs!\n",
__func__, odp->dom_family, odp->dom_name, opp->pr_protocol);
}
pru = _MALLOC(sizeof (*pru), M_TEMP, M_WAITOK | M_ZERO);
if (pru == NULL) {
error = ENOMEM;
goto done;
}
pru->pru_flags = PRUF_OLD;
pru->pru_abort = opru->pru_abort;
pru->pru_accept = opru->pru_accept;
pru->pru_attach = opru->pru_attach;
pru->pru_bind = opru->pru_bind;
pru->pru_connect = opru->pru_connect;
pru->pru_connect2 = opru->pru_connect2;
pru->pru_control = opru->pru_control;
pru->pru_detach = opru->pru_detach;
pru->pru_disconnect = opru->pru_disconnect;
pru->pru_listen = opru->pru_listen;
pru->pru_peeraddr = opru->pru_peeraddr;
pru->pru_rcvd = opru->pru_rcvd;
pru->pru_rcvoob = opru->pru_rcvoob;
pru->pru_send = opru->pru_send;
pru->pru_sense = opru->pru_sense;
pru->pru_shutdown = opru->pru_shutdown;
pru->pru_sockaddr = opru->pru_sockaddr;
pru->pru_sosend = opru->pru_sosend;
pru->pru_soreceive = opru->pru_soreceive;
pru->pru_sopoll = opru->pru_sopoll;
pp = _MALLOC(sizeof (*pp), M_TEMP, M_WAITOK | M_ZERO);
if (pp == NULL) {
error = ENOMEM;
goto done;
}
if (opp->pr_unused != NULL) {
printf("%s: domain (%d,%s), proto %d: pr_fasttimo is "
"deprecated and won't be called\n", __func__,
odp->dom_family, odp->dom_name, opp->pr_protocol);
}
if (opp->pr_unused2 != NULL) {
printf("%s: domain (%d,%s), proto %d: pr_slowtimo is "
"deprecated and won't be called\n", __func__,
odp->dom_family, odp->dom_name, opp->pr_protocol);
}
pp->pr_type = opp->pr_type;
pp->pr_protocol = opp->pr_protocol;
pp->pr_flags = (opp->pr_flags & PRF_USERFLAGS) | PR_OLD;
pp->pr_input = opp->pr_input;
pp->pr_output = opp->pr_output;
pp->pr_ctlinput = opp->pr_ctlinput;
pp->pr_ctloutput = opp->pr_ctloutput;
pp->pr_usrreqs = pru;
pp->pr_init = pr_init_old;
pp->pr_drain = opp->pr_drain;
pp->pr_sysctl = opp->pr_sysctl;
pp->pr_lock = opp->pr_lock;
pp->pr_unlock = opp->pr_unlock;
pp->pr_getlock = opp->pr_getlock;
pp->pr_old = opp;
attach_proto(pp, dp);
net_init_proto(pp, dp);
done:
if (error != 0) {
printf("%s: domain (%d,%s), proto %d: failed to attach, "
"error %d\n", __func__, odp->dom_family,
odp->dom_name, opp->pr_protocol, error);
if (pru != NULL)
FREE(pru, M_TEMP);
if (pp != NULL)
FREE(pp, M_TEMP);
}
domain_guard_release(guard);
return (error);
}
int
net_del_proto(int type, int protocol, struct domain *dp)
{
struct protosw *pp;
domain_proto_mtx_lock_assert_held();
TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
if (pp->pr_type == type && pp->pr_protocol == protocol)
break;
}
if (pp == NULL)
return (ENXIO);
detach_proto(pp, dp);
if (pp->pr_usrreqs->pru_flags & PRUF_OLD)
FREE(pp->pr_usrreqs, M_TEMP);
if (pp->pr_flags & PR_OLD)
FREE(pp, M_TEMP);
return (0);
}
int
net_del_proto_old(int type, int protocol, struct domain_old *odp)
{
int error = 0;
struct protosw *pp;
struct domain *dp;
domain_guard_t guard;
guard = domain_guard_deploy();
TAILQ_FOREACH(dp, &domains, dom_entry) {
if (!(dp->dom_flags & DOM_OLD))
continue;
if (dp->dom_old == odp)
break;
}
if (dp == NULL) {
error = ENXIO;
goto done;
}
TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
if (pp->pr_type == type && pp->pr_protocol == protocol)
break;
}
if (pp == NULL) {
error = ENXIO;
goto done;
}
detach_proto(pp, dp);
if (pp->pr_usrreqs->pru_flags & PRUF_OLD)
FREE(pp->pr_usrreqs, M_TEMP);
if (pp->pr_flags & PR_OLD)
FREE(pp, M_TEMP);
done:
domain_guard_release(guard);
return (error);
}
static void
domain_sched_timeout(void)
{
lck_mtx_assert(&domain_timeout_mtx, LCK_MTX_ASSERT_OWNED);
if (!domain_timeout_run && domain_draining) {
domain_timeout_run = TRUE;
timeout(domain_timeout, NULL, hz);
}
}
void
net_drain_domains(void)
{
lck_mtx_lock(&domain_timeout_mtx);
domain_draining = TRUE;
domain_sched_timeout();
lck_mtx_unlock(&domain_timeout_mtx);
}
#if INET6
extern struct domain inet6domain_s;
#endif
#if IPSEC
extern struct domain keydomain_s;
#endif
extern struct domain routedomain_s, ndrvdomain_s, inetdomain_s;
extern struct domain systemdomain_s, localdomain_s;
#if MULTIPATH
extern struct domain mpdomain_s;
#endif
static void
domain_timeout(void *arg)
{
#pragma unused(arg)
struct protosw *pp;
struct domain *dp;
domain_guard_t guard;
lck_mtx_lock(&domain_timeout_mtx);
if (domain_draining) {
domain_draining = FALSE;
lck_mtx_unlock(&domain_timeout_mtx);
guard = domain_guard_deploy();
TAILQ_FOREACH(dp, &domains, dom_entry) {
TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
if (pp->pr_drain != NULL)
(*pp->pr_drain)();
}
}
domain_guard_release(guard);
lck_mtx_lock(&domain_timeout_mtx);
}
domain_timeout_run = FALSE;
domain_sched_timeout();
lck_mtx_unlock(&domain_timeout_mtx);
}
void
domaininit(void)
{
struct domain *dp;
domain_guard_t guard;
domain_proto_mtx_grp_attr = lck_grp_attr_alloc_init();
domain_proto_mtx_grp = lck_grp_alloc_init("domain",
domain_proto_mtx_grp_attr);
domain_proto_mtx_attr = lck_attr_alloc_init();
lck_mtx_init(&domain_proto_mtx, domain_proto_mtx_grp,
domain_proto_mtx_attr);
lck_mtx_init(&domain_timeout_mtx, domain_proto_mtx_grp,
domain_proto_mtx_attr);
guard = domain_guard_deploy();
attach_domain(&inetdomain_s);
#if INET6
attach_domain(&inet6domain_s);
#endif
#if MULTIPATH
attach_domain(&mpdomain_s);
#endif
attach_domain(&systemdomain_s);
attach_domain(&localdomain_s);
#if IPSEC
attach_domain(&keydomain_s);
#endif
attach_domain(&ndrvdomain_s);
attach_domain(&routedomain_s);
TAILQ_FOREACH(dp, &domains, dom_entry)
init_domain(dp);
domain_guard_release(guard);
}
static __inline__ struct domain *
pffinddomain_locked(int pf)
{
struct domain *dp;
domain_proto_mtx_lock_assert_held();
TAILQ_FOREACH(dp, &domains, dom_entry) {
if (dp->dom_family == pf)
break;
}
return (dp);
}
struct protosw *
pffindtype(int family, int type)
{
struct protosw *pp = NULL;
struct domain *dp;
domain_guard_t guard;
guard = domain_guard_deploy();
if ((dp = pffinddomain_locked(family)) == NULL)
goto done;
TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
if (pp->pr_type != 0 && pp->pr_type == type)
goto done;
}
done:
domain_guard_release(guard);
return (pp);
}
struct domain *
pffinddomain(int pf)
{
struct domain *dp;
domain_guard_t guard;
guard = domain_guard_deploy();
dp = pffinddomain_locked(pf);
domain_guard_release(guard);
return (dp);
}
struct domain_old *
pffinddomain_old(int pf)
{
struct domain_old *odp = NULL;
struct domain *dp;
domain_guard_t guard;
guard = domain_guard_deploy();
if ((dp = pffinddomain_locked(pf)) != NULL && (dp->dom_flags & DOM_OLD))
odp = dp->dom_old;
domain_guard_release(guard);
return (odp);
}
struct protosw *
pffindproto(int family, int protocol, int type)
{
struct protosw *pp;
domain_guard_t guard;
guard = domain_guard_deploy();
pp = pffindproto_locked(family, protocol, type);
domain_guard_release(guard);
return (pp);
}
struct protosw *
pffindproto_locked(int family, int protocol, int type)
{
struct protosw *maybe = NULL;
struct protosw *pp;
struct domain *dp;
domain_proto_mtx_lock_assert_held();
if (family == 0)
return (0);
dp = pffinddomain_locked(family);
if (dp == NULL)
return (NULL);
TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
if ((pp->pr_protocol == protocol) && (pp->pr_type == type))
return (pp);
if (type == SOCK_RAW && pp->pr_type == SOCK_RAW &&
pp->pr_protocol == 0 && maybe == NULL)
maybe = pp;
}
return (maybe);
}
struct protosw_old *
pffindproto_old(int family, int protocol, int type)
{
struct protosw_old *opr = NULL;
struct protosw *pp;
domain_guard_t guard;
guard = domain_guard_deploy();
if ((pp = pffindproto_locked(family, protocol, type)) != NULL &&
(pp->pr_flags & PR_OLD))
opr = pp->pr_old;
domain_guard_release(guard);
return (opr);
}
static struct protosw *
pffindprotonotype_locked(int family, int protocol, int type)
{
#pragma unused(type)
struct domain *dp;
struct protosw *pp;
domain_proto_mtx_lock_assert_held();
if (family == 0)
return (0);
dp = pffinddomain_locked(family);
if (dp == NULL)
return (NULL);
TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
if (pp->pr_protocol == protocol)
return (pp);
}
return (NULL);
}
struct protosw *
pffindprotonotype(int family, int protocol)
{
struct protosw *pp;
domain_guard_t guard;
if (protocol == 0)
return (NULL);
guard = domain_guard_deploy();
pp = pffindprotonotype_locked(family, protocol, 0);
domain_guard_release(guard);
return (pp);
}
void
pfctlinput(int cmd, struct sockaddr *sa)
{
pfctlinput2(cmd, sa, NULL);
}
void
pfctlinput2(int cmd, struct sockaddr *sa, void *ctlparam)
{
struct domain *dp;
struct protosw *pp;
domain_guard_t guard;
if (sa == NULL)
return;
guard = domain_guard_deploy();
TAILQ_FOREACH(dp, &domains, dom_entry) {
TAILQ_FOREACH(pp, &dp->dom_protosw, pr_entry) {
if (pp->pr_ctlinput != NULL)
(*pp->pr_ctlinput)(cmd, sa, ctlparam);
}
}
domain_guard_release(guard);
}
void
net_update_uptime(void)
{
struct timeval tv;
microuptime(&tv);
_net_uptime = tv.tv_sec;
if (tv.tv_usec > 500000)
_net_uptime++;
}
void
net_update_uptime_secs(uint64_t secs)
{
_net_uptime = secs;
}
void
net_uptime2timeval(struct timeval *tv)
{
if (tv == NULL)
return;
tv->tv_usec = 0;
tv->tv_sec = net_uptime();
}
u_int64_t
net_uptime(void)
{
if (_net_uptime == 0)
net_update_uptime();
return (_net_uptime);
}
void
domain_proto_mtx_lock_assert_held(void)
{
lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED);
}
void
domain_proto_mtx_lock_assert_notheld(void)
{
lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
}
domain_guard_t
domain_guard_deploy(void)
{
net_thread_marks_t marks;
marks = net_thread_marks_push(NET_THREAD_HELD_DOMAIN);
if (marks != net_thread_marks_none) {
lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
lck_mtx_lock(&domain_proto_mtx);
}
else
lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED);
return ((domain_guard_t)(const void*)marks);
}
void
domain_guard_release(domain_guard_t guard)
{
net_thread_marks_t marks = (net_thread_marks_t)(const void*)guard;
if (marks != net_thread_marks_none) {
lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED);
lck_mtx_unlock(&domain_proto_mtx);
net_thread_marks_pop(marks);
}
else
lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
}
domain_unguard_t
domain_unguard_deploy(void)
{
net_thread_marks_t marks;
marks = net_thread_unmarks_push(NET_THREAD_HELD_DOMAIN);
if (marks != net_thread_marks_none) {
lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED);
lck_mtx_unlock(&domain_proto_mtx);
}
else
lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
return ((domain_unguard_t)(const void*)marks);
}
void
domain_unguard_release(domain_unguard_t unguard)
{
net_thread_marks_t marks = (net_thread_marks_t)(const void*)unguard;
if (marks != net_thread_marks_none) {
lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_NOTOWNED);
lck_mtx_lock(&domain_proto_mtx);
net_thread_unmarks_pop(marks);
}
else
lck_mtx_assert(&domain_proto_mtx, LCK_MTX_ASSERT_OWNED);
}
#if (DEVELOPMENT || DEBUG)
static int
sysctl_do_drain_domains SYSCTL_HANDLER_ARGS
{
#pragma unused(arg1, arg2)
int error;
int dummy = 0;
error = sysctl_handle_int(oidp, &dummy, 0, req);
if (error || req->newptr == USER_ADDR_NULL)
return (error);
net_drain_domains();
return (0);
}
#endif