diff options
author | scottl <scottl@FreeBSD.org> | 2005-06-09 19:56:38 +0000 |
---|---|---|
committer | scottl <scottl@FreeBSD.org> | 2005-06-09 19:56:38 +0000 |
commit | 6be4cb00a414f098d88dc8554c3daee743124744 (patch) | |
tree | 23a647623e2274c2bbbfebca501e980c86f0155e /sys | |
parent | 1d3209ab83aac3089f15e00934e922d222a4ecf0 (diff) | |
download | FreeBSD-src-6be4cb00a414f098d88dc8554c3daee743124744.zip FreeBSD-src-6be4cb00a414f098d88dc8554c3daee743124744.tar.gz |
Back out 1.68.2.26. It was a mis-guided change that was already backed out
of HEAD and should not have been MFC'd. This will restore UDP socket
functionality, which will correct the recent NFS problems.
Submitted by: rwatson
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/uipc_socket.c | 1470 |
1 files changed, 504 insertions, 966 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 4c6f8bf..de55b24 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1,6 +1,4 @@ -/*- - * Copyright (c) 2004 The FreeBSD Foundation - * Copyright (c) 2004-2005 Robert N. M. Watson +/* * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * @@ -12,6 +10,10 @@ * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -29,27 +31,20 @@ * SUCH DAMAGE. * * @(#)uipc_socket.c 8.3 (Berkeley) 4/15/94 + * $FreeBSD$ */ -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - #include "opt_inet.h" -#include "opt_mac.h" -#include "opt_zero.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/fcntl.h> -#include <sys/limits.h> -#include <sys/lock.h> -#include <sys/mac.h> #include <sys/malloc.h> #include <sys/mbuf.h> -#include <sys/mutex.h> #include <sys/domain.h> #include <sys/file.h> /* for struct knote */ #include <sys/kernel.h> +#include <sys/malloc.h> #include <sys/event.h> #include <sys/poll.h> #include <sys/proc.h> @@ -61,27 +56,28 @@ __FBSDID("$FreeBSD$"); #include <sys/sysctl.h> #include <sys/uio.h> #include <sys/jail.h> +#include <vm/vm_zone.h> -#include <vm/uma.h> +#include <machine/limits.h> +#ifdef INET +static int do_setopt_accept_filter(struct socket *so, struct sockopt *sopt); +#endif /* INET */ -static int soreceive_rcvoob(struct socket *so, struct uio *uio, - int flags); - -static void filt_sordetach(struct knote *kn); -static int filt_soread(struct knote *kn, long hint); -static void filt_sowdetach(struct knote *kn); +static void filt_sordetach(struct knote *kn); +static int filt_soread(struct knote *kn, long hint); +static void filt_sowdetach(struct knote *kn); static int filt_sowrite(struct knote *kn, long hint); static int filt_solisten(struct knote *kn, long hint); -static struct filterops solisten_filtops = +static struct filterops solisten_filtops = { 1, NULL, filt_sordetach, filt_solisten }; static struct filterops soread_filtops = { 1, NULL, filt_sordetach, filt_soread }; -static struct filterops sowrite_filtops = +static struct filterops sowrite_filtops = { 1, NULL, filt_sowdetach, filt_sowrite }; -uma_zone_t socket_zone; +struct vm_zone *socket_zone; so_gen_t so_gencnt; /* generation count for sockets */ MALLOC_DEFINE(M_SONAME, "soname", "socket name"); @@ -90,39 +86,8 @@ MALLOC_DEFINE(M_PCB, "pcb", "protocol control block"); SYSCTL_DECL(_kern_ipc); static int somaxconn = SOMAXCONN; -static int somaxconn_sysctl(SYSCTL_HANDLER_ARGS); -/* XXX: we dont have SYSCTL_USHORT */ -SYSCTL_PROC(_kern_ipc, KIPC_SOMAXCONN, somaxconn, CTLTYPE_UINT | CTLFLAG_RW, - 0, sizeof(int), somaxconn_sysctl, "I", "Maximum pending socket connection " - "queue size"); -static int numopensockets; -SYSCTL_INT(_kern_ipc, OID_AUTO, numopensockets, CTLFLAG_RD, - &numopensockets, 0, "Number of open sockets"); -#ifdef ZERO_COPY_SOCKETS -/* These aren't static because they're used in other files. */ -int so_zero_copy_send = 1; -int so_zero_copy_receive = 1; -SYSCTL_NODE(_kern_ipc, OID_AUTO, zero_copy, CTLFLAG_RD, 0, - "Zero copy controls"); -SYSCTL_INT(_kern_ipc_zero_copy, OID_AUTO, receive, CTLFLAG_RW, - &so_zero_copy_receive, 0, "Enable zero copy receive"); -SYSCTL_INT(_kern_ipc_zero_copy, OID_AUTO, send, CTLFLAG_RW, - &so_zero_copy_send, 0, "Enable zero copy send"); -#endif /* ZERO_COPY_SOCKETS */ - -/* - * accept_mtx locks down per-socket fields relating to accept queues. See - * socketvar.h for an annotation of the protected fields of struct socket. - */ -struct mtx accept_mtx; -MTX_SYSINIT(accept_mtx, &accept_mtx, "accept", MTX_DEF); - -/* - * so_global_mtx protects so_gencnt, numopensockets, and the per-socket - * so_gencnt field. - */ -static struct mtx so_global_mtx; -MTX_SYSINIT(so_global_mtx, &so_global_mtx, "so_glabel", MTX_DEF); +SYSCTL_INT(_kern_ipc, KIPC_SOMAXCONN, somaxconn, CTLFLAG_RW, + &somaxconn, 0, "Maximum pending socket connection queue size"); /* * Socket operation routines. @@ -134,63 +99,48 @@ MTX_SYSINIT(so_global_mtx, &so_global_mtx, "so_glabel", MTX_DEF); /* * Get a socket structure from our zone, and initialize it. + * We don't implement `waitok' yet (see comments in uipc_domain.c). * Note that it would probably be better to allocate socket * and PCB at the same time, but I'm not convinced that all * the protocols can be easily modified to do this. - * - * soalloc() returns a socket with a ref count of 0. */ struct socket * -soalloc(int mflags) +soalloc(waitok) + int waitok; { struct socket *so; - so = uma_zalloc(socket_zone, mflags | M_ZERO); - if (so != NULL) { -#ifdef MAC - if (mac_init_socket(so, mflags) != 0) { - uma_zfree(socket_zone, so); - return (NULL); - } -#endif - SOCKBUF_LOCK_INIT(&so->so_snd, "so_snd"); - SOCKBUF_LOCK_INIT(&so->so_rcv, "so_rcv"); - TAILQ_INIT(&so->so_aiojobq); - mtx_lock(&so_global_mtx); + so = zalloci(socket_zone); + if (so) { + /* XXX race condition for reentrant kernel */ + bzero(so, sizeof *so); so->so_gencnt = ++so_gencnt; - ++numopensockets; - mtx_unlock(&so_global_mtx); + TAILQ_INIT(&so->so_aiojobq); } - return (so); + return so; } -/* - * socreate returns a socket with a ref count of 1. The socket should be - * closed with soclose(). - */ int -socreate(dom, aso, type, proto, cred, td) +socreate(dom, aso, type, proto, p) int dom; struct socket **aso; - int type; + register int type; int proto; - struct ucred *cred; - struct thread *td; + struct proc *p; { - struct protosw *prp; - struct socket *so; - int error; + register struct protosw *prp; + register struct socket *so; + register int error; if (proto) prp = pffindproto(dom, proto, type); else prp = pffindtype(dom, type); - if (prp == NULL || prp->pr_usrreqs->pru_attach == NULL || - prp->pr_usrreqs->pru_attach == pru_attach_notsupp) + if (prp == 0 || prp->pr_usrreqs->pru_attach == 0) return (EPROTONOSUPPORT); - if (jailed(cred) && jail_socket_unixiproute_only && + if (p->p_prison && jail_socket_unixiproute_only && prp->pr_domain->dom_family != PF_LOCAL && prp->pr_domain->dom_family != PF_INET && prp->pr_domain->dom_family != PF_ROUTE) { @@ -199,27 +149,20 @@ socreate(dom, aso, type, proto, cred, td) if (prp->pr_type != type) return (EPROTOTYPE); - so = soalloc(M_WAITOK); - if (so == NULL) + so = soalloc(p != 0); + if (so == 0) return (ENOBUFS); TAILQ_INIT(&so->so_incomp); TAILQ_INIT(&so->so_comp); so->so_type = type; - so->so_cred = crhold(cred); + so->so_cred = p->p_ucred; + crhold(so->so_cred); so->so_proto = prp; -#ifdef MAC - mac_create_socket(cred, so); -#endif - knlist_init(&so->so_rcv.sb_sel.si_note, SOCKBUF_MTX(&so->so_rcv)); - knlist_init(&so->so_snd.sb_sel.si_note, SOCKBUF_MTX(&so->so_snd)); - so->so_count = 1; - error = (*prp->pr_usrreqs->pru_attach)(so, proto, td); + error = (*prp->pr_usrreqs->pru_attach)(so, proto, p); if (error) { - ACCEPT_LOCK(); - SOCK_LOCK(so); so->so_state |= SS_NOFDREF; - sorele(so); + sofree(so); return (error); } *aso = so; @@ -227,23 +170,25 @@ socreate(dom, aso, type, proto, cred, td) } int -sobind(so, nam, td) +sobind(so, nam, p) struct socket *so; struct sockaddr *nam; - struct thread *td; + struct proc *p; { + int s = splnet(); + int error; - return ((*so->so_proto->pr_usrreqs->pru_bind)(so, nam, td)); + error = (*so->so_proto->pr_usrreqs->pru_bind)(so, nam, p); + splx(s); + return (error); } void -sodealloc(struct socket *so) +sodealloc(so) + struct socket *so; { - KASSERT(so->so_count == 0, ("sodealloc(): so_count %d", so->so_count)); - mtx_lock(&so_global_mtx); so->so_gencnt = ++so_gencnt; - mtx_unlock(&so_global_mtx); if (so->so_rcv.sb_hiwat) (void)chgsbsize(so->so_cred->cr_uidinfo, &so->so_rcv.sb_hiwat, 0, RLIM_INFINITY); @@ -251,159 +196,75 @@ sodealloc(struct socket *so) (void)chgsbsize(so->so_cred->cr_uidinfo, &so->so_snd.sb_hiwat, 0, RLIM_INFINITY); #ifdef INET - /* remove acccept filter if one is present. */ - if (so->so_accf != NULL) - do_setopt_accept_filter(so, NULL); -#endif -#ifdef MAC - mac_destroy_socket(so); -#endif + if (so->so_accf != NULL) { + if (so->so_accf->so_accept_filter != NULL && + so->so_accf->so_accept_filter->accf_destroy != NULL) { + so->so_accf->so_accept_filter->accf_destroy(so); + } + if (so->so_accf->so_accept_filter_str != NULL) + FREE(so->so_accf->so_accept_filter_str, M_ACCF); + FREE(so->so_accf, M_ACCF); + } +#endif /* INET */ crfree(so->so_cred); - SOCKBUF_LOCK_DESTROY(&so->so_snd); - SOCKBUF_LOCK_DESTROY(&so->so_rcv); - uma_zfree(socket_zone, so); - mtx_lock(&so_global_mtx); - --numopensockets; - mtx_unlock(&so_global_mtx); + zfreei(socket_zone, so); } -/* - * solisten() transitions a socket from a non-listening state to a listening - * state, but can also be used to update the listen queue depth on an - * existing listen socket. The protocol will call back into the sockets - * layer using solisten_proto_check() and solisten_proto() to check and set - * socket-layer listen state. Call backs are used so that the protocol can - * acquire both protocol and socket layer locks in whatever order is reuiqred - * by the protocol. - * - * Protocol implementors are advised to hold the socket lock across the - * socket-layer test and set to avoid races at the socket layer. - */ int -solisten(so, backlog, td) - struct socket *so; +solisten(so, backlog, p) + register struct socket *so; int backlog; - struct thread *td; + struct proc *p; { - int error; + int s, error; - error = (*so->so_proto->pr_usrreqs->pru_listen)(so, td); - if (error) + s = splnet(); + if (so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING)) { + splx(s); + return (EINVAL); + } + error = (*so->so_proto->pr_usrreqs->pru_listen)(so, p); + if (error) { + splx(s); return (error); - - /* - * XXXRW: The following state adjustment should occur in - * solisten_proto(), but we don't currently pass the backlog request - * to the protocol via pru_listen(). - */ + } + if (TAILQ_EMPTY(&so->so_comp)) + so->so_options |= SO_ACCEPTCONN; if (backlog < 0 || backlog > somaxconn) backlog = somaxconn; so->so_qlimit = backlog; + splx(s); return (0); } -int -solisten_proto_check(so) - struct socket *so; -{ - - SOCK_LOCK_ASSERT(so); - - if (so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING | - SS_ISDISCONNECTING)) - return (EINVAL); - return (0); -} - -void -solisten_proto(so) - struct socket *so; -{ - - SOCK_LOCK_ASSERT(so); - - so->so_options |= SO_ACCEPTCONN; -} - -/* - * Attempt to free a socket. This should really be sotryfree(). - * - * We free the socket if the protocol is no longer interested in the socket, - * there's no file descriptor reference, and the refcount is 0. While the - * calling macro sotryfree() tests the refcount, sofree() has to test it - * again as it's possible to race with an accept()ing thread if the socket is - * in an listen queue of a listen socket, as being in the listen queue - * doesn't elevate the reference count. sofree() acquires the accept mutex - * early for this test in order to avoid that race. - */ void sofree(so) - struct socket *so; + register struct socket *so; { - struct socket *head; + struct socket *head = so->so_head; - ACCEPT_LOCK_ASSERT(); - SOCK_LOCK_ASSERT(so); - - if (so->so_pcb != NULL || (so->so_state & SS_NOFDREF) == 0 || - so->so_count != 0) { - SOCK_UNLOCK(so); - ACCEPT_UNLOCK(); + if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) return; - } - - head = so->so_head; if (head != NULL) { - KASSERT((so->so_qstate & SQ_COMP) != 0 || - (so->so_qstate & SQ_INCOMP) != 0, - ("sofree: so_head != NULL, but neither SQ_COMP nor " - "SQ_INCOMP")); - KASSERT((so->so_qstate & SQ_COMP) == 0 || - (so->so_qstate & SQ_INCOMP) == 0, - ("sofree: so->so_qstate is SQ_COMP and also SQ_INCOMP")); - /* - * accept(2) is responsible draining the completed - * connection queue and freeing those sockets, so - * we just return here if this socket is currently - * on the completed connection queue. Otherwise, - * accept(2) may hang after select(2) has indicating - * that a listening socket was ready. If it's an - * incomplete connection, we remove it from the queue - * and free it; otherwise, it won't be released until - * the listening socket is closed. - */ - if ((so->so_qstate & SQ_COMP) != 0) { - SOCK_UNLOCK(so); - ACCEPT_UNLOCK(); + if (so->so_state & SS_INCOMP) { + TAILQ_REMOVE(&head->so_incomp, so, so_list); + head->so_incqlen--; + } else if (so->so_state & SS_COMP) { + /* + * We must not decommission a socket that's + * on the accept(2) queue. If we do, then + * accept(2) may hang after select(2) indicated + * that the listening socket was ready. + */ return; + } else { + panic("sofree: not queued"); } - TAILQ_REMOVE(&head->so_incomp, so, so_list); - head->so_incqlen--; - so->so_qstate &= ~SQ_INCOMP; + so->so_state &= ~SS_INCOMP; so->so_head = NULL; } - KASSERT((so->so_qstate & SQ_COMP) == 0 && - (so->so_qstate & SQ_INCOMP) == 0, - ("sofree: so_head == NULL, but still SQ_COMP(%d) or SQ_INCOMP(%d)", - so->so_qstate & SQ_COMP, so->so_qstate & SQ_INCOMP)); - SOCK_UNLOCK(so); - ACCEPT_UNLOCK(); - SOCKBUF_LOCK(&so->so_snd); - so->so_snd.sb_flags |= SB_NOINTR; - (void)sblock(&so->so_snd, M_WAITOK); - /* - * socantsendmore_locked() drops the socket buffer mutex so that it - * can safely perform wakeups. Re-acquire the mutex before - * continuing. - */ - socantsendmore_locked(so); - SOCKBUF_LOCK(&so->so_snd); - sbunlock(&so->so_snd); - sbrelease_locked(&so->so_snd, so); - SOCKBUF_UNLOCK(&so->so_snd); + sbrelease(&so->so_snd, so); sorflush(so); - knlist_destroy(&so->so_rcv.sb_sel.si_note); - knlist_destroy(&so->so_snd.sb_sel.si_note); sodealloc(so); } @@ -411,44 +272,34 @@ sofree(so) * Close a socket on last file table reference removal. * Initiate disconnect if connected. * Free socket when disconnect complete. - * - * This function will sorele() the socket. Note that soclose() may be - * called prior to the ref count reaching zero. The actual socket - * structure will not be freed until the ref count reaches zero. */ int soclose(so) - struct socket *so; + register struct socket *so; { + int s = splnet(); /* conservative */ int error = 0; - KASSERT(!(so->so_state & SS_NOFDREF), ("soclose: SS_NOFDREF on enter")); - - funsetown(&so->so_sigio); + funsetown(so->so_sigio); if (so->so_options & SO_ACCEPTCONN) { - struct socket *sp; - ACCEPT_LOCK(); - while ((sp = TAILQ_FIRST(&so->so_incomp)) != NULL) { - TAILQ_REMOVE(&so->so_incomp, sp, so_list); - so->so_incqlen--; - sp->so_qstate &= ~SQ_INCOMP; - sp->so_head = NULL; - ACCEPT_UNLOCK(); + struct socket *sp, *sonext; + + sp = TAILQ_FIRST(&so->so_incomp); + for (; sp != NULL; sp = sonext) { + sonext = TAILQ_NEXT(sp, so_list); (void) soabort(sp); - ACCEPT_LOCK(); } - while ((sp = TAILQ_FIRST(&so->so_comp)) != NULL) { + for (sp = TAILQ_FIRST(&so->so_comp); sp != NULL; sp = sonext) { + sonext = TAILQ_NEXT(sp, so_list); + /* Dequeue from so_comp since sofree() won't do it */ TAILQ_REMOVE(&so->so_comp, sp, so_list); so->so_qlen--; - sp->so_qstate &= ~SQ_COMP; + sp->so_state &= ~SS_COMP; sp->so_head = NULL; - ACCEPT_UNLOCK(); (void) soabort(sp); - ACCEPT_LOCK(); } - ACCEPT_UNLOCK(); } - if (so->so_pcb == NULL) + if (so->so_pcb == 0) goto discard; if (so->so_state & SS_ISCONNECTED) { if ((so->so_state & SS_ISDISCONNECTING) == 0) { @@ -461,7 +312,7 @@ soclose(so) (so->so_state & SS_NBIO)) goto drop; while (so->so_state & SS_ISCONNECTED) { - error = tsleep(&so->so_timeo, + error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH, "soclos", so->so_linger * hz); if (error) break; @@ -469,25 +320,22 @@ soclose(so) } } drop: - if (so->so_pcb != NULL) { + if (so->so_pcb) { int error2 = (*so->so_proto->pr_usrreqs->pru_detach)(so); if (error == 0) error = error2; } discard: - ACCEPT_LOCK(); - SOCK_LOCK(so); - KASSERT((so->so_state & SS_NOFDREF) == 0, ("soclose: NOFDREF")); + if (so->so_state & SS_NOFDREF) + panic("soclose: NOFDREF"); so->so_state |= SS_NOFDREF; - sorele(so); + sofree(so); + splx(s); return (error); } /* - * soabort() must not be called with any socket locks held, as it calls - * into the protocol, which will call back into the socket code causing - * it to acquire additional socket locks that may cause recursion or lock - * order reversals. + * Must be called at splnet... */ int soabort(so) @@ -497,9 +345,7 @@ soabort(so) error = (*so->so_proto->pr_usrreqs->pru_abort)(so); if (error) { - ACCEPT_LOCK(); - SOCK_LOCK(so); - sotryfree(so); /* note: does not decrement the ref count */ + sofree(so); return error; } return (0); @@ -507,29 +353,32 @@ soabort(so) int soaccept(so, nam) - struct socket *so; + register struct socket *so; struct sockaddr **nam; { + int s = splnet(); int error; - SOCK_LOCK(so); - KASSERT((so->so_state & SS_NOFDREF) != 0, ("soaccept: !NOFDREF")); + if ((so->so_state & SS_NOFDREF) == 0) + panic("soaccept: !NOFDREF"); so->so_state &= ~SS_NOFDREF; - SOCK_UNLOCK(so); error = (*so->so_proto->pr_usrreqs->pru_accept)(so, nam); + splx(s); return (error); } int -soconnect(so, nam, td) - struct socket *so; +soconnect(so, nam, p) + register struct socket *so; struct sockaddr *nam; - struct thread *td; + struct proc *p; { + int s; int error; if (so->so_options & SO_ACCEPTCONN) return (EOPNOTSUPP); + s = splnet(); /* * If protocol is connection-based, can only connect once. * Otherwise, if connected, try to disconnect first. @@ -538,40 +387,45 @@ soconnect(so, nam, td) */ if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && ((so->so_proto->pr_flags & PR_CONNREQUIRED) || - (error = sodisconnect(so)))) { + (error = sodisconnect(so)))) error = EISCONN; - } else { - /* - * Prevent accumulated error from previous connection - * from biting us. - */ - so->so_error = 0; - error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam, td); - } - + else + error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam, p); + splx(s); return (error); } int soconnect2(so1, so2) - struct socket *so1; + register struct socket *so1; struct socket *so2; { + int s = splnet(); + int error; - return ((*so1->so_proto->pr_usrreqs->pru_connect2)(so1, so2)); + error = (*so1->so_proto->pr_usrreqs->pru_connect2)(so1, so2); + splx(s); + return (error); } int sodisconnect(so) - struct socket *so; + register struct socket *so; { + int s = splnet(); int error; - if ((so->so_state & SS_ISCONNECTED) == 0) - return (ENOTCONN); - if (so->so_state & SS_ISDISCONNECTING) - return (EALREADY); + if ((so->so_state & SS_ISCONNECTED) == 0) { + error = ENOTCONN; + goto bad; + } + if (so->so_state & SS_ISDISCONNECTING) { + error = EALREADY; + goto bad; + } error = (*so->so_proto->pr_usrreqs->pru_disconnect)(so); +bad: + splx(s); return (error); } @@ -593,42 +447,23 @@ sodisconnect(so) * must check for short counts if EINTR/ERESTART are returned. * Data and control buffers are freed on return. */ - -#ifdef ZERO_COPY_SOCKETS -struct so_zerocopy_stats{ - int size_ok; - int align_ok; - int found_ifp; -}; -struct so_zerocopy_stats so_zerocp_stats = {0,0,0}; -#include <netinet/in.h> -#include <net/route.h> -#include <netinet/in_pcb.h> -#include <vm/vm.h> -#include <vm/vm_page.h> -#include <vm/vm_object.h> -#endif /*ZERO_COPY_SOCKETS*/ - int -sosend(so, addr, uio, top, control, flags, td) - struct socket *so; +sosend(so, addr, uio, top, control, flags, p) + register struct socket *so; struct sockaddr *addr; struct uio *uio; struct mbuf *top; struct mbuf *control; int flags; - struct thread *td; + struct proc *p; { struct mbuf **mp; - struct mbuf *m; - long space, len = 0, resid; - int clen = 0, error, dontroute; + register struct mbuf *m; + register long space, len, resid; + int clen = 0, error, s, dontroute, mlen; int atomic = sosendallatonce(so) || top; -#ifdef ZERO_COPY_SOCKETS - int cow_send; -#endif /* ZERO_COPY_SOCKETS */ - if (uio != NULL) + if (uio) resid = uio->uio_resid; else resid = top->m_pkthdr.len; @@ -650,25 +485,24 @@ sosend(so, addr, uio, top, control, flags, td) dontroute = (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && (so->so_proto->pr_flags & PR_ATOMIC); - if (td != NULL) - td->td_proc->p_stats->p_ru.ru_msgsnd++; - if (control != NULL) + if (p) + p->p_stats->p_ru.ru_msgsnd++; + if (control) clen = control->m_len; -#define snderr(errno) { error = (errno); goto release; } +#define snderr(errno) { error = errno; splx(s); goto release; } - SOCKBUF_LOCK(&so->so_snd); restart: - SOCKBUF_LOCK_ASSERT(&so->so_snd); error = sblock(&so->so_snd, SBLOCKWAIT(flags)); if (error) - goto out_locked; + goto out; do { - SOCKBUF_LOCK_ASSERT(&so->so_snd); - if (so->so_snd.sb_state & SBS_CANTSENDMORE) + s = splnet(); + if (so->so_state & SS_CANTSENDMORE) snderr(EPIPE); if (so->so_error) { error = so->so_error; so->so_error = 0; + splx(s); goto release; } if ((so->so_state & SS_ISCONNECTED) == 0) { @@ -683,7 +517,7 @@ restart: if ((so->so_state & SS_ISCONFIRMING) == 0 && !(resid == 0 && clen != 0)) snderr(ENOTCONN); - } else if (addr == NULL) + } else if (addr == 0) snderr(so->so_proto->pr_flags & PR_CONNREQUIRED ? ENOTCONN : EDESTADDRREQ); } @@ -695,15 +529,16 @@ restart: snderr(EMSGSIZE); if (space < resid + clen && (atomic || space < so->so_snd.sb_lowat || space < clen)) { - if ((so->so_state & SS_NBIO) || (flags & MSG_NBIO)) + if (so->so_state & SS_NBIO) snderr(EWOULDBLOCK); sbunlock(&so->so_snd); error = sbwait(&so->so_snd); + splx(s); if (error) - goto out_locked; + goto out; goto restart; } - SOCKBUF_UNLOCK(&so->so_snd); + splx(s); mp = ⊤ space -= clen; do { @@ -715,94 +550,47 @@ restart: if (flags & MSG_EOR) top->m_flags |= M_EOR; } else do { -#ifdef ZERO_COPY_SOCKETS - cow_send = 0; -#endif /* ZERO_COPY_SOCKETS */ - if (resid >= MINCLSIZE) { -#ifdef ZERO_COPY_SOCKETS - if (top == NULL) { - MGETHDR(m, M_TRYWAIT, MT_DATA); - if (m == NULL) { - error = ENOBUFS; - SOCKBUF_LOCK(&so->so_snd); - goto release; - } - m->m_pkthdr.len = 0; - m->m_pkthdr.rcvif = (struct ifnet *)0; - } else { - MGET(m, M_TRYWAIT, MT_DATA); - if (m == NULL) { - error = ENOBUFS; - SOCKBUF_LOCK(&so->so_snd); - goto release; - } - } - if (so_zero_copy_send && - resid>=PAGE_SIZE && - space>=PAGE_SIZE && - uio->uio_iov->iov_len>=PAGE_SIZE) { - so_zerocp_stats.size_ok++; - so_zerocp_stats.align_ok++; - cow_send = socow_setup(m, uio); - len = cow_send; - } - if (!cow_send) { - MCLGET(m, M_TRYWAIT); - if ((m->m_flags & M_EXT) == 0) { - m_free(m); - m = NULL; - } else { - len = min(min(MCLBYTES, resid), space); - } + if (top == 0) { + MGETHDR(m, M_WAIT, MT_DATA); + if (m == NULL) { + error = ENOBUFS; + goto release; } -#else /* ZERO_COPY_SOCKETS */ - if (top == NULL) { - m = m_getcl(M_TRYWAIT, MT_DATA, M_PKTHDR); - m->m_pkthdr.len = 0; - m->m_pkthdr.rcvif = (struct ifnet *)0; - } else - m = m_getcl(M_TRYWAIT, MT_DATA, 0); - len = min(min(MCLBYTES, resid), space); -#endif /* ZERO_COPY_SOCKETS */ + mlen = MHLEN; + m->m_pkthdr.len = 0; + m->m_pkthdr.rcvif = (struct ifnet *)0; } else { - if (top == NULL) { - m = m_gethdr(M_TRYWAIT, MT_DATA); - m->m_pkthdr.len = 0; - m->m_pkthdr.rcvif = (struct ifnet *)0; - - len = min(min(MHLEN, resid), space); - /* - * For datagram protocols, leave room - * for protocol headers in first mbuf. - */ - if (atomic && m && len < MHLEN) - MH_ALIGN(m, len); - } else { - m = m_get(M_TRYWAIT, MT_DATA); - len = min(min(MLEN, resid), space); + MGET(m, M_WAIT, MT_DATA); + if (m == NULL) { + error = ENOBUFS; + goto release; } + mlen = MLEN; } - if (m == NULL) { - error = ENOBUFS; - SOCKBUF_LOCK(&so->so_snd); - goto release; + if (resid >= MINCLSIZE) { + MCLGET(m, M_WAIT); + if ((m->m_flags & M_EXT) == 0) + goto nopages; + mlen = MCLBYTES; + len = min(min(mlen, resid), space); + } else { +nopages: + len = min(min(mlen, resid), space); + /* + * For datagram protocols, leave room + * for protocol headers in first mbuf. + */ + if (atomic && top == 0 && len < mlen) + MH_ALIGN(m, len); } - space -= len; -#ifdef ZERO_COPY_SOCKETS - if (cow_send) - error = 0; - else -#endif /* ZERO_COPY_SOCKETS */ - error = uiomove(mtod(m, void *), (int)len, uio); + error = uiomove(mtod(m, caddr_t), (int)len, uio); resid = uio->uio_resid; m->m_len = len; *mp = m; top->m_pkthdr.len += len; - if (error) { - SOCKBUF_LOCK(&so->so_snd); + if (error) goto release; - } mp = &m->m_next; if (resid <= 0) { if (flags & MSG_EOR) @@ -810,17 +598,15 @@ restart: break; } } while (space > 0 && atomic); - if (dontroute) { - SOCK_LOCK(so); + if (dontroute) so->so_options |= SO_DONTROUTE; - SOCK_UNLOCK(so); - } + s = splnet(); /* XXX */ /* - * XXX all the SBS_CANTSENDMORE checks previously + * XXX all the SS_CANTSENDMORE checks previously * done could be out of date. We could have recieved * a reset packet in an interrupt or maybe we slept * while doing page faults in uiomove() etc. We could - * probably recheck again inside the locking protection + * probably recheck again inside the splnet() protection * here, but there are probably other places that this * also happens. We must rethink this. */ @@ -837,127 +623,30 @@ restart: PRUS_EOF : /* If there is more to send set PRUS_MORETOCOME */ (resid > 0 && space > 0) ? PRUS_MORETOCOME : 0, - top, addr, control, td); - if (dontroute) { - SOCK_LOCK(so); + top, addr, control, p); + splx(s); + if (dontroute) so->so_options &= ~SO_DONTROUTE; - SOCK_UNLOCK(so); - } clen = 0; - control = NULL; - top = NULL; + control = 0; + top = 0; mp = ⊤ - if (error) { - SOCKBUF_LOCK(&so->so_snd); + if (error) goto release; - } } while (resid && space > 0); - SOCKBUF_LOCK(&so->so_snd); } while (resid); release: - SOCKBUF_LOCK_ASSERT(&so->so_snd); sbunlock(&so->so_snd); -out_locked: - SOCKBUF_LOCK_ASSERT(&so->so_snd); - SOCKBUF_UNLOCK(&so->so_snd); out: - if (top != NULL) + if (top) m_freem(top); - if (control != NULL) + if (control) m_freem(control); return (error); } /* - * The part of soreceive() that implements reading non-inline out-of-band - * data from a socket. For more complete comments, see soreceive(), from - * which this code originated. - * - * Note that soreceive_rcvoob(), unlike the remainder of soreceive(), is - * unable to return an mbuf chain to the caller. - */ -static int -soreceive_rcvoob(so, uio, flags) - struct socket *so; - struct uio *uio; - int flags; -{ - struct protosw *pr = so->so_proto; - struct mbuf *m; - int error; - - KASSERT(flags & MSG_OOB, ("soreceive_rcvoob: (flags & MSG_OOB) == 0")); - - 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 { -#ifdef ZERO_COPY_SOCKETS - if (so_zero_copy_receive) { - int disposable; - - if ((m->m_flags & M_EXT) - && (m->m_ext.ext_type == EXT_DISPOSABLE)) - disposable = 1; - else - disposable = 0; - - error = uiomoveco(mtod(m, void *), - min(uio->uio_resid, m->m_len), - uio, disposable); - } else -#endif /* ZERO_COPY_SOCKETS */ - error = uiomove(mtod(m, void *), - (int) min(uio->uio_resid, m->m_len), uio); - m = m_free(m); - } while (uio->uio_resid && error == 0 && m); -bad: - if (m != NULL) - m_freem(m); - return (error); -} - -/* - * Following replacement or removal of the first mbuf on the first mbuf chain - * of a socket buffer, push necessary state changes back into the socket - * buffer so that other consumers see the values consistently. 'nextrecord' - * is the callers locally stored value of the original value of - * sb->sb_mb->m_nextpkt which must be restored when the lead mbuf changes. - * NOTE: 'nextrecord' may be NULL. - */ -static __inline void -sockbuf_pushsync(struct sockbuf *sb, struct mbuf *nextrecord) -{ - - SOCKBUF_LOCK_ASSERT(sb); - /* - * First, update for the new value of nextrecord. If necessary, make - * it the first record. - */ - if (sb->sb_mb != NULL) - sb->sb_mb->m_nextpkt = nextrecord; - else - sb->sb_mb = nextrecord; - - /* - * Now update any dependent socket buffer fields to reflect the new - * state. This is an expanded inline of SB_EMPTY_FIXUP(), with the - * addition of a second clause that takes care of the case where - * sb_mb has been updated, but remains the last record. - */ - if (sb->sb_mb == NULL) { - sb->sb_mbtail = NULL; - sb->sb_lastrecord = NULL; - } else if (sb->sb_mb->m_nextpkt == NULL) - sb->sb_lastrecord = sb->sb_mb; -} - - -/* * 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) @@ -975,43 +664,56 @@ sockbuf_pushsync(struct sockbuf *sb, struct mbuf *nextrecord) */ int soreceive(so, psa, uio, mp0, controlp, flagsp) - struct socket *so; + register struct socket *so; struct sockaddr **psa; struct uio *uio; struct mbuf **mp0; struct mbuf **controlp; int *flagsp; { - struct mbuf *m, **mp; - int flags, len, error, offset; + register struct mbuf *m, **mp; + register int flags, len, error, s, offset; struct protosw *pr = so->so_proto; struct mbuf *nextrecord; int moff, type = 0; int orig_resid = uio->uio_resid; mp = mp0; - if (psa != NULL) - *psa = NULL; - if (controlp != NULL) - *controlp = NULL; - if (flagsp != NULL) + if (psa) + *psa = 0; + if (controlp) + *controlp = 0; + if (flagsp) flags = *flagsp &~ MSG_EOR; else flags = 0; - if (flags & MSG_OOB) - return (soreceive_rcvoob(so, uio, flags)); - if (mp != NULL) - *mp = NULL; - if ((pr->pr_flags & PR_WANTRCVD) && (so->so_state & SS_ISCONFIRMING) - && uio->uio_resid) + if (flags & MSG_OOB) { + m = m_get(M_WAIT, MT_DATA); + if (m == NULL) + return (ENOBUFS); + error = (*pr->pr_usrreqs->pru_rcvoob)(so, m, flags & MSG_PEEK); + if (error) + goto bad; + do { + 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); - SOCKBUF_LOCK(&so->so_rcv); restart: - SOCKBUF_LOCK_ASSERT(&so->so_rcv); error = sblock(&so->so_rcv, SBLOCKWAIT(flags)); if (error) - goto out; + return (error); + s = splnet(); m = so->so_rcv.sb_mb; /* @@ -1025,30 +727,27 @@ restart: * 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 == NULL || (((flags & MSG_DONTWAIT) == 0 && + 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 == NULL && (pr->pr_flags & PR_ATOMIC) == 0)) { - KASSERT(m != NULL || !so->so_rcv.sb_cc, - ("receive: m == %p so->so_rcv.sb_cc == %u", - m, so->so_rcv.sb_cc)); + m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0)) { + KASSERT(m != 0 || !so->so_rcv.sb_cc, ("receive 1")); if (so->so_error) { - if (m != NULL) + if (m) goto dontblock; error = so->so_error; if ((flags & MSG_PEEK) == 0) so->so_error = 0; goto release; } - SOCKBUF_LOCK_ASSERT(&so->so_rcv); - if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { + if (so->so_state & SS_CANTRCVMORE) { if (m) goto dontblock; else goto release; } - for (; m != NULL; m = m->m_next) + 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; @@ -1060,8 +759,7 @@ restart: } if (uio->uio_resid == 0) goto release; - if ((so->so_state & SS_NBIO) || - (flags & (MSG_DONTWAIT|MSG_NBIO))) { + if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) { error = EWOULDBLOCK; goto release; } @@ -1069,109 +767,69 @@ restart: SBLASTMBUFCHK(&so->so_rcv); sbunlock(&so->so_rcv); error = sbwait(&so->so_rcv); + splx(s); if (error) - goto out; + return (error); goto restart; } dontblock: - /* - * From this point onward, we maintain 'nextrecord' as a cache of the - * pointer to the next record in the socket buffer. We must keep the - * various socket buffer pointers and local stack versions of the - * pointers in sync, pushing out modifications before dropping the - * socket buffer mutex, and re-reading them when picking it up. - * - * Otherwise, we will race with the network stack appending new data - * or records onto the socket buffer by using inconsistent/stale - * versions of the field, possibly resulting in socket buffer - * corruption. - * - * By holding the high-level sblock(), we prevent simultaneous - * readers from pulling off the front of the socket buffer. - */ - SOCKBUF_LOCK_ASSERT(&so->so_rcv); - if (uio->uio_td) - uio->uio_td->td_proc->p_stats->p_ru.ru_msgrcv++; - KASSERT(m == so->so_rcv.sb_mb, ("soreceive: m != so->so_rcv.sb_mb")); + if (uio->uio_procp) + uio->uio_procp->p_stats->p_ru.ru_msgrcv++; SBLASTRECORDCHK(&so->so_rcv); SBLASTMBUFCHK(&so->so_rcv); nextrecord = m->m_nextpkt; if (pr->pr_flags & PR_ADDR) { - KASSERT(m->m_type == MT_SONAME, - ("m->m_type == %d", m->m_type)); + KASSERT(m->m_type == MT_SONAME, ("receive 1a")); orig_resid = 0; - if (psa != NULL) - *psa = sodupsockaddr(mtod(m, struct sockaddr *), - M_NOWAIT); + 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); so->so_rcv.sb_mb = m_free(m); m = so->so_rcv.sb_mb; - sockbuf_pushsync(&so->so_rcv, nextrecord); } } - - /* - * Process one or more MT_CONTROL mbufs present before any data mbufs - * in the first mbuf chain on the socket buffer. If MSG_PEEK, we - * just copy the data; if !MSG_PEEK, we call into the protocol to - * perform externalization (or freeing if controlp == NULL). - */ - if (m != NULL && m->m_type == MT_CONTROL) { - struct mbuf *cm = NULL, *cmn; - struct mbuf **cme = &cm; - - do { - if (flags & MSG_PEEK) { - if (controlp != NULL) { - *controlp = m_copy(m, 0, m->m_len); - controlp = &(*controlp)->m_next; - } - m = m->m_next; - } else { - sbfree(&so->so_rcv, m); + 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); + if (controlp) { + if (pr->pr_domain->dom_externalize && + mtod(m, struct cmsghdr *)->cmsg_type == + SCM_RIGHTS) + error = (*pr->pr_domain->dom_externalize)(m); + *controlp = m; so->so_rcv.sb_mb = m->m_next; - m->m_next = NULL; - *cme = m; - cme = &(*cme)->m_next; + m->m_next = 0; + m = so->so_rcv.sb_mb; + } else { + so->so_rcv.sb_mb = m_free(m); m = so->so_rcv.sb_mb; } - } while (m != NULL && m->m_type == MT_CONTROL); - if ((flags & MSG_PEEK) == 0) - sockbuf_pushsync(&so->so_rcv, nextrecord); - while (cm != NULL) { - cmn = cm->m_next; - cm->m_next = NULL; - if (pr->pr_domain->dom_externalize != NULL) { - SOCKBUF_UNLOCK(&so->so_rcv); - error = (*pr->pr_domain->dom_externalize) - (cm, controlp); - SOCKBUF_LOCK(&so->so_rcv); - } else if (controlp != NULL) - *controlp = cm; - else - m_freem(cm); - if (controlp != NULL) { - orig_resid = 0; - while (*controlp != NULL) - controlp = &(*controlp)->m_next; - } - cm = cmn; } - nextrecord = so->so_rcv.sb_mb->m_nextpkt; - orig_resid = 0; + if (controlp) { + orig_resid = 0; + controlp = &(*controlp)->m_next; + } } - if (m != NULL) { + if (m) { if ((flags & MSG_PEEK) == 0) { - KASSERT(m->m_nextpkt == nextrecord, - ("soreceive: post-control, nextrecord !sync")); + m->m_nextpkt = nextrecord; + /* + * If nextrecord == NULL (this is a single chain), + * then sb_lastrecord may not be valid here if m + * was changed earlier. + */ if (nextrecord == NULL) { KASSERT(so->so_rcv.sb_mb == m, - ("soreceive: post-control, sb_mb!=m")); - KASSERT(so->so_rcv.sb_lastrecord == m, - ("soreceive: post-control, lastrecord!=m")); + ("receive tailq 1")); + so->so_rcv.sb_lastrecord = m; } } type = m->m_type; @@ -1179,34 +837,17 @@ dontblock: flags |= MSG_OOB; } else { if ((flags & MSG_PEEK) == 0) { - KASSERT(so->so_rcv.sb_mb == nextrecord, - ("soreceive: sb_mb != nextrecord")); - if (so->so_rcv.sb_mb == NULL) { - KASSERT(so->so_rcv.sb_lastrecord == NULL, - ("soreceive: sb_lastercord != NULL")); - } + KASSERT(so->so_rcv.sb_mb == m,("receive tailq 2")); + so->so_rcv.sb_mb = nextrecord; + SB_EMPTY_FIXUP(&so->so_rcv); } } - SOCKBUF_LOCK_ASSERT(&so->so_rcv); SBLASTRECORDCHK(&so->so_rcv); SBLASTMBUFCHK(&so->so_rcv); - /* - * Now continue to read any data mbufs off of the head of the socket - * buffer until the read request is satisfied. Note that 'type' is - * used to store the type of any mbuf reads that have happened so far - * such that soreceive() can stop reading if the type changes, which - * causes soreceive() to return only one of regular data and inline - * out-of-band data in a single socket receive operation. - */ moff = 0; offset = 0; - while (m != NULL && uio->uio_resid > 0 && error == 0) { - /* - * If the type of mbuf has changed since the last mbuf - * examined ('type'), end the receive operation. - */ - SOCKBUF_LOCK_ASSERT(&so->so_rcv); + while (m && uio->uio_resid > 0 && error == 0) { if (m->m_type == MT_OOBDATA) { if (type != MT_OOBDATA) break; @@ -1214,8 +855,8 @@ dontblock: break; else KASSERT(m->m_type == MT_DATA || m->m_type == MT_HEADER, - ("m->m_type == %d", m->m_type)); - so->so_rcv.sb_state &= ~SBS_RCVATMARK; + ("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; @@ -1229,33 +870,16 @@ dontblock: * we must note any additions to the sockbuf when we * block interrupts again. */ - if (mp == NULL) { - SOCKBUF_LOCK_ASSERT(&so->so_rcv); + if (mp == 0) { SBLASTRECORDCHK(&so->so_rcv); SBLASTMBUFCHK(&so->so_rcv); - SOCKBUF_UNLOCK(&so->so_rcv); -#ifdef ZERO_COPY_SOCKETS - if (so_zero_copy_receive) { - int disposable; - - if ((m->m_flags & M_EXT) - && (m->m_ext.ext_type == EXT_DISPOSABLE)) - disposable = 1; - else - disposable = 0; - - error = uiomoveco(mtod(m, char *) + moff, - (int)len, uio, - disposable); - } else -#endif /* ZERO_COPY_SOCKETS */ - error = uiomove(mtod(m, char *) + moff, (int)len, uio); - SOCKBUF_LOCK(&so->so_rcv); + splx(s); + error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); + s = splnet(); if (error) goto release; } else uio->uio_resid -= len; - SOCKBUF_LOCK_ASSERT(&so->so_rcv); if (len == m->m_len - moff) { if (m->m_flags & M_EOR) flags |= MSG_EOR; @@ -1265,16 +889,15 @@ dontblock: } else { nextrecord = m->m_nextpkt; sbfree(&so->so_rcv, m); - if (mp != NULL) { + if (mp) { *mp = m; mp = &m->m_next; so->so_rcv.sb_mb = m = m->m_next; - *mp = NULL; + *mp = (struct mbuf *)0; } else { - so->so_rcv.sb_mb = m_free(m); - m = so->so_rcv.sb_mb; + so->so_rcv.sb_mb = m = m_free(m); } - if (m != NULL) { + if (m) { m->m_nextpkt = nextrecord; if (nextrecord == NULL) so->so_rcv.sb_lastrecord = m; @@ -1289,40 +912,18 @@ dontblock: if (flags & MSG_PEEK) moff += len; else { - if (mp != NULL) { - int copy_flag; - - if (flags & MSG_DONTWAIT) - copy_flag = M_DONTWAIT; - else - copy_flag = M_TRYWAIT; - if (copy_flag == M_TRYWAIT) - SOCKBUF_UNLOCK(&so->so_rcv); - *mp = m_copym(m, 0, len, copy_flag); - if (copy_flag == M_TRYWAIT) - SOCKBUF_LOCK(&so->so_rcv); - if (*mp == NULL) { - /* - * m_copym() couldn't allocate an mbuf. - * Adjust uio_resid back (it was adjusted - * down by len bytes, which we didn't end - * up "copying" over). - */ - uio->uio_resid += len; - break; - } - } + if (mp) + *mp = m_copym(m, 0, len, M_WAIT); m->m_data += len; m->m_len -= len; so->so_rcv.sb_cc -= len; } } - SOCKBUF_LOCK_ASSERT(&so->so_rcv); if (so->so_oobmark) { if ((flags & MSG_PEEK) == 0) { so->so_oobmark -= len; if (so->so_oobmark == 0) { - so->so_rcv.sb_state |= SBS_RCVATMARK; + so->so_state |= SS_RCVATMARK; break; } } else { @@ -1340,39 +941,39 @@ dontblock: * with a short count but without error. * Keep sockbuf locked against other readers. */ - while (flags & MSG_WAITALL && m == NULL && uio->uio_resid > 0 && - !sosendallatonce(so) && nextrecord == NULL) { - SOCKBUF_LOCK_ASSERT(&so->so_rcv); - if (so->so_error || so->so_rcv.sb_state & SBS_CANTRCVMORE) + 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. + * The window might have closed to zero, make + * sure we send an ack now that we've drained + * the buffer or we might end up blocking until + * the idle takes over (5 seconds). */ - if (pr->pr_flags & PR_WANTRCVD && so->so_pcb != NULL) { - SOCKBUF_UNLOCK(&so->so_rcv); + if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) (*pr->pr_usrreqs->pru_rcvd)(so, flags); - SOCKBUF_LOCK(&so->so_rcv); - } SBLASTRECORDCHK(&so->so_rcv); SBLASTMBUFCHK(&so->so_rcv); error = sbwait(&so->so_rcv); - if (error) - goto release; + if (error) { + sbunlock(&so->so_rcv); + splx(s); + return (0); + } m = so->so_rcv.sb_mb; - if (m != NULL) + if (m) nextrecord = m->m_nextpkt; } } - SOCKBUF_LOCK_ASSERT(&so->so_rcv); - if (m != NULL && pr->pr_flags & PR_ATOMIC) { + if (m && pr->pr_flags & PR_ATOMIC) { flags |= MSG_TRUNC; if ((flags & MSG_PEEK) == 0) - (void) sbdroprecord_locked(&so->so_rcv); + (void) sbdroprecord(&so->so_rcv); } if ((flags & MSG_PEEK) == 0) { - if (m == NULL) { + if (m == 0) { /* * First part is an inline SB_EMPTY_FIXUP(). Second * part makes sure sb_lastrecord is up-to-date if @@ -1387,42 +988,30 @@ dontblock: } SBLASTRECORDCHK(&so->so_rcv); SBLASTMBUFCHK(&so->so_rcv); - /* - * If soreceive() is being done from the socket callback, then - * don't need to generate ACK to peer to update window, since - * ACK will be generated on return to TCP. - */ - if (!(flags & MSG_SOCALLBCK) && - (pr->pr_flags & PR_WANTRCVD) && so->so_pcb) { - SOCKBUF_UNLOCK(&so->so_rcv); + if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) (*pr->pr_usrreqs->pru_rcvd)(so, flags); - SOCKBUF_LOCK(&so->so_rcv); - } } - SOCKBUF_LOCK_ASSERT(&so->so_rcv); if (orig_resid == uio->uio_resid && orig_resid && - (flags & MSG_EOR) == 0 && (so->so_rcv.sb_state & SBS_CANTRCVMORE) == 0) { + (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { sbunlock(&so->so_rcv); + splx(s); goto restart; } - if (flagsp != NULL) + if (flagsp) *flagsp |= flags; release: - SOCKBUF_LOCK_ASSERT(&so->so_rcv); sbunlock(&so->so_rcv); -out: - SOCKBUF_LOCK_ASSERT(&so->so_rcv); - SOCKBUF_UNLOCK(&so->so_rcv); + splx(s); return (error); } int soshutdown(so, how) - struct socket *so; - int how; + register struct socket *so; + register int how; { - struct protosw *pr = so->so_proto; + register struct protosw *pr = so->so_proto; if (!(how == SHUT_RD || how == SHUT_WR || how == SHUT_RDWR)) return (EINVAL); @@ -1436,49 +1025,109 @@ soshutdown(so, how) void sorflush(so) - struct socket *so; + register struct socket *so; { - struct sockbuf *sb = &so->so_rcv; - struct protosw *pr = so->so_proto; + register struct sockbuf *sb = &so->so_rcv; + register struct protosw *pr = so->so_proto; + register int s; struct sockbuf asb; - /* - * XXXRW: This is quite ugly. Previously, this code made a copy of - * the socket buffer, then zero'd the original to clear the buffer - * fields. However, with mutexes in the socket buffer, this causes - * problems. We only clear the zeroable bits of the original; - * however, we have to initialize and destroy the mutex in the copy - * so that dom_dispose() and sbrelease() can lock t as needed. - */ - SOCKBUF_LOCK(sb); sb->sb_flags |= SB_NOINTR; (void) sblock(sb, M_WAITOK); - /* - * socantrcvmore_locked() drops the socket buffer mutex so that it - * can safely perform wakeups. Re-acquire the mutex before - * continuing. - */ - socantrcvmore_locked(so); - SOCKBUF_LOCK(sb); + s = splimp(); + socantrcvmore(so); sbunlock(sb); - /* - * Invalidate/clear most of the sockbuf structure, but leave - * selinfo and mutex data unchanged. - */ - bzero(&asb, offsetof(struct sockbuf, sb_startzero)); - bcopy(&sb->sb_startzero, &asb.sb_startzero, - sizeof(*sb) - offsetof(struct sockbuf, sb_startzero)); - bzero(&sb->sb_startzero, - sizeof(*sb) - offsetof(struct sockbuf, sb_startzero)); - SOCKBUF_UNLOCK(sb); - - SOCKBUF_LOCK_INIT(&asb, "so_rcv"); - if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose != NULL) + asb = *sb; + bzero((caddr_t)sb, sizeof (*sb)); + if (asb.sb_flags & SB_KNOTE) { + sb->sb_sel.si_note = asb.sb_sel.si_note; + sb->sb_flags = SB_KNOTE; + } + splx(s); + if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) (*pr->pr_domain->dom_dispose)(asb.sb_mb); sbrelease(&asb, so); - SOCKBUF_LOCK_DESTROY(&asb); } +#ifdef INET +static int +do_setopt_accept_filter(so, sopt) + struct socket *so; + struct sockopt *sopt; +{ + struct accept_filter_arg *afap = NULL; + struct accept_filter *afp; + struct so_accf *af = so->so_accf; + int error = 0; + + /* do not set/remove accept filters on non listen sockets */ + if ((so->so_options & SO_ACCEPTCONN) == 0) { + error = EINVAL; + goto out; + } + + /* removing the filter */ + if (sopt == NULL) { + if (af != NULL) { + if (af->so_accept_filter != NULL && + af->so_accept_filter->accf_destroy != NULL) { + af->so_accept_filter->accf_destroy(so); + } + if (af->so_accept_filter_str != NULL) { + FREE(af->so_accept_filter_str, M_ACCF); + } + FREE(af, M_ACCF); + so->so_accf = NULL; + } + so->so_options &= ~SO_ACCEPTFILTER; + return (0); + } + /* adding a filter */ + /* must remove previous filter first */ + if (af != NULL) { + error = EINVAL; + goto out; + } + /* don't put large objects on the kernel stack */ + MALLOC(afap, struct accept_filter_arg *, sizeof(*afap), M_TEMP, M_WAITOK); + error = sooptcopyin(sopt, afap, sizeof *afap, sizeof *afap); + afap->af_name[sizeof(afap->af_name)-1] = '\0'; + afap->af_arg[sizeof(afap->af_arg)-1] = '\0'; + if (error) + goto out; + afp = accept_filt_get(afap->af_name); + if (afp == NULL) { + error = ENOENT; + goto out; + } + MALLOC(af, struct so_accf *, sizeof(*af), M_ACCF, M_WAITOK); + bzero(af, sizeof(*af)); + if (afp->accf_create != NULL) { + if (afap->af_name[0] != '\0') { + int len = strlen(afap->af_name) + 1; + + MALLOC(af->so_accept_filter_str, char *, len, M_ACCF, M_WAITOK); + strcpy(af->so_accept_filter_str, afap->af_name); + } + af->so_accept_filter_arg = afp->accf_create(so, afap->af_arg); + if (af->so_accept_filter_arg == NULL) { + FREE(af->so_accept_filter_str, M_ACCF); + FREE(af, M_ACCF); + so->so_accf = NULL; + error = EINVAL; + goto out; + } + } + af->so_accept_filter = afp; + so->so_accf = af; + so->so_options |= SO_ACCEPTFILTER; +out: + if (afap != NULL) + FREE(afap, M_TEMP); + return (error); +} +#endif /* INET */ + /* * Perhaps this routine, and sooptcopyout(), below, ought to come in * an additional variant to handle the case where the option value needs @@ -1506,32 +1155,13 @@ sooptcopyin(sopt, buf, len, minlen) if (valsize > len) sopt->sopt_valsize = valsize = len; - if (sopt->sopt_td != NULL) + if (sopt->sopt_p != 0) return (copyin(sopt->sopt_val, buf, valsize)); bcopy(sopt->sopt_val, buf, valsize); return 0; } -/* - * Kernel version of setsockopt(2)/ - * XXX: optlen is size_t, not socklen_t - */ -int -so_setsockopt(struct socket *so, int level, int optname, void *optval, - size_t optlen) -{ - struct sockopt sopt; - - sopt.sopt_level = level; - sopt.sopt_name = optname; - sopt.sopt_dir = SOPT_SET; - sopt.sopt_val = optval; - sopt.sopt_valsize = optlen; - sopt.sopt_td = NULL; - return (sosetopt(so, &sopt)); -} - int sosetopt(so, sopt) struct socket *so; @@ -1541,9 +1171,6 @@ sosetopt(so, sopt) struct linger l; struct timeval tv; u_long val; -#ifdef MAC - struct mac extmac; -#endif error = 0; if (sopt->sopt_level != SOL_SOCKET) { @@ -1559,19 +1186,17 @@ sosetopt(so, sopt) if (error) goto bad; break; -#endif +#endif /* INET */ case SO_LINGER: error = sooptcopyin(sopt, &l, sizeof l, sizeof l); if (error) goto bad; - SOCK_LOCK(so); so->so_linger = l.l_linger; if (l.l_onoff) so->so_options |= SO_LINGER; else so->so_options &= ~SO_LINGER; - SOCK_UNLOCK(so); break; case SO_DEBUG: @@ -1583,18 +1208,14 @@ sosetopt(so, sopt) case SO_REUSEPORT: case SO_OOBINLINE: case SO_TIMESTAMP: - case SO_BINTIME: - case SO_NOSIGPIPE: error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); if (error) goto bad; - SOCK_LOCK(so); if (optval) so->so_options |= sopt->sopt_name; else so->so_options &= ~sopt->sopt_name; - SOCK_UNLOCK(so); break; case SO_SNDBUF: @@ -1620,7 +1241,7 @@ sosetopt(so, sopt) case SO_RCVBUF: if (sbreserve(sopt->sopt_name == SO_SNDBUF ? &so->so_snd : &so->so_rcv, (u_long)optval, - so, curthread) == 0) { + so, curproc) == 0) { error = ENOBUFS; goto bad; } @@ -1631,18 +1252,14 @@ sosetopt(so, sopt) * the high-water. */ case SO_SNDLOWAT: - SOCKBUF_LOCK(&so->so_snd); so->so_snd.sb_lowat = (optval > so->so_snd.sb_hiwat) ? so->so_snd.sb_hiwat : optval; - SOCKBUF_UNLOCK(&so->so_snd); break; case SO_RCVLOWAT: - SOCKBUF_LOCK(&so->so_rcv); so->so_rcv.sb_lowat = (optval > so->so_rcv.sb_hiwat) ? so->so_rcv.sb_hiwat : optval; - SOCKBUF_UNLOCK(&so->so_rcv); break; } break; @@ -1655,15 +1272,15 @@ sosetopt(so, sopt) goto bad; /* assert(hz > 0); */ - if (tv.tv_sec < 0 || tv.tv_sec > INT_MAX / hz || + if (tv.tv_sec < 0 || tv.tv_sec > SHRT_MAX / hz || tv.tv_usec < 0 || tv.tv_usec >= 1000000) { error = EDOM; goto bad; } /* assert(tick > 0); */ - /* assert(ULONG_MAX - INT_MAX >= 1000000); */ + /* assert(ULONG_MAX - SHRT_MAX >= 1000000); */ val = (u_long)(tv.tv_sec * hz) + tv.tv_usec / tick; - if (val > INT_MAX) { + if (val > SHRT_MAX) { error = EDOM; goto bad; } @@ -1679,24 +1296,11 @@ sosetopt(so, sopt) break; } break; - case SO_LABEL: -#ifdef MAC - error = sooptcopyin(sopt, &extmac, sizeof extmac, - sizeof extmac); - if (error) - goto bad; - error = mac_setsockopt_label(sopt->sopt_td->td_ucred, - so, &extmac); -#else - error = EOPNOTSUPP; -#endif - break; default: error = ENOPROTOOPT; break; } - if (error == 0 && so->so_proto != NULL && - so->so_proto->pr_ctloutput != NULL) { + if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) { (void) ((*so->so_proto->pr_ctloutput) (so, sopt)); } @@ -1725,8 +1329,8 @@ sooptcopyout(struct sockopt *sopt, const void *buf, size_t len) */ valsize = min(len, sopt->sopt_valsize); sopt->sopt_valsize = valsize; - if (sopt->sopt_val != NULL) { - if (sopt->sopt_td != NULL) + if (sopt->sopt_val != 0) { + if (sopt->sopt_p != 0) error = copyout(buf, sopt->sopt_val, valsize); else bcopy(buf, sopt->sopt_val, valsize); @@ -1742,9 +1346,7 @@ sogetopt(so, sopt) int error, optval; struct linger l; struct timeval tv; -#ifdef MAC - struct mac extmac; -#endif + struct accept_filter_arg *afap; error = 0; if (sopt->sopt_level != SOL_SOCKET) { @@ -1757,14 +1359,24 @@ sogetopt(so, sopt) switch (sopt->sopt_name) { #ifdef INET case SO_ACCEPTFILTER: - error = do_getopt_accept_filter(so, sopt); + if ((so->so_options & SO_ACCEPTCONN) == 0) + return (EINVAL); + MALLOC(afap, struct accept_filter_arg *, sizeof(*afap), + M_TEMP, M_WAITOK); + bzero(afap, sizeof(*afap)); + if ((so->so_options & SO_ACCEPTFILTER) != 0) { + strcpy(afap->af_name, so->so_accf->so_accept_filter->accf_name); + if (so->so_accf->so_accept_filter_str != NULL) + strcpy(afap->af_arg, so->so_accf->so_accept_filter_str); + } + error = sooptcopyout(sopt, afap, sizeof(*afap)); + FREE(afap, M_TEMP); break; -#endif +#endif /* INET */ + case SO_LINGER: - SOCK_LOCK(so); l.l_onoff = so->so_options & SO_LINGER; l.l_linger = so->so_linger; - SOCK_UNLOCK(so); error = sooptcopyout(sopt, &l, sizeof l); break; @@ -1777,8 +1389,6 @@ sogetopt(so, sopt) case SO_BROADCAST: case SO_OOBINLINE: case SO_TIMESTAMP: - case SO_BINTIME: - case SO_NOSIGPIPE: optval = so->so_options & sopt->sopt_name; integer: error = sooptcopyout(sopt, &optval, sizeof optval); @@ -1817,37 +1427,8 @@ integer: tv.tv_sec = optval / hz; tv.tv_usec = (optval % hz) * tick; error = sooptcopyout(sopt, &tv, sizeof tv); - break; - case SO_LABEL: -#ifdef MAC - error = sooptcopyin(sopt, &extmac, sizeof(extmac), - sizeof(extmac)); - if (error) - return (error); - error = mac_getsockopt_label(sopt->sopt_td->td_ucred, - so, &extmac); - if (error) - return (error); - error = sooptcopyout(sopt, &extmac, sizeof extmac); -#else - error = EOPNOTSUPP; -#endif - break; - case SO_PEERLABEL: -#ifdef MAC - error = sooptcopyin(sopt, &extmac, sizeof(extmac), - sizeof(extmac)); - if (error) - return (error); - error = mac_getsockopt_peerlabel( - sopt->sopt_td->td_ucred, so, &extmac); - if (error) - return (error); - error = sooptcopyout(sopt, &extmac, sizeof extmac); -#else - error = EOPNOTSUPP; -#endif - break; + break; + default: error = ENOPROTOOPT; break; @@ -1863,11 +1444,11 @@ soopt_getm(struct sockopt *sopt, struct mbuf **mp) struct mbuf *m, *m_prev; int sopt_size = sopt->sopt_valsize; - MGET(m, sopt->sopt_td ? M_TRYWAIT : M_DONTWAIT, MT_DATA); - if (m == NULL) + MGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT, MT_DATA); + if (m == 0) return ENOBUFS; if (sopt_size > MLEN) { - MCLGET(m, sopt->sopt_td ? M_TRYWAIT : M_DONTWAIT); + MCLGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT); if ((m->m_flags & M_EXT) == 0) { m_free(m); return ENOBUFS; @@ -1881,16 +1462,14 @@ soopt_getm(struct sockopt *sopt, struct mbuf **mp) m_prev = m; while (sopt_size) { - MGET(m, sopt->sopt_td ? M_TRYWAIT : M_DONTWAIT, MT_DATA); - if (m == NULL) { + MGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT, MT_DATA); + if (m == 0) { m_freem(*mp); return ENOBUFS; } if (sopt_size > MLEN) { - MCLGET(m, sopt->sopt_td != NULL ? M_TRYWAIT : - M_DONTWAIT); + MCLGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT); if ((m->m_flags & M_EXT) == 0) { - m_freem(m); m_freem(*mp); return ENOBUFS; } @@ -1914,7 +1493,7 @@ soopt_mcopyin(struct sockopt *sopt, struct mbuf *m) if (sopt->sopt_val == NULL) return 0; while (m != NULL && sopt->sopt_valsize >= m->m_len) { - if (sopt->sopt_td != NULL) { + if (sopt->sopt_p != NULL) { int error; error = copyin(sopt->sopt_val, mtod(m, char *), @@ -1926,7 +1505,7 @@ soopt_mcopyin(struct sockopt *sopt, struct mbuf *m) } else bcopy(sopt->sopt_val, mtod(m, char *), m->m_len); sopt->sopt_valsize -= m->m_len; - sopt->sopt_val = (char *)sopt->sopt_val + m->m_len; + (caddr_t)sopt->sopt_val += m->m_len; m = m->m_next; } if (m != NULL) /* should be allocated enoughly at ip6_sooptmcopyin() */ @@ -1944,7 +1523,7 @@ soopt_mcopyout(struct sockopt *sopt, struct mbuf *m) if (sopt->sopt_val == NULL) return 0; while (m != NULL && sopt->sopt_valsize >= m->m_len) { - if (sopt->sopt_td != NULL) { + if (sopt->sopt_p != NULL) { int error; error = copyout(mtod(m, char *), sopt->sopt_val, @@ -1956,7 +1535,7 @@ soopt_mcopyout(struct sockopt *sopt, struct mbuf *m) } else bcopy(mtod(m, char *), sopt->sopt_val, m->m_len); sopt->sopt_valsize -= m->m_len; - sopt->sopt_val = (char *)sopt->sopt_val + m->m_len; + (caddr_t)sopt->sopt_val += m->m_len; valsize += m->m_len; m = m->m_next; } @@ -1971,69 +1550,62 @@ soopt_mcopyout(struct sockopt *sopt, struct mbuf *m) void sohasoutofband(so) - struct socket *so; + register struct socket *so; { if (so->so_sigio != NULL) - pgsigio(&so->so_sigio, SIGURG, 0); - selwakeuppri(&so->so_rcv.sb_sel, PSOCK); + pgsigio(so->so_sigio, SIGURG, 0); + selwakeup(&so->so_rcv.sb_sel); } int -sopoll(struct socket *so, int events, struct ucred *active_cred, - struct thread *td) +sopoll(struct socket *so, int events, struct ucred *cred, struct proc *p) { int revents = 0; + int s = splnet(); - SOCKBUF_LOCK(&so->so_snd); - SOCKBUF_LOCK(&so->so_rcv); if (events & (POLLIN | POLLRDNORM)) if (soreadable(so)) revents |= events & (POLLIN | POLLRDNORM); - if (events & POLLINIGNEOF) - if (so->so_rcv.sb_cc >= so->so_rcv.sb_lowat || - !TAILQ_EMPTY(&so->so_comp) || so->so_error) - revents |= POLLINIGNEOF; - if (events & (POLLOUT | POLLWRNORM)) if (sowriteable(so)) revents |= events & (POLLOUT | POLLWRNORM); if (events & (POLLPRI | POLLRDBAND)) - if (so->so_oobmark || (so->so_rcv.sb_state & SBS_RCVATMARK)) + if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) revents |= events & (POLLPRI | POLLRDBAND); if (revents == 0) { - if (events & - (POLLIN | POLLINIGNEOF | POLLPRI | POLLRDNORM | - POLLRDBAND)) { - selrecord(td, &so->so_rcv.sb_sel); + if (events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) { + selrecord(p, &so->so_rcv.sb_sel); so->so_rcv.sb_flags |= SB_SEL; } if (events & (POLLOUT | POLLWRNORM)) { - selrecord(td, &so->so_snd.sb_sel); + selrecord(p, &so->so_snd.sb_sel); so->so_snd.sb_flags |= SB_SEL; } } - SOCKBUF_UNLOCK(&so->so_rcv); - SOCKBUF_UNLOCK(&so->so_snd); + splx(s); return (revents); } int -soo_kqfilter(struct file *fp, struct knote *kn) +sokqfilter(struct file *fp, struct knote *kn) { - struct socket *so = kn->kn_fp->f_data; + struct socket *so = (struct socket *)kn->kn_fp->f_data; struct sockbuf *sb; + int s; switch (kn->kn_filter) { case EVFILT_READ: if (so->so_options & SO_ACCEPTCONN) kn->kn_fop = &solisten_filtops; - else + else if (so->so_state & SS_ISCONNECTED) kn->kn_fop = &soread_filtops; + else + return (EINVAL); sb = &so->so_rcv; break; case EVFILT_WRITE: @@ -2041,121 +1613,87 @@ soo_kqfilter(struct file *fp, struct knote *kn) sb = &so->so_snd; break; default: - return (EINVAL); + return (1); } - SOCKBUF_LOCK(sb); - knlist_add(&sb->sb_sel.si_note, kn, 1); + s = splnet(); + SLIST_INSERT_HEAD(&sb->sb_sel.si_note, kn, kn_selnext); sb->sb_flags |= SB_KNOTE; - SOCKBUF_UNLOCK(sb); + splx(s); return (0); } static void filt_sordetach(struct knote *kn) { - struct socket *so = kn->kn_fp->f_data; + struct socket *so = (struct socket *)kn->kn_fp->f_data; + int s = splnet(); - SOCKBUF_LOCK(&so->so_rcv); - knlist_remove(&so->so_rcv.sb_sel.si_note, kn, 1); - if (knlist_empty(&so->so_rcv.sb_sel.si_note)) + SLIST_REMOVE(&so->so_rcv.sb_sel.si_note, kn, knote, kn_selnext); + if (SLIST_EMPTY(&so->so_rcv.sb_sel.si_note)) so->so_rcv.sb_flags &= ~SB_KNOTE; - SOCKBUF_UNLOCK(&so->so_rcv); + splx(s); } /*ARGSUSED*/ static int filt_soread(struct knote *kn, long hint) { - struct socket *so; + struct socket *so = (struct socket *)kn->kn_fp->f_data; - so = kn->kn_fp->f_data; - SOCKBUF_LOCK_ASSERT(&so->so_rcv); - - kn->kn_data = so->so_rcv.sb_cc - so->so_rcv.sb_ctl; - if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { - kn->kn_flags |= EV_EOF; + kn->kn_data = so->so_rcv.sb_cc; + if (so->so_state & SS_CANTRCVMORE) { + kn->kn_flags |= EV_EOF; kn->kn_fflags = so->so_error; return (1); - } else if (so->so_error) /* temporary udp error */ + } + if (so->so_error) /* temporary udp error */ return (1); - else if (kn->kn_sfflags & NOTE_LOWAT) + if (kn->kn_sfflags & NOTE_LOWAT) return (kn->kn_data >= kn->kn_sdata); - else - return (so->so_rcv.sb_cc >= so->so_rcv.sb_lowat); + return (kn->kn_data >= so->so_rcv.sb_lowat); } static void filt_sowdetach(struct knote *kn) { - struct socket *so = kn->kn_fp->f_data; + struct socket *so = (struct socket *)kn->kn_fp->f_data; + int s = splnet(); - SOCKBUF_LOCK(&so->so_snd); - knlist_remove(&so->so_snd.sb_sel.si_note, kn, 1); - if (knlist_empty(&so->so_snd.sb_sel.si_note)) + SLIST_REMOVE(&so->so_snd.sb_sel.si_note, kn, knote, kn_selnext); + if (SLIST_EMPTY(&so->so_snd.sb_sel.si_note)) so->so_snd.sb_flags &= ~SB_KNOTE; - SOCKBUF_UNLOCK(&so->so_snd); + splx(s); } /*ARGSUSED*/ static int filt_sowrite(struct knote *kn, long hint) { - struct socket *so; + struct socket *so = (struct socket *)kn->kn_fp->f_data; - so = kn->kn_fp->f_data; - SOCKBUF_LOCK_ASSERT(&so->so_snd); kn->kn_data = sbspace(&so->so_snd); - if (so->so_snd.sb_state & SBS_CANTSENDMORE) { - kn->kn_flags |= EV_EOF; + if (so->so_state & SS_CANTSENDMORE) { + kn->kn_flags |= EV_EOF; kn->kn_fflags = so->so_error; return (1); - } else if (so->so_error) /* temporary udp error */ + } + if (so->so_error) /* temporary udp error */ return (1); - else if (((so->so_state & SS_ISCONNECTED) == 0) && + if (((so->so_state & SS_ISCONNECTED) == 0) && (so->so_proto->pr_flags & PR_CONNREQUIRED)) return (0); - else if (kn->kn_sfflags & NOTE_LOWAT) + if (kn->kn_sfflags & NOTE_LOWAT) return (kn->kn_data >= kn->kn_sdata); - else - return (kn->kn_data >= so->so_snd.sb_lowat); + return (kn->kn_data >= so->so_snd.sb_lowat); } /*ARGSUSED*/ static int filt_solisten(struct knote *kn, long hint) { - struct socket *so = kn->kn_fp->f_data; + struct socket *so = (struct socket *)kn->kn_fp->f_data; kn->kn_data = so->so_qlen; return (! TAILQ_EMPTY(&so->so_comp)); } - -int -socheckuid(struct socket *so, uid_t uid) -{ - - if (so == NULL) - return (EPERM); - if (so->so_cred->cr_uid != uid) - return (EPERM); - return (0); -} - -static int -somaxconn_sysctl(SYSCTL_HANDLER_ARGS) -{ - int error; - int val; - - val = somaxconn; - error = sysctl_handle_int(oidp, &val, sizeof(int), req); - if (error || !req->newptr ) - return (error); - - if (val < 1 || val > USHRT_MAX) - return (EINVAL); - - somaxconn = val; - return (0); -} |