summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorscottl <scottl@FreeBSD.org>2005-06-09 19:56:38 +0000
committerscottl <scottl@FreeBSD.org>2005-06-09 19:56:38 +0000
commit6be4cb00a414f098d88dc8554c3daee743124744 (patch)
tree23a647623e2274c2bbbfebca501e980c86f0155e /sys
parent1d3209ab83aac3089f15e00934e922d222a4ecf0 (diff)
downloadFreeBSD-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.c1470
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 = &top;
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 = &top;
- 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);
-}
OpenPOWER on IntegriCloud