Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/uipc_usrreq.c
Show First 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
#include <vm/uma.h> | #include <vm/uma.h> | ||||
MALLOC_DECLARE(M_FILECAPS); | MALLOC_DECLARE(M_FILECAPS); | ||||
/* | static struct domain localdomain; | ||||
* See unpcb.h for the locking key. | |||||
*/ | |||||
static uma_zone_t unp_zone; | static uma_zone_t unp_zone; | ||||
static unp_gen_t unp_gencnt; /* (l) */ | static unp_gen_t unp_gencnt; /* (l) */ | ||||
static u_int unp_count; /* (l) Count of local sockets. */ | static u_int unp_count; /* (l) Count of local sockets. */ | ||||
static ino_t unp_ino; /* Prototype for fake inode numbers. */ | static ino_t unp_ino; /* Prototype for fake inode numbers. */ | ||||
static int unp_rights; /* (g) File descriptors in flight. */ | static int unp_rights; /* (g) File descriptors in flight. */ | ||||
static struct unp_head unp_shead; /* (l) List of stream sockets. */ | static struct unp_head unp_shead; /* (l) List of stream sockets. */ | ||||
static struct unp_head unp_dhead; /* (l) List of datagram sockets. */ | static struct unp_head unp_dhead; /* (l) List of datagram sockets. */ | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | |||||
* unpcb. This includes the unp_conn field, which either links two connected | * unpcb. This includes the unp_conn field, which either links two connected | ||||
* PCBs together (for connected socket types) or points at the destination | * PCBs together (for connected socket types) or points at the destination | ||||
* socket (for connectionless socket types). The operations of creating or | * socket (for connectionless socket types). The operations of creating or | ||||
* destroying a connection therefore involve locking multiple PCBs. To avoid | * destroying a connection therefore involve locking multiple PCBs. To avoid | ||||
* lock order reversals, in some cases this involves dropping a PCB lock and | * lock order reversals, in some cases this involves dropping a PCB lock and | ||||
* using a reference counter to maintain liveness. | * using a reference counter to maintain liveness. | ||||
* | * | ||||
* UNIX domain sockets each have an unpcb hung off of their so_pcb pointer, | * UNIX domain sockets each have an unpcb hung off of their so_pcb pointer, | ||||
* allocated in pru_attach() and freed in pru_detach(). The validity of that | * allocated in pr_attach() and freed in pr_detach(). The validity of that | ||||
* pointer is an invariant, so no lock is required to dereference the so_pcb | * pointer is an invariant, so no lock is required to dereference the so_pcb | ||||
* pointer if a valid socket reference is held by the caller. In practice, | * pointer if a valid socket reference is held by the caller. In practice, | ||||
* this is always true during operations performed on a socket. Each unpcb | * this is always true during operations performed on a socket. Each unpcb | ||||
* has a back-pointer to its socket, unp_socket, which will be stable under | * has a back-pointer to its socket, unp_socket, which will be stable under | ||||
* the same circumstances. | * the same circumstances. | ||||
* | * | ||||
* This pointer may only be safely dereferenced as long as a valid reference | * This pointer may only be safely dereferenced as long as a valid reference | ||||
* to the unpcb is held. Typically, this reference will be from the socket, | * to the unpcb is held. Typically, this reference will be from the socket, | ||||
▲ Show 20 Lines • Show All 181 Lines • ▼ Show 20 Lines | unp_pcb_lock_peer(struct unpcb *unp) | ||||
} | } | ||||
if (unp->unp_conn == NULL) { | if (unp->unp_conn == NULL) { | ||||
UNP_PCB_UNLOCK(unp2); | UNP_PCB_UNLOCK(unp2); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
return (unp2); | return (unp2); | ||||
} | } | ||||
/* | |||||
* Definitions of protocols supported in the LOCAL domain. | |||||
*/ | |||||
static struct domain localdomain; | |||||
static struct pr_usrreqs uipc_usrreqs_dgram, uipc_usrreqs_stream; | |||||
static struct pr_usrreqs uipc_usrreqs_seqpacket; | |||||
static struct protosw localsw[] = { | |||||
{ | |||||
.pr_type = SOCK_STREAM, | |||||
.pr_domain = &localdomain, | |||||
.pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_RIGHTS| | |||||
PR_CAPATTACH, | |||||
.pr_ctloutput = &uipc_ctloutput, | |||||
.pr_usrreqs = &uipc_usrreqs_stream | |||||
}, | |||||
{ | |||||
.pr_type = SOCK_DGRAM, | |||||
.pr_domain = &localdomain, | |||||
.pr_flags = PR_ATOMIC | PR_ADDR |PR_RIGHTS | PR_CAPATTACH | | |||||
PR_SOCKBUF, | |||||
.pr_ctloutput = &uipc_ctloutput, | |||||
.pr_usrreqs = &uipc_usrreqs_dgram | |||||
}, | |||||
{ | |||||
.pr_type = SOCK_SEQPACKET, | |||||
.pr_domain = &localdomain, | |||||
/* | |||||
* XXXRW: For now, PR_ADDR because soreceive will bump into them | |||||
* due to our use of sbappendaddr. A new sbappend variants is needed | |||||
* that supports both atomic record writes and control data. | |||||
*/ | |||||
.pr_flags = PR_ADDR|PR_ATOMIC|PR_CONNREQUIRED| | |||||
PR_WANTRCVD|PR_RIGHTS|PR_CAPATTACH, | |||||
.pr_ctloutput = &uipc_ctloutput, | |||||
.pr_usrreqs = &uipc_usrreqs_seqpacket, | |||||
}, | |||||
}; | |||||
static struct domain localdomain = { | |||||
.dom_family = AF_LOCAL, | |||||
.dom_name = "local", | |||||
.dom_externalize = unp_externalize, | |||||
.dom_dispose = unp_dispose, | |||||
.dom_protosw = localsw, | |||||
.dom_protoswNPROTOSW = &localsw[nitems(localsw)] | |||||
}; | |||||
DOMAIN_SET(local); | |||||
static void | static void | ||||
uipc_abort(struct socket *so) | uipc_abort(struct socket *so) | ||||
{ | { | ||||
struct unpcb *unp, *unp2; | struct unpcb *unp, *unp2; | ||||
unp = sotounpcb(so); | unp = sotounpcb(so); | ||||
KASSERT(unp != NULL, ("uipc_abort: unp == NULL")); | KASSERT(unp != NULL, ("uipc_abort: unp == NULL")); | ||||
UNP_PCB_UNLOCK_ASSERT(unp); | UNP_PCB_UNLOCK_ASSERT(unp); | ||||
▲ Show 20 Lines • Show All 634 Lines • ▼ Show 20 Lines | uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, | ||||
SOCKBUF_LOCK(&so->so_snd); | SOCKBUF_LOCK(&so->so_snd); | ||||
if (sbcc >= so->so_snd.sb_hiwat || mbcnt >= so->so_snd.sb_mbmax) | if (sbcc >= so->so_snd.sb_hiwat || mbcnt >= so->so_snd.sb_mbmax) | ||||
so->so_snd.sb_flags |= SB_STOP; | so->so_snd.sb_flags |= SB_STOP; | ||||
SOCKBUF_UNLOCK(&so->so_snd); | SOCKBUF_UNLOCK(&so->so_snd); | ||||
UNP_PCB_UNLOCK(unp2); | UNP_PCB_UNLOCK(unp2); | ||||
m = NULL; | m = NULL; | ||||
out: | out: | ||||
/* | /* | ||||
* PRUS_EOF is equivalent to pru_send followed by pru_shutdown. | * PRUS_EOF is equivalent to pr_send followed by pr_shutdown. | ||||
*/ | */ | ||||
if (flags & PRUS_EOF) { | if (flags & PRUS_EOF) { | ||||
UNP_PCB_LOCK(unp); | UNP_PCB_LOCK(unp); | ||||
socantsendmore(so); | socantsendmore(so); | ||||
unp_shutdown(unp); | unp_shutdown(unp); | ||||
UNP_PCB_UNLOCK(unp); | UNP_PCB_UNLOCK(unp); | ||||
} | } | ||||
if (control != NULL && error != 0) | if (control != NULL && error != 0) | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | if (m == NULL) { | ||||
} | } | ||||
f = m_gethdr(M_WAITOK, MT_SONAME); | f = m_gethdr(M_WAITOK, MT_SONAME); | ||||
cc = m->m_pkthdr.len; | cc = m->m_pkthdr.len; | ||||
mbcnt = MSIZE + m->m_pkthdr.memlen; | mbcnt = MSIZE + m->m_pkthdr.memlen; | ||||
if (c != NULL && | if (c != NULL && | ||||
(error = unp_internalize(&c, td, &clast, &ctl, &mbcnt))) | (error = unp_internalize(&c, td, &clast, &ctl, &mbcnt))) | ||||
goto out; | goto out; | ||||
} else { | } else { | ||||
/* pru_sosend() with mbuf usually is a kernel thread. */ | /* pr_sosend() with mbuf usually is a kernel thread. */ | ||||
M_ASSERTPKTHDR(m); | M_ASSERTPKTHDR(m); | ||||
if (__predict_false(c != NULL)) | if (__predict_false(c != NULL)) | ||||
panic("%s: control from a kernel thread", __func__); | panic("%s: control from a kernel thread", __func__); | ||||
if (__predict_false(m->m_pkthdr.len > unpdg_maxdgram)) { | if (__predict_false(m->m_pkthdr.len > unpdg_maxdgram)) { | ||||
error = EMSGSIZE; | error = EMSGSIZE; | ||||
goto out; | goto out; | ||||
▲ Show 20 Lines • Show All 543 Lines • ▼ Show 20 Lines | if (unp->unp_addr != NULL) | ||||
sa = (struct sockaddr *) unp->unp_addr; | sa = (struct sockaddr *) unp->unp_addr; | ||||
else | else | ||||
sa = &sun_noname; | sa = &sun_noname; | ||||
bcopy(sa, *nam, sa->sa_len); | bcopy(sa, *nam, sa->sa_len); | ||||
UNP_PCB_UNLOCK(unp); | UNP_PCB_UNLOCK(unp); | ||||
return (0); | return (0); | ||||
} | } | ||||
static struct pr_usrreqs uipc_usrreqs_dgram = { | |||||
.pru_abort = uipc_abort, | |||||
.pru_accept = uipc_accept, | |||||
.pru_attach = uipc_attach, | |||||
.pru_bind = uipc_bind, | |||||
.pru_bindat = uipc_bindat, | |||||
.pru_connect = uipc_connect, | |||||
.pru_connectat = uipc_connectat, | |||||
.pru_connect2 = uipc_connect2, | |||||
.pru_detach = uipc_detach, | |||||
.pru_disconnect = uipc_disconnect, | |||||
.pru_peeraddr = uipc_peeraddr, | |||||
.pru_sosend = uipc_sosend_dgram, | |||||
.pru_sense = uipc_sense, | |||||
.pru_shutdown = uipc_shutdown, | |||||
.pru_sockaddr = uipc_sockaddr, | |||||
.pru_soreceive = uipc_soreceive_dgram, | |||||
.pru_close = uipc_close, | |||||
}; | |||||
static struct pr_usrreqs uipc_usrreqs_seqpacket = { | |||||
.pru_abort = uipc_abort, | |||||
.pru_accept = uipc_accept, | |||||
.pru_attach = uipc_attach, | |||||
.pru_bind = uipc_bind, | |||||
.pru_bindat = uipc_bindat, | |||||
.pru_connect = uipc_connect, | |||||
.pru_connectat = uipc_connectat, | |||||
.pru_connect2 = uipc_connect2, | |||||
.pru_detach = uipc_detach, | |||||
.pru_disconnect = uipc_disconnect, | |||||
.pru_listen = uipc_listen, | |||||
.pru_peeraddr = uipc_peeraddr, | |||||
.pru_rcvd = uipc_rcvd, | |||||
.pru_send = uipc_send, | |||||
.pru_sense = uipc_sense, | |||||
.pru_shutdown = uipc_shutdown, | |||||
.pru_sockaddr = uipc_sockaddr, | |||||
.pru_soreceive = soreceive_generic, /* XXX: or...? */ | |||||
.pru_close = uipc_close, | |||||
}; | |||||
static struct pr_usrreqs uipc_usrreqs_stream = { | |||||
.pru_abort = uipc_abort, | |||||
.pru_accept = uipc_accept, | |||||
.pru_attach = uipc_attach, | |||||
.pru_bind = uipc_bind, | |||||
.pru_bindat = uipc_bindat, | |||||
.pru_connect = uipc_connect, | |||||
.pru_connectat = uipc_connectat, | |||||
.pru_connect2 = uipc_connect2, | |||||
.pru_detach = uipc_detach, | |||||
.pru_disconnect = uipc_disconnect, | |||||
.pru_listen = uipc_listen, | |||||
.pru_peeraddr = uipc_peeraddr, | |||||
.pru_rcvd = uipc_rcvd, | |||||
.pru_send = uipc_send, | |||||
.pru_ready = uipc_ready, | |||||
.pru_sense = uipc_sense, | |||||
.pru_shutdown = uipc_shutdown, | |||||
.pru_sockaddr = uipc_sockaddr, | |||||
.pru_soreceive = soreceive_generic, | |||||
.pru_close = uipc_close, | |||||
}; | |||||
static int | static int | ||||
uipc_ctloutput(struct socket *so, struct sockopt *sopt) | uipc_ctloutput(struct socket *so, struct sockopt *sopt) | ||||
{ | { | ||||
struct unpcb *unp; | struct unpcb *unp; | ||||
struct xucred xu; | struct xucred xu; | ||||
int error, optval; | int error, optval; | ||||
if (sopt->sopt_level != SOL_LOCAL) | if (sopt->sopt_level != SOL_LOCAL) | ||||
▲ Show 20 Lines • Show All 1,573 Lines • ▼ Show 20 Lines | for (m = m0; m; m = m->m_next) { | ||||
clen = 0; | clen = 0; | ||||
cm = NULL; | cm = NULL; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
m0 = m0->m_nextpkt; | m0 = m0->m_nextpkt; | ||||
} | } | ||||
} | } | ||||
/* | |||||
* Definitions of protocols supported in the LOCAL domain. | |||||
*/ | |||||
static struct protosw streamproto = { | |||||
.pr_type = SOCK_STREAM, | |||||
.pr_domain = &localdomain, | |||||
.pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_RIGHTS| | |||||
PR_CAPATTACH, | |||||
.pr_ctloutput = &uipc_ctloutput, | |||||
.pr_abort = uipc_abort, | |||||
.pr_accept = uipc_accept, | |||||
.pr_attach = uipc_attach, | |||||
.pr_bind = uipc_bind, | |||||
.pr_bindat = uipc_bindat, | |||||
.pr_connect = uipc_connect, | |||||
.pr_connectat = uipc_connectat, | |||||
.pr_connect2 = uipc_connect2, | |||||
.pr_detach = uipc_detach, | |||||
.pr_disconnect = uipc_disconnect, | |||||
.pr_listen = uipc_listen, | |||||
.pr_peeraddr = uipc_peeraddr, | |||||
.pr_rcvd = uipc_rcvd, | |||||
.pr_send = uipc_send, | |||||
.pr_ready = uipc_ready, | |||||
.pr_sense = uipc_sense, | |||||
.pr_shutdown = uipc_shutdown, | |||||
.pr_sockaddr = uipc_sockaddr, | |||||
.pr_soreceive = soreceive_generic, | |||||
.pr_close = uipc_close, | |||||
}; | |||||
static struct protosw dgramproto = { | |||||
.pr_type = SOCK_DGRAM, | |||||
.pr_domain = &localdomain, | |||||
.pr_flags = PR_ATOMIC | PR_ADDR |PR_RIGHTS | PR_CAPATTACH | | |||||
PR_SOCKBUF, | |||||
.pr_ctloutput = &uipc_ctloutput, | |||||
.pr_abort = uipc_abort, | |||||
.pr_accept = uipc_accept, | |||||
.pr_attach = uipc_attach, | |||||
.pr_bind = uipc_bind, | |||||
.pr_bindat = uipc_bindat, | |||||
.pr_connect = uipc_connect, | |||||
.pr_connectat = uipc_connectat, | |||||
.pr_connect2 = uipc_connect2, | |||||
.pr_detach = uipc_detach, | |||||
.pr_disconnect = uipc_disconnect, | |||||
.pr_peeraddr = uipc_peeraddr, | |||||
.pr_sosend = uipc_sosend_dgram, | |||||
.pr_sense = uipc_sense, | |||||
.pr_shutdown = uipc_shutdown, | |||||
.pr_sockaddr = uipc_sockaddr, | |||||
.pr_soreceive = uipc_soreceive_dgram, | |||||
.pr_close = uipc_close, | |||||
}; | |||||
static struct protosw seqpacketproto = { | |||||
.pr_type = SOCK_SEQPACKET, | |||||
.pr_domain = &localdomain, | |||||
/* | |||||
* XXXRW: For now, PR_ADDR because soreceive will bump into them | |||||
* due to our use of sbappendaddr. A new sbappend variants is needed | |||||
* that supports both atomic record writes and control data. | |||||
*/ | |||||
.pr_flags = PR_ADDR|PR_ATOMIC|PR_CONNREQUIRED| | |||||
PR_WANTRCVD|PR_RIGHTS|PR_CAPATTACH, | |||||
.pr_ctloutput = &uipc_ctloutput, | |||||
.pr_abort = uipc_abort, | |||||
.pr_accept = uipc_accept, | |||||
.pr_attach = uipc_attach, | |||||
.pr_bind = uipc_bind, | |||||
.pr_bindat = uipc_bindat, | |||||
.pr_connect = uipc_connect, | |||||
.pr_connectat = uipc_connectat, | |||||
.pr_connect2 = uipc_connect2, | |||||
.pr_detach = uipc_detach, | |||||
.pr_disconnect = uipc_disconnect, | |||||
.pr_listen = uipc_listen, | |||||
.pr_peeraddr = uipc_peeraddr, | |||||
.pr_rcvd = uipc_rcvd, | |||||
.pr_send = uipc_send, | |||||
.pr_sense = uipc_sense, | |||||
.pr_shutdown = uipc_shutdown, | |||||
.pr_sockaddr = uipc_sockaddr, | |||||
.pr_soreceive = soreceive_generic, /* XXX: or...? */ | |||||
.pr_close = uipc_close, | |||||
}; | |||||
static struct domain localdomain = { | |||||
.dom_family = AF_LOCAL, | |||||
.dom_name = "local", | |||||
.dom_externalize = unp_externalize, | |||||
.dom_dispose = unp_dispose, | |||||
.dom_nprotosw = 3, | |||||
.dom_protosw = { | |||||
&streamproto, | |||||
&dgramproto, | |||||
&seqpacketproto, | |||||
} | |||||
}; | |||||
DOMAIN_SET(local); | |||||
/* | /* | ||||
* A helper function called by VFS before socket-type vnode reclamation. | * A helper function called by VFS before socket-type vnode reclamation. | ||||
* For an active vnode it clears unp_vnode pointer and decrements unp_vnode | * For an active vnode it clears unp_vnode pointer and decrements unp_vnode | ||||
* use count. | * use count. | ||||
*/ | */ | ||||
void | void | ||||
vfs_unp_reclaim(struct vnode *vp) | vfs_unp_reclaim(struct vnode *vp) | ||||
▲ Show 20 Lines • Show All 142 Lines • Show Last 20 Lines |