diff options
Diffstat (limited to 'sys/contrib/lomac/kernel_socket.c')
-rw-r--r-- | sys/contrib/lomac/kernel_socket.c | 772 |
1 files changed, 0 insertions, 772 deletions
diff --git a/sys/contrib/lomac/kernel_socket.c b/sys/contrib/lomac/kernel_socket.c deleted file mode 100644 index ebaf15deefdf..000000000000 --- a/sys/contrib/lomac/kernel_socket.c +++ /dev/null @@ -1,772 +0,0 @@ -/* - * LOMAC - Low Water-Mark Mandatory Access Control - * Copyright (c) 2001 Networks Associates Technology, Inc. - * Copyright (c) 1982, 1986, 1989, 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: kernel_socket.c,v 1.9 2001/11/05 20:57:41 tfraser Exp $ - * - * This file implements LOMAC controls over socket operations. LOMAC - * gains control of socket operations by interposing on the `struct - * pr_usrreqs' operations vectors of each `struct protosw'. This code - * replaces each `struct pr_usrreqs' with an instance of `struct - * lomac_pr_usrreqs' containing LOMAC socket control functions. These - * socket control functions implement LOMAC's socket controls, and then - * call the corresponding socket operations from the original `struct - * pr_usrreqs'. Each instance of `struct lomac_pr_usrreqs' ends with - * a pointer to the `struct pr_usrreqs' it replaces. These pointers - * allow the LOMAC socket control functions to find their corresponding - * original `struct pr_usrreqs' functions. - * - * This file provides the function lomac_initialize_sockets() to turn - * socket interposition on. Once socket iterposition is turned on, - * the kernel will begin to call LOMAC's socket control functions. - */ - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/kernel.h> -#include <sys/proc.h> -#include <sys/resourcevar.h> - -#include <sys/domain.h> -#include <sys/mbuf.h> -#include <sys/namei.h> -#include <sys/protosw.h> -#include <sys/socketvar.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <sys/unpcb.h> -#include <sys/uio.h> -#include <sys/vnode.h> - -#include "kernel_interface.h" -#include "kernel_socket.h" -#include "kernel_mediate.h" -#include "kernel_monitor.h" -#include "lomacfs.h" - -MALLOC_DEFINE(M_LOMAC_USRREQS, "LOMAC-UR", "LOMAC usrreqs"); - -struct lomac_pr_usrreqs { - struct pr_usrreqs lomac_pr_usrreqs; /* LOMAC socket control fxns */ - struct pr_usrreqs *orig_pr_usrreqs; /* original socket op vector */ -}; - -int lomac_local_accept(struct socket *, struct sockaddr **); -int lomac_local_connect(struct socket *, struct sockaddr *, struct thread *); -int lomac_local_connect2(struct socket *, struct socket *); -int lomac_local_detach(struct socket *); -int lomac_local_send( struct socket *, int, struct mbuf *, struct sockaddr *, - struct mbuf *, struct thread * ); -int lomac_soreceive( struct socket *, struct sockaddr **, struct uio *, - struct mbuf **, struct mbuf **, int * ); -int lomac_local_soreceive( struct socket *, struct sockaddr **, struct uio *, - struct mbuf **, struct mbuf **, int * ); -static int monitored_soreceive( struct socket *, struct sockaddr **, - struct uio *, struct mbuf **, struct mbuf **, int * ); - -/* This usrreqs structure implements LOMAC's controls on local sockets */ -struct pr_usrreqs lomac_local_usrreqs = { - NULL, - lomac_local_accept, - NULL, - NULL, - lomac_local_connect, - lomac_local_connect2, - NULL, - lomac_local_detach, - NULL, - NULL, - NULL, - NULL, - NULL, - lomac_local_send, - NULL, - NULL, - NULL, - NULL, - lomac_local_soreceive, - NULL -}; - -/* This usrreqs structure implements LOMAC's controls on network sockets */ -struct pr_usrreqs lomac_net_usrreqs = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - lomac_soreceive, - NULL -}; - -static __inline struct pr_usrreqs * -orig_pr_usrreqs( struct socket *so ) { - return (((struct lomac_pr_usrreqs *)(so->so_proto->pr_usrreqs))-> - orig_pr_usrreqs); -} - -int -lomac_local_accept( struct socket *so, struct sockaddr **nam ) { - struct vnode *vp; - struct unpcb *unp; - int ret_val; /* value to return to caller */ - - unp = sotounpcb(so); - if (unp == NULL) - return (EINVAL); - if (unp->unp_conn != NULL) { - vp = unp->unp_vnode = unp->unp_conn->unp_vnode; - if (vp != NULL) - vref(vp); - } - ret_val = (*orig_pr_usrreqs(so)->pru_accept)(so, nam); - return (ret_val); -} - -int -lomac_local_connect(struct socket *so, struct sockaddr *nam, struct thread *td) -{ - register struct sockaddr_un *soun = (struct sockaddr_un *)nam; - register struct vnode *vp; - register struct socket *so2, *so3; - struct unpcb *unp, *unp2, *unp3; - int error, len; - struct nameidata nd; - char buf[SOCK_MAXADDRLEN]; - - len = nam->sa_len - offsetof(struct sockaddr_un, sun_path); - if (len <= 0) - return EINVAL; - strncpy(buf, soun->sun_path, len); - buf[len] = 0; - - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, buf, td); - error = namei(&nd); - if (error) - goto bad2; - vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); - if (vp->v_type != VSOCK) { - error = ENOTSOCK; - goto bad; - } - error = VOP_ACCESS(vp, VWRITE, td->td_proc->p_ucred, td); - if (error) - goto bad; - so2 = vp->v_socket; - if (so2 == 0) { - error = ECONNREFUSED; - goto bad; - } - if (so->so_type != so2->so_type) { - error = EPROTOTYPE; - goto bad; - } - if (so->so_proto->pr_flags & PR_CONNREQUIRED) { - if ((so2->so_options & SO_ACCEPTCONN) == 0 || - (so3 = sonewconn3(so2, 0, td)) == 0) { - error = ECONNREFUSED; - goto bad; - } - unp = sotounpcb(so); - unp2 = sotounpcb(so2); - unp3 = sotounpcb(so3); - if (unp2->unp_addr) - unp3->unp_addr = (struct sockaddr_un *) - dup_sockaddr((struct sockaddr *) - unp2->unp_addr, 1); - - /* - * unp_peercred management: - * - * The connecter's (client's) credentials are copied - * from its process structure at the time of connect() - * (which is now). - */ - memset(&unp3->unp_peercred, '\0', sizeof(unp3->unp_peercred)); - unp3->unp_peercred.cr_uid = td->td_proc->p_ucred->cr_uid; - unp3->unp_peercred.cr_ngroups = td->td_proc->p_ucred->cr_ngroups; - memcpy(unp3->unp_peercred.cr_groups, td->td_proc->p_ucred->cr_groups, - sizeof(unp3->unp_peercred.cr_groups)); - unp3->unp_flags |= UNP_HAVEPC; - /* - * The receiver's (server's) credentials are copied - * from the unp_peercred member of socket on which the - * former called listen(); unp_listen() cached that - * process's credentials at that time so we can use - * them now. - */ - KASSERT(unp2->unp_flags & UNP_HAVEPCCACHED, - ("unp_connect: listener without cached peercred")); - memcpy(&unp->unp_peercred, &unp2->unp_peercred, - sizeof(unp->unp_peercred)); - unp->unp_flags |= UNP_HAVEPC; - - so2 = so3; - } - error = lomac_local_connect2(so, so2); -bad: - vput(vp); -bad2: - return (error); -} - -int -lomac_local_connect2( struct socket *so1, struct socket *so2 ) { - struct vnode *vp; - int ret_val; /* value to return to caller */ - - if (so2->so_head != NULL) { - vp = sotounpcb(so2->so_head)->unp_vnode; - if (vp != NULL) { - sotounpcb(so1)->unp_vnode = vp; - vref(vp); - } - } - ret_val = (*orig_pr_usrreqs(so1)->pru_connect2)(so1, so2); - return (ret_val); -} - -int -lomac_local_detach( struct socket *so ) { - int ret_val; /* value to return to caller */ - struct unpcb *unp = sotounpcb(so); - - if (unp == NULL) - return (EINVAL); - if (unp->unp_vnode != NULL && unp->unp_vnode->v_socket != so) { - vrele(unp->unp_vnode); - unp->unp_vnode = NULL; - } - ret_val = (*orig_pr_usrreqs(so)->pru_detach)(so); - return (ret_val); -} - -int -lomac_local_send( struct socket *so, int flags, struct mbuf *m, - struct sockaddr *addr, struct mbuf *control, struct thread *td ) { - struct vnode *vp; - struct unpcb *unp = sotounpcb(so); - int error; - - /* printf( "pid %d local send\n", p->p_pid ); */ - if (unp == NULL) { - error = EINVAL; - goto out; - } - if (so->so_type == SOCK_DGRAM) { - if (addr != NULL) { - if (unp->unp_conn != NULL) { - error = EISCONN; - goto out; - } - error = lomac_local_connect(so, addr, td); - if (error) - goto out; - } else if (unp->unp_conn == NULL) { - error = ENOTCONN; - goto out; - } - } else if ((so->so_state & SS_ISCONNECTED) == 0) { - if (addr != NULL) { - error = lomac_local_connect(so, addr, td); - if (error) - goto out; /* XXX */ - } else { - error = ENOTCONN; - goto out; - } - } - vp = unp->unp_vnode; - if (vp != NULL) { - lomac_object_t lobj; - - lobj.lo_type = VISLOMAC(vp) ? LO_TYPE_LVNODE : LO_TYPE_UVNODE; - lobj.lo_object.vnode = vp; - if (!mediate_subject_object("send", td->td_proc, &lobj)) { - error = EPERM; - goto out; - } - } else { - /* - * This is a send to a socket in a socketpair() pair. - * Mark both sockets in pair with the appropriate level. - */ - lomac_object_t lobj1, lobj2; - lattr_t lattr; - - lobj1.lo_type = LO_TYPE_SOCKETPAIR; - lobj1.lo_object.socket = so; - if ((error = monitor_pipe_write(td->td_proc, &lobj1)) != 0) - goto out; - lobj2.lo_type = LO_TYPE_SOCKETPAIR; - lobj2.lo_object.socket = unp->unp_conn->unp_socket; - get_object_lattr(&lobj1, &lattr); - set_object_lattr(&lobj2, lattr); - } - error = (*orig_pr_usrreqs(so)->pru_send)( so, flags, m, NULL, - control, td ); - if (addr != NULL && so->so_type == SOCK_DGRAM) - (*orig_pr_usrreqs(so)->pru_disconnect)(so); -out: - return (error); -} - - - -int -lomac_local_soreceive(struct socket *so, struct sockaddr **paddr, - struct uio *uio, struct mbuf **mp0, struct mbuf **controlp, int *flagsp) { - lomac_object_t lobj; - struct vnode *vp; - struct unpcb *unp = sotounpcb(so); - int ret_val; /* value to return to caller */ - - if (unp == NULL) - return (EINVAL); - vp = unp->unp_vnode; - if (vp != NULL) { - lobj.lo_type = VISLOMAC(vp) ? LO_TYPE_LVNODE : LO_TYPE_UVNODE; - lobj.lo_object.vnode = vp; - ret_val = monitor_read_object(uio->uio_td->td_proc, &lobj); - if (ret_val == 0) - ret_val = (*orig_pr_usrreqs(so)->pru_soreceive)(so, - paddr, uio, mp0, controlp, flagsp); - } else { - /* - * This is a receive from a socket in a pair created by - * socketpair(). Monitor it as we would a pipe read, - * except for allowing for arbitrary numbers of sleeps. - */ - ret_val = monitored_soreceive(so, paddr, uio, mp0, controlp, - flagsp); - } - return (ret_val); -} - -int -lomac_soreceive(struct socket *so, struct sockaddr **paddr, struct uio *uio, - struct mbuf **mp0, struct mbuf **controlp, int *flagsp) { - int ret_val; /* value to return to caller */ - - (void)monitor_read_net_socket(uio->uio_td->td_proc); - ret_val = (*orig_pr_usrreqs(so)->pru_soreceive)(so, paddr, uio, mp0, - controlp, flagsp); - return (ret_val); -} - -int -lomac_initialize_sockets(void) { - struct domain *dp; /* used to traverse global `domains' list */ - struct protosw *pr; /* used to traverse each domain's protosw list */ - struct lomac_pr_usrreqs *lomac_pr_usrreqs; /* lomac usrreqs vectors */ - void (**lfuncp)(void), (**funcp)(void); - int n, nreq; - - nreq = sizeof(struct pr_usrreqs) / sizeof(void (*)(void)); - for (dp = domains; dp; dp = dp->dom_next) { - for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { - - lomac_pr_usrreqs = (struct lomac_pr_usrreqs *)malloc( - sizeof(struct lomac_pr_usrreqs), M_LOMAC_USRREQS, - M_WAITOK); - - if (dp->dom_family == AF_LOCAL) - memcpy(lomac_pr_usrreqs, &lomac_local_usrreqs, - sizeof(struct pr_usrreqs)); - else - memcpy(lomac_pr_usrreqs, &lomac_net_usrreqs, - sizeof(struct pr_usrreqs)); - /* - * Do sparse allocation of user requests and only - * override the ones we need to (to reduce overhead). - */ - lfuncp = (void (**)(void))lomac_pr_usrreqs; - funcp = (void (**)(void))pr->pr_usrreqs; - for (n = 0; n < nreq; n++) { - if (lfuncp[n] == NULL) - lfuncp[n] = funcp[n]; - } - lomac_pr_usrreqs->orig_pr_usrreqs = pr->pr_usrreqs; - pr->pr_usrreqs = (struct pr_usrreqs *)lomac_pr_usrreqs; - } - } - return (0); -} - - -int -lomac_uninitialize_sockets(void) { - struct domain *dp; /* used to traverse global `domains' list */ - struct protosw *pr; /* used to traverse each domain's protosw list */ - struct lomac_pr_usrreqs *lomac_pr_usrreqs; /* lomac usrreqs vectors */ - - for (dp = domains; dp; dp = dp->dom_next) { - for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { - lomac_pr_usrreqs = (struct lomac_pr_usrreqs *) - pr->pr_usrreqs; - pr->pr_usrreqs = lomac_pr_usrreqs->orig_pr_usrreqs; - free(lomac_pr_usrreqs, M_LOMAC_USRREQS); - } - } - return (0); -} - -#define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK) -/* - * Implement receive operations on a socket. - * We depend on the way that records are added to the sockbuf - * by sbappend*. In particular, each record (mbufs linked through m_next) - * must begin with an address if the protocol so specifies, - * followed by an optional mbuf or mbufs containing ancillary data, - * and then zero or more mbufs of data. - * In order to avoid blocking network interrupts for the entire time here, - * we splx() while doing the actual copy to user space. - * Although the sockbuf is locked, new data may still be appended, - * and thus we must maintain consistency of the sockbuf during that time. - * - * The caller may receive the data as a single mbuf chain by supplying - * an mbuf **mp0 for use in returning the chain. The uio is then used - * only for the count in uio_resid. - */ -static int -monitored_soreceive(so, psa, uio, mp0, controlp, flagsp) - register struct socket *so; - struct sockaddr **psa; - struct uio *uio; - struct mbuf **mp0; - struct mbuf **controlp; - int *flagsp; -{ - lomac_object_t lobj; - register struct mbuf *m, **mp; - register int flags, len, error, s, offset; - struct protosw *pr = so->so_proto; - struct mbuf *nextrecord; - struct proc *p; - int moff, type = 0; - int orig_resid = uio->uio_resid; - - mp = mp0; - if (psa) - *psa = 0; - if (controlp) - *controlp = 0; - if (flagsp) - flags = *flagsp &~ MSG_EOR; - else - flags = 0; - lobj.lo_type = LO_TYPE_SOCKETPAIR; - lobj.lo_object.socket = so; - if (uio->uio_td != NULL) /* XXX */ - p = uio->uio_td->td_proc; - else - p = curthread->td_proc; - if (flags & MSG_OOB) { - m = m_get(M_TRYWAIT, MT_DATA); - if (m == NULL) - return (ENOBUFS); - error = (*pr->pr_usrreqs->pru_rcvoob)(so, m, flags & MSG_PEEK); - if (error) - goto bad; - do { - monitor_read_object(p, &lobj); - error = uiomove(mtod(m, caddr_t), - (int) min(uio->uio_resid, m->m_len), uio); - m = m_free(m); - } while (uio->uio_resid && error == 0 && m); -bad: - if (m) - m_freem(m); - return (error); - } - if (mp) - *mp = (struct mbuf *)0; - if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) - (*pr->pr_usrreqs->pru_rcvd)(so, 0); - -restart: - error = sblock(&so->so_rcv, SBLOCKWAIT(flags)); - if (error) - return (error); - s = splnet(); - - m = so->so_rcv.sb_mb; - /* - * If we have less data than requested, block awaiting more - * (subject to any timeout) if: - * 1. the current count is less than the low water mark, or - * 2. MSG_WAITALL is set, and it is possible to do the entire - * receive operation at once if we block (resid <= hiwat). - * 3. MSG_DONTWAIT is not set - * If MSG_WAITALL is set but resid is larger than the receive buffer, - * we have to do the receive in sections, and thus risk returning - * a short count if a timeout or signal occurs after we start. - */ - if (m == 0 || (((flags & MSG_DONTWAIT) == 0 && - so->so_rcv.sb_cc < uio->uio_resid) && - (so->so_rcv.sb_cc < so->so_rcv.sb_lowat || - ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) && - m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0)) { - KASSERT(m != 0 || !so->so_rcv.sb_cc, - ("receive: m == %p so->so_rcv.sb_cc == %lu", - m, so->so_rcv.sb_cc)); - if (so->so_error) { - if (m) - goto dontblock; - error = so->so_error; - if ((flags & MSG_PEEK) == 0) - so->so_error = 0; - goto release; - } - if (so->so_state & SS_CANTRCVMORE) { - if (m) - goto dontblock; - else - goto release; - } - for (; m; m = m->m_next) - if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) { - m = so->so_rcv.sb_mb; - goto dontblock; - } - if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && - (so->so_proto->pr_flags & PR_CONNREQUIRED)) { - error = ENOTCONN; - goto release; - } - if (uio->uio_resid == 0) - goto release; - if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) { - error = EWOULDBLOCK; - goto release; - } - sbunlock(&so->so_rcv); - error = sbwait(&so->so_rcv); - splx(s); - if (error) - return (error); - goto restart; - } -dontblock: - if (uio->uio_td) - p->p_stats->p_ru.ru_msgrcv++; - nextrecord = m->m_nextpkt; - if (pr->pr_flags & PR_ADDR) { - KASSERT(m->m_type == MT_SONAME, ("receive 1a")); - orig_resid = 0; - if (psa) - *psa = dup_sockaddr(mtod(m, struct sockaddr *), - mp0 == 0); - if (flags & MSG_PEEK) { - m = m->m_next; - } else { - sbfree(&so->so_rcv, m); - MFREE(m, so->so_rcv.sb_mb); - m = so->so_rcv.sb_mb; - } - } - while (m && m->m_type == MT_CONTROL && error == 0) { - if (flags & MSG_PEEK) { - if (controlp) - *controlp = m_copy(m, 0, m->m_len); - m = m->m_next; - } else { - sbfree(&so->so_rcv, m); - so->so_rcv.sb_mb = m->m_next; - m->m_next = NULL; - if (pr->pr_domain->dom_externalize) - error = - (*pr->pr_domain->dom_externalize)(m, controlp); - else if (controlp) - *controlp = m; - else - m_freem(m); - m = so->so_rcv.sb_mb; - } - if (controlp) { - orig_resid = 0; - do - controlp = &(*controlp)->m_next; - while (*controlp != NULL); - } - } - if (m) { - if ((flags & MSG_PEEK) == 0) - m->m_nextpkt = nextrecord; - type = m->m_type; - if (type == MT_OOBDATA) - flags |= MSG_OOB; - } - moff = 0; - offset = 0; - while (m && uio->uio_resid > 0 && error == 0) { - if (m->m_type == MT_OOBDATA) { - if (type != MT_OOBDATA) - break; - } else if (type == MT_OOBDATA) - break; - else - KASSERT(m->m_type == MT_DATA || m->m_type == MT_HEADER, - ("receive 3")); - so->so_state &= ~SS_RCVATMARK; - len = uio->uio_resid; - if (so->so_oobmark && len > so->so_oobmark - offset) - len = so->so_oobmark - offset; - if (len > m->m_len - moff) - len = m->m_len - moff; - /* - * If mp is set, just pass back the mbufs. - * Otherwise copy them out via the uio, then free. - * Sockbuf must be consistent here (points to current mbuf, - * it points to next record) when we drop priority; - * we must note any additions to the sockbuf when we - * block interrupts again. - */ - if (mp == 0) { - splx(s); - monitor_read_object(p, &lobj); - error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); - s = splnet(); - if (error) - goto release; - } else - uio->uio_resid -= len; - if (len == m->m_len - moff) { - if (m->m_flags & M_EOR) - flags |= MSG_EOR; - if (flags & MSG_PEEK) { - m = m->m_next; - moff = 0; - } else { - nextrecord = m->m_nextpkt; - sbfree(&so->so_rcv, m); - if (mp) { - *mp = m; - mp = &m->m_next; - so->so_rcv.sb_mb = m = m->m_next; - *mp = (struct mbuf *)0; - } else { - MFREE(m, so->so_rcv.sb_mb); - m = so->so_rcv.sb_mb; - } - if (m) - m->m_nextpkt = nextrecord; - } - } else { - if (flags & MSG_PEEK) - moff += len; - else { - if (mp) - *mp = m_copym(m, 0, len, M_TRYWAIT); - m->m_data += len; - m->m_len -= len; - so->so_rcv.sb_cc -= len; - } - } - if (so->so_oobmark) { - if ((flags & MSG_PEEK) == 0) { - so->so_oobmark -= len; - if (so->so_oobmark == 0) { - so->so_state |= SS_RCVATMARK; - break; - } - } else { - offset += len; - if (offset == so->so_oobmark) - break; - } - } - if (flags & MSG_EOR) - break; - /* - * If the MSG_WAITALL flag is set (for non-atomic socket), - * we must not quit until "uio->uio_resid == 0" or an error - * termination. If a signal/timeout occurs, return - * with a short count but without error. - * Keep sockbuf locked against other readers. - */ - while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 && - !sosendallatonce(so) && !nextrecord) { - if (so->so_error || so->so_state & SS_CANTRCVMORE) - break; - /* - * Notify the protocol that some data has been - * drained before blocking. - */ - if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) - (*pr->pr_usrreqs->pru_rcvd)(so, flags); - error = sbwait(&so->so_rcv); - if (error) { - sbunlock(&so->so_rcv); - splx(s); - return (0); - } - m = so->so_rcv.sb_mb; - if (m) - nextrecord = m->m_nextpkt; - } - } - - if (m && pr->pr_flags & PR_ATOMIC) { - flags |= MSG_TRUNC; - if ((flags & MSG_PEEK) == 0) - (void) sbdroprecord(&so->so_rcv); - } - if ((flags & MSG_PEEK) == 0) { - if (m == 0) - so->so_rcv.sb_mb = nextrecord; - if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) - (*pr->pr_usrreqs->pru_rcvd)(so, flags); - } - if (orig_resid == uio->uio_resid && orig_resid && - (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { - sbunlock(&so->so_rcv); - splx(s); - goto restart; - } - - if (flagsp) - *flagsp |= flags; -release: - sbunlock(&so->so_rcv); - splx(s); - return (error); -} |