summaryrefslogtreecommitdiffstats
path: root/sys/contrib/lomac/kernel_socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/lomac/kernel_socket.c')
-rw-r--r--sys/contrib/lomac/kernel_socket.c772
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 3ca1725..0000000
--- 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.
- *
- * $FreeBSD$
- *
- * 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);
-}
OpenPOWER on IntegriCloud