From 243917fe3b5e36464ab72473e872da9acd44aa1c Mon Sep 17 00:00:00 2001 From: Seigo Tanimura Date: Mon, 20 May 2002 05:41:09 +0000 Subject: [PATCH] Lock down a socket, milestone 1. o Add a mutex (sb_mtx) to struct sockbuf. This protects the data in a socket buffer. The mutex in the receive buffer also protects the data in struct socket. o Determine the lock strategy for each members in struct socket. o Lock down the following members: - so_count - so_options - so_linger - so_state o Remove *_locked() socket APIs. Make the following socket APIs touching the members above now require a locked socket: - sodisconnect() - soisconnected() - soisconnecting() - soisdisconnected() - soisdisconnecting() - sofree() - soref() - sorele() - sorwakeup() - sotryfree() - sowakeup() - sowwakeup() Reviewed by: alfred --- sys/compat/svr4/svr4_filio.c | 16 +- sys/compat/svr4/svr4_ioctl.c | 17 ++- sys/fs/fifofs/fifo_vnops.c | 32 +++- sys/fs/portalfs/portal_vnops.c | 33 ++-- sys/kern/kern_descrip.c | 7 +- sys/kern/sys_socket.c | 8 + sys/kern/uipc_domain.c | 8 +- sys/kern/uipc_sockbuf.c | 133 ++++++++-------- sys/kern/uipc_socket.c | 208 ++++++++++++++++++++++---- sys/kern/uipc_socket2.c | 133 ++++++++-------- sys/kern/uipc_syscalls.c | 37 ++++- sys/kern/uipc_usrreq.c | 35 ++++- sys/kern/vfs_aio.c | 3 + sys/net/raw_cb.c | 13 +- sys/net/raw_usrreq.c | 10 ++ sys/net/rtsock.c | 9 +- sys/netatalk/ddp_input.c | 2 + sys/netatalk/ddp_pcb.c | 10 +- sys/netatalk/ddp_usrreq.c | 10 +- sys/netatm/atm_aal5.c | 15 +- sys/netatm/atm_socket.c | 21 ++- sys/netgraph/ng_ksocket.c | 60 ++++++-- sys/netgraph/ng_socket.c | 16 ++ sys/netinet/accf_data.c | 10 +- sys/netinet/accf_http.c | 31 +++- sys/netinet/in_pcb.c | 81 ++++++---- sys/netinet/ip_divert.c | 21 ++- sys/netinet/ip_input.c | 5 +- sys/netinet/ip_mroute.c | 2 + sys/netinet/raw_ip.c | 52 +++++-- sys/netinet/tcp_input.c | 102 +++++++++++-- sys/netinet/tcp_output.c | 17 ++- sys/netinet/tcp_reass.c | 102 +++++++++++-- sys/netinet/tcp_subr.c | 14 +- sys/netinet/tcp_timer.c | 68 ++++++--- sys/netinet/tcp_timewait.c | 14 +- sys/netinet/tcp_usrreq.c | 63 ++++++-- sys/netinet/udp_usrreq.c | 41 ++++- sys/netinet6/icmp6.c | 10 +- sys/netinet6/in6_pcb.c | 68 ++++++--- sys/netinet6/in6_src.c | 2 + sys/netinet6/ip6_input.c | 5 +- sys/netinet6/ip6_mroute.c | 2 + sys/netinet6/raw_ip6.c | 45 +++++- sys/netinet6/udp6_usrreq.c | 57 ++++++- sys/netipx/ipx_pcb.c | 18 ++- sys/netipx/ipx_usrreq.c | 31 +++- sys/netipx/spx_usrreq.c | 80 ++++++++-- sys/netkey/keysock.c | 6 +- sys/netnatm/natm.c | 12 ++ sys/netncp/ncp_sock.c | 5 +- sys/netns/idp_usrreq.c | 34 ++++- sys/netns/ns.c | 6 +- sys/netns/ns_pcb.c | 24 ++- sys/netns/spp_usrreq.c | 89 +++++++++-- sys/netsmb/smb_trantcp.c | 10 +- sys/nfsclient/bootp_subr.c | 7 +- sys/nfsclient/nfs_socket.c | 19 ++- sys/nfsserver/nfs_srvsock.c | 8 +- sys/security/lomac/kernel_interface.c | 11 +- sys/security/lomac/kernel_socket.c | 62 ++++++-- sys/sys/socketvar.h | 161 +++++++++++--------- 62 files changed, 1720 insertions(+), 511 deletions(-) diff --git a/sys/compat/svr4/svr4_filio.c b/sys/compat/svr4/svr4_filio.c index ef9b8b67c8d1..5527716204ee 100644 --- a/sys/compat/svr4/svr4_filio.c +++ b/sys/compat/svr4/svr4_filio.c @@ -116,15 +116,17 @@ svr4_sys_read(td, uap) if (fp->f_type == DTYPE_SOCKET) { so = (struct socket *)fp->f_data; - DPRINTF(("fd %d is a socket\n", SCARG(uap, fd))); - if (so->so_state & SS_ASYNC) { - DPRINTF(("fd %d is an ASYNC socket!\n", SCARG(uap, fd))); - } - DPRINTF(("Here are its flags: 0x%x\n", so->so_state)); -#if defined(GROTTY_READ_HACK) + SOCK_LOCK(so); so_state = so->so_state; +#if defined(GROTTY_READ_HACK) so->so_state &= ~SS_NBIO; #endif + SOCK_UNLOCK(so); + DPRINTF(("fd %d is a socket\n", SCARG(uap, fd))); + if (so_state & SS_ASYNC) { + DPRINTF(("fd %d is an ASYNC socket!\n", SCARG(uap, fd))); + } + DPRINTF(("Here are its flags: 0x%x\n", so_state)); } rv = read(td, &ra); @@ -140,7 +142,9 @@ svr4_sys_read(td, uap) #if defined(GROTTY_READ_HACK) if (so) { /* We've already checked to see if this is a socket */ + SOCK_LOCK(so); so->so_state = so_state; + SOCK_UNLOCK(so); } #endif fdrop(fp, td); diff --git a/sys/compat/svr4/svr4_ioctl.c b/sys/compat/svr4/svr4_ioctl.c index 50d28ee55bde..d84e89c546a1 100644 --- a/sys/compat/svr4/svr4_ioctl.c +++ b/sys/compat/svr4/svr4_ioctl.c @@ -29,10 +29,12 @@ */ #include -#include +#include #include #include -#include +#include +#include +#include #include #include #include @@ -93,6 +95,7 @@ svr4_sys_ioctl(td, uap) char c; int num; int argsiz; + int sostate; svr4_decode_cmd(SCARG(uap, com), dir, &c, &num, &argsiz); @@ -113,7 +116,10 @@ svr4_sys_ioctl(td, uap) #if defined(DEBUG_SVR4) if (fp->f_type == DTYPE_SOCKET) { struct socket *so = (struct socket *)fp->f_data; - DPRINTF(("<<< IN: so_state = 0x%x\n", so->so_state)); + SOCK_LOCK(so); + sostate = so->so_state; + SOCK_UNLOCK(so); + DPRINTF(("<<< IN: so_state = 0x%x\n", sostate)); } #endif @@ -158,7 +164,10 @@ svr4_sys_ioctl(td, uap) struct socket *so; so = (struct socket *)fp->f_data; - DPRINTF((">>> OUT: so_state = 0x%x\n", so->so_state)); + SOCK_LOCK(so); + sostate = so->so_state; + SOCK_UNLOCK(so); + DPRINTF((">>> OUT: so_state = 0x%x\n", sostate)); } #endif error = (*fun)(fp, td, retval, SCARG(uap, fd), cmd, SCARG(uap, data)); diff --git a/sys/fs/fifofs/fifo_vnops.c b/sys/fs/fifofs/fifo_vnops.c index 36e8f7cf17ac..71ba03ce2cd5 100644 --- a/sys/fs/fifofs/fifo_vnops.c +++ b/sys/fs/fifofs/fifo_vnops.c @@ -203,26 +203,32 @@ fifo_open(ap) } fip->fi_readers = fip->fi_writers = 0; wso->so_snd.sb_lowat = PIPE_BUF; + SOCK_LOCK(rso); rso->so_state |= SS_CANTRCVMORE; + SOCK_UNLOCK(rso); } if (ap->a_mode & FREAD) { fip->fi_readers++; if (fip->fi_readers == 1) { + SOCK_LOCK(fip->fi_writesock); fip->fi_writesock->so_state &= ~SS_CANTSENDMORE; if (fip->fi_writers > 0) { wakeup((caddr_t)&fip->fi_writers); sowwakeup(fip->fi_writesock); } + SOCK_UNLOCK(fip->fi_writesock); } } if (ap->a_mode & FWRITE) { fip->fi_writers++; if (fip->fi_writers == 1) { + SOCK_LOCK(fip->fi_readsock); fip->fi_readsock->so_state &= ~SS_CANTRCVMORE; if (fip->fi_readers > 0) { wakeup((caddr_t)&fip->fi_readers); sorwakeup(fip->fi_writesock); } + SOCK_UNLOCK(fip->fi_readsock); } } if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) { @@ -282,15 +288,21 @@ fifo_read(ap) #endif if (uio->uio_resid == 0) return (0); - if (ap->a_ioflag & IO_NDELAY) + if (ap->a_ioflag & IO_NDELAY) { + SOCK_LOCK(rso); rso->so_state |= SS_NBIO; + SOCK_UNLOCK(rso); + } startresid = uio->uio_resid; VOP_UNLOCK(ap->a_vp, 0, td); error = soreceive(rso, (struct sockaddr **)0, uio, (struct mbuf **)0, (struct mbuf **)0, (int *)0); vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, td); - if (ap->a_ioflag & IO_NDELAY) + if (ap->a_ioflag & IO_NDELAY) { + SOCK_LOCK(rso); rso->so_state &= ~SS_NBIO; + SOCK_UNLOCK(rso); + } return (error); } @@ -315,14 +327,20 @@ fifo_write(ap) if (ap->a_uio->uio_rw != UIO_WRITE) panic("fifo_write mode"); #endif - if (ap->a_ioflag & IO_NDELAY) + if (ap->a_ioflag & IO_NDELAY) { + SOCK_LOCK(wso); wso->so_state |= SS_NBIO; + SOCK_UNLOCK(wso); + } VOP_UNLOCK(ap->a_vp, 0, td); error = sosend(wso, (struct sockaddr *)0, ap->a_uio, 0, (struct mbuf *)0, 0, td); vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, td); - if (ap->a_ioflag & IO_NDELAY) + if (ap->a_ioflag & IO_NDELAY) { + SOCK_LOCK(wso); wso->so_state &= ~SS_NBIO; + SOCK_UNLOCK(wso); + } return (error); } @@ -412,10 +430,13 @@ filt_fiforead(struct knote *kn, long hint) struct socket *so = (struct socket *)kn->kn_hook; kn->kn_data = so->so_rcv.sb_cc; + SOCK_LOCK(so); if (so->so_state & SS_CANTRCVMORE) { + SOCK_UNLOCK(so); kn->kn_flags |= EV_EOF; return (1); } + SOCK_UNLOCK(so); kn->kn_flags &= ~EV_EOF; return (kn->kn_data > 0); } @@ -436,10 +457,13 @@ filt_fifowrite(struct knote *kn, long hint) struct socket *so = (struct socket *)kn->kn_hook; kn->kn_data = sbspace(&so->so_snd); + SOCK_LOCK(so); if (so->so_state & SS_CANTSENDMORE) { + SOCK_UNLOCK(so); kn->kn_flags |= EV_EOF; return (1); } + SOCK_UNLOCK(so); kn->kn_flags &= ~EV_EOF; return (kn->kn_data >= so->so_snd.sb_lowat); } diff --git a/sys/fs/portalfs/portal_vnops.c b/sys/fs/portalfs/portal_vnops.c index b345c573d4be..23b471f7b381 100644 --- a/sys/fs/portalfs/portal_vnops.c +++ b/sys/fs/portalfs/portal_vnops.c @@ -43,24 +43,26 @@ */ #include -#include -#include -#include -#include -#include -#include -#include #include #include -#include -#include +#include +#include +#include #include -#include #include +#include +#include +#include +#include #include #include +#include +#include +#include +#include #include #include +#include #include static int portal_fileid = PORTAL_ROOTFILEID+1; @@ -182,8 +184,12 @@ portal_connect(so, so2) if (so->so_type != so2->so_type) return (EPROTOTYPE); - if ((so2->so_options & SO_ACCEPTCONN) == 0) + SOCK_LOCK(so2); + if ((so2->so_options & SO_ACCEPTCONN) == 0) { + SOCK_UNLOCK(so2); return (ECONNREFUSED); + } + SOCK_UNLOCK(so2); if ((so3 = sonewconn(so2, 0)) == 0) return (ECONNREFUSED); @@ -280,14 +286,17 @@ portal_open(ap) * and keep polling the reference count. XXX. */ s = splnet(); + SOCK_LOCK(so); while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { if (fmp->pm_server->f_count == 1) { + SOCK_UNLOCK(so); error = ECONNREFUSED; splx(s); goto bad; } - (void) tsleep((caddr_t) &so->so_timeo, PSOCK, "portalcon", 5 * hz); + (void) msleep((caddr_t) &so->so_timeo, SOCK_MTX(so), PSOCK, "portalcon", 5 * hz); } + SOCK_UNLOCK(so); splx(s); if (so->so_error) { diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 15837d304e8d..8a6176dac751 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -1777,19 +1777,22 @@ fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp) *spp = (struct socket *)fp->f_data; if (fflagp) *fflagp = fp->f_flag; + SOCK_LOCK(*spp); soref(*spp); + SOCK_UNLOCK(*spp); } FILEDESC_UNLOCK(td->td_proc->p_fd); return(error); } /* - * Drop the reference count on the the socket and XXX release the SX lock in - * the future. The last reference closes the socket. + * Drop the reference count on the the socket and release the lock. + * The last reference closes the socket. The socket must be unlocked. */ void fputsock(struct socket *so) { + SOCK_LOCK(so); sorele(so); } diff --git a/sys/kern/sys_socket.c b/sys/kern/sys_socket.c index c8a6198def6b..6c1a23c1500c 100644 --- a/sys/kern/sys_socket.c +++ b/sys/kern/sys_socket.c @@ -104,13 +104,16 @@ soo_ioctl(fp, cmd, data, td) switch (cmd) { case FIONBIO: + SOCK_LOCK(so); if (*(int *)data) so->so_state |= SS_NBIO; else so->so_state &= ~SS_NBIO; + SOCK_UNLOCK(so); return (0); case FIOASYNC: + SOCK_LOCK(so); if (*(int *)data) { so->so_state |= SS_ASYNC; so->so_rcv.sb_flags |= SB_ASYNC; @@ -120,6 +123,7 @@ soo_ioctl(fp, cmd, data, td) so->so_rcv.sb_flags &= ~SB_ASYNC; so->so_snd.sb_flags &= ~SB_ASYNC; } + SOCK_UNLOCK(so); return (0); case FIONREAD: @@ -141,7 +145,9 @@ soo_ioctl(fp, cmd, data, td) return (0); case SIOCATMARK: + SOCK_LOCK(so); *(int *)data = (so->so_state&SS_RCVATMARK) != 0; + SOCK_UNLOCK(so); return (0); } /* @@ -181,11 +187,13 @@ soo_stat(fp, ub, td) * If SS_CANTRCVMORE is set, but there's still data left in the * receive buffer, the socket is still readable. */ + SOCK_LOCK(so); if ((so->so_state & SS_CANTRCVMORE) == 0 || so->so_rcv.sb_cc != 0) ub->st_mode |= S_IRUSR | S_IRGRP | S_IROTH; if ((so->so_state & SS_CANTSENDMORE) == 0) ub->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH; + SOCK_UNLOCK(so); ub->st_size = so->so_rcv.sb_cc; ub->st_uid = so->so_cred->cr_uid; ub->st_gid = so->so_cred->cr_gid; diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c index b8321eba4fb4..cfb77687e225 100644 --- a/sys/kern/uipc_domain.c +++ b/sys/kern/uipc_domain.c @@ -35,11 +35,13 @@ */ #include -#include -#include #include -#include #include +#include +#include +#include +#include +#include #include #include #include diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c index 34779f84aac0..c395d878b8eb 100644 --- a/sys/kern/uipc_sockbuf.c +++ b/sys/kern/uipc_sockbuf.c @@ -102,71 +102,56 @@ soisconnecting(so) register struct socket *so; { + SOCK_ASSERT(so, MA_OWNED); so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); so->so_state |= SS_ISCONNECTING; } -void -soisconnected_locked(so) - struct socket *so; -{ - struct socket *head = so->so_head; - - so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); - so->so_state |= SS_ISCONNECTED; - if (head && (so->so_state & SS_INCOMP)) { - if ((so->so_options & SO_ACCEPTFILTER) != 0) { - so->so_upcall = head->so_accf->so_accept_filter->accf_callback; - so->so_upcallarg = head->so_accf->so_accept_filter_arg; - so->so_rcv.sb_flags |= SB_UPCALL; - so->so_options &= ~SO_ACCEPTFILTER; - so->so_upcall(so, so->so_upcallarg, 0); - return; - } - TAILQ_REMOVE(&head->so_incomp, so, so_list); - head->so_incqlen--; - so->so_state &= ~SS_INCOMP; - TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); - head->so_qlen++; - so->so_state |= SS_COMP; - sorwakeup_locked(head); - wakeup_one(&head->so_timeo); - } else { - wakeup(&so->so_timeo); - sorwakeup_locked(so); - sowwakeup_locked(so); - } -} - void soisconnected(so) struct socket *so; { - struct socket *head = so->so_head; + struct socket *head; + so_upcall_t *upcp; + void *upcarg; + SOCK_ASSERT(so, MA_OWNED); + head = so->so_head; so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); so->so_state |= SS_ISCONNECTED; if (head && (so->so_state & SS_INCOMP)) { if ((so->so_options & SO_ACCEPTFILTER) != 0) { - so->so_upcall = head->so_accf->so_accept_filter->accf_callback; - so->so_upcallarg = head->so_accf->so_accept_filter_arg; + SOCK_UNLOCK(so); + SOCK_LOCK(head); + upcp = head->so_accf->so_accept_filter->accf_callback; + upcarg = head->so_accf->so_accept_filter_arg; + SOCK_UNLOCK(head); + SOCK_LOCK(so); + so->so_upcall = upcp; + so->so_upcallarg = upcarg; so->so_rcv.sb_flags |= SB_UPCALL; so->so_options &= ~SO_ACCEPTFILTER; - so->so_upcall(so, so->so_upcallarg, 0); + SOCK_UNLOCK(so); + so->so_upcall(so, upcarg, 0); + SOCK_LOCK(so); return; } + so->so_state &= ~SS_INCOMP; + so->so_state |= SS_COMP; + SOCK_UNLOCK(so); + SOCK_LOCK(head); TAILQ_REMOVE(&head->so_incomp, so, so_list); head->so_incqlen--; - so->so_state &= ~SS_INCOMP; TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); head->so_qlen++; - so->so_state |= SS_COMP; - sorwakeup_locked(head); + sorwakeup(head); wakeup_one(&head->so_timeo); + SOCK_UNLOCK(head); + SOCK_LOCK(so); } else { wakeup(&so->so_timeo); - sorwakeup_locked(so); - sowwakeup_locked(so); + sorwakeup(so); + sowwakeup(so); } } @@ -175,23 +160,12 @@ soisdisconnecting(so) register struct socket *so; { + SOCK_ASSERT(so, MA_OWNED); so->so_state &= ~SS_ISCONNECTING; so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE); wakeup((caddr_t)&so->so_timeo); - sowwakeup_locked(so); - sorwakeup_locked(so); -} - -void -soisdisconnected_locked(so) - register struct socket *so; -{ - - so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); - so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED); - wakeup((caddr_t)&so->so_timeo); - sowwakeup_locked(so); - sorwakeup_locked(so); + sowwakeup(so); + sorwakeup(so); } void @@ -199,7 +173,12 @@ soisdisconnected(so) register struct socket *so; { - soisdisconnected_locked(so); + SOCK_ASSERT(so, MA_OWNED); + so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); + so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED); + wakeup((caddr_t)&so->so_timeo); + sowwakeup(so); + sorwakeup(so); } /* @@ -224,25 +203,32 @@ sonewconn(head, connstatus) so = soalloc(0); if (so == NULL) return ((struct socket *)0); + SOCK_LOCK(head); if ((head->so_options & SO_ACCEPTFILTER) != 0) connstatus = 0; + SOCK_UNLOCK(head); so->so_head = head; so->so_type = head->so_type; + SOCK_LOCK(so); so->so_options = head->so_options &~ SO_ACCEPTCONN; so->so_linger = head->so_linger; so->so_state = head->so_state | SS_NOFDREF; + SOCK_UNLOCK(so); so->so_proto = head->so_proto; so->so_timeo = head->so_timeo; so->so_cred = crhold(head->so_cred); if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat) || (*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) { + SOCK_LOCK(so); sotryfree(so); return ((struct socket *)0); } if (connstatus) { TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); + SOCK_LOCK(so); so->so_state |= SS_COMP; + SOCK_UNLOCK(so); head->so_qlen++; } else { if (head->so_incqlen >= head->so_qlimit) { @@ -251,13 +237,19 @@ sonewconn(head, connstatus) (void) soabort(sp); } TAILQ_INSERT_TAIL(&head->so_incomp, so, so_list); + SOCK_LOCK(so); so->so_state |= SS_INCOMP; + SOCK_UNLOCK(so); head->so_incqlen++; } if (connstatus) { - sorwakeup_locked(head); + SOCK_LOCK(head); + sorwakeup(head); wakeup((caddr_t)&head->so_timeo); + SOCK_UNLOCK(head); + SOCK_LOCK(so); so->so_state |= connstatus; + SOCK_UNLOCK(so); } return (so); } @@ -277,8 +269,10 @@ socantsendmore(so) struct socket *so; { + SOCK_LOCK(so); so->so_state |= SS_CANTSENDMORE; - sowwakeup_locked(so); + sowwakeup(so); + SOCK_UNLOCK(so); } void @@ -286,8 +280,10 @@ socantrcvmore(so) struct socket *so; { + SOCK_LOCK(so); so->so_state |= SS_CANTRCVMORE; - sorwakeup_locked(so); + sorwakeup(so); + SOCK_UNLOCK(so); } /* @@ -336,6 +332,7 @@ sowakeup(so, sb) register struct socket *so; register struct sockbuf *sb; { + SOCK_ASSERT(so, MA_OWNED); selwakeup(&sb->sb_sel); sb->sb_flags &= ~SB_SEL; @@ -343,13 +340,23 @@ sowakeup(so, sb) sb->sb_flags &= ~SB_WAIT; wakeup((caddr_t)&sb->sb_cc); } - if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL) + if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL) { + SOCK_UNLOCK(so); pgsigio(&so->so_sigio, SIGIO, 0); - if (sb->sb_flags & SB_UPCALL) + SOCK_LOCK(so); + } + if (sb->sb_flags & SB_UPCALL) { + SOCK_UNLOCK(so); (*so->so_upcall)(so, so->so_upcallarg, M_DONTWAIT); - if (sb->sb_flags & SB_AIO) + SOCK_LOCK(so); + } + if (sb->sb_flags & SB_AIO) { + SOCK_UNLOCK(so); aio_swake(so, sb); + } else + SOCK_UNLOCK(so); KNOTE(&sb->sb_sel.si_note, 0); + SOCK_LOCK(so); } /* @@ -959,9 +966,11 @@ sotoxsocket(struct socket *so, struct xsocket *xso) xso->xso_len = sizeof *xso; xso->xso_so = so; xso->so_type = so->so_type; + SOCK_LOCK(so); xso->so_options = so->so_options; xso->so_linger = so->so_linger; xso->so_state = so->so_state; + SOCK_UNLOCK(so); xso->so_pcb = so->so_pcb; xso->xso_protocol = so->so_proto->pr_protocol; xso->xso_family = so->so_proto->pr_domain->dom_family; diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 4bbc6e259ed4..cc63c31684e5 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -82,6 +82,7 @@ static struct filterops sowrite_filtops = uma_zone_t socket_zone; so_gen_t so_gencnt; /* generation count for sockets */ +struct mtx socq_lock; MALLOC_DEFINE(M_SONAME, "soname", "socket name"); MALLOC_DEFINE(M_PCB, "pcb", "protocol control block"); @@ -129,7 +130,8 @@ soalloc(waitok) /* XXX race condition for reentrant kernel */ bzero(so, sizeof *so); so->so_gencnt = ++so_gencnt; - /* sx_init(&so->so_sxlock, "socket sxlock"); */ + mtx_init(&so->so_rcv.sb_mtx, "sockbuf rcv", NULL, MTX_DEF); + mtx_init(&so->so_snd.sb_mtx, "sockbuf snd", NULL, MTX_DEF); TAILQ_INIT(&so->so_aiojobq); ++numopensockets; } @@ -174,14 +176,17 @@ socreate(dom, aso, type, proto, cred, td) if (so == 0) return (ENOBUFS); + SOCK_LOCK(so); TAILQ_INIT(&so->so_incomp); TAILQ_INIT(&so->so_comp); so->so_type = type; so->so_cred = crhold(cred); so->so_proto = prp; soref(so); + SOCK_UNLOCK(so); error = (*prp->pr_usrreqs->pru_attach)(so, proto, td); if (error) { + SOCK_LOCK(so); so->so_state |= SS_NOFDREF; sorele(so); return (error); @@ -208,7 +213,9 @@ static void sodealloc(struct socket *so) { + SOCK_LOCK(so); KASSERT(so->so_count == 0, ("sodealloc(): so_count %d", so->so_count)); + SOCK_UNLOCK(so); so->so_gencnt = ++so_gencnt; if (so->so_rcv.sb_hiwat) (void)chgsbsize(so->so_cred->cr_uidinfo, @@ -228,7 +235,8 @@ sodealloc(struct socket *so) } #endif crfree(so->so_cred); - /* sx_destroy(&so->so_sxlock); */ + mtx_destroy(&so->so_rcv.sb_mtx); + mtx_destroy(&so->so_snd.sb_mtx); uma_zfree(socket_zone, so); --numopensockets; } @@ -247,8 +255,11 @@ solisten(so, backlog, td) splx(s); return (error); } - if (TAILQ_EMPTY(&so->so_comp)) + if (TAILQ_EMPTY(&so->so_comp)) { + SOCK_LOCK(so); so->so_options |= SO_ACCEPTCONN; + SOCK_UNLOCK(so); + } if (backlog < 0 || backlog > somaxconn) backlog = somaxconn; so->so_qlimit = backlog; @@ -262,15 +273,21 @@ sofree(so) { struct socket *head = so->so_head; + SOCK_ASSERT(so, MA_OWNED); + KASSERT(so->so_count == 0, ("socket %p so_count not 0", so)); - if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) + if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) { + SOCK_UNLOCK(so); return; + } if (head != NULL) { if (so->so_state & SS_INCOMP) { + SOCK_UNLOCK(so); TAILQ_REMOVE(&head->so_incomp, so, so_list); head->so_incqlen--; } else if (so->so_state & SS_COMP) { + SOCK_UNLOCK(so); /* * We must not decommission a socket that's * on the accept(2) queue. If we do, then @@ -279,11 +296,15 @@ sofree(so) */ return; } else { + SOCK_UNLOCK(so); panic("sofree: not queued"); } + SOCK_LOCK(so); so->so_state &= ~SS_INCOMP; + SOCK_UNLOCK(so); so->so_head = NULL; - } + } else + SOCK_UNLOCK(so); sbrelease(&so->so_snd, so); sorflush(so); sodealloc(so); @@ -306,9 +327,11 @@ soclose(so) int error = 0; funsetown(&so->so_sigio); + SOCK_LOCK(so); if (so->so_options & SO_ACCEPTCONN) { struct socket *sp, *sonext; + SOCK_UNLOCK(so); sp = TAILQ_FIRST(&so->so_incomp); for (; sp != NULL; sp = sonext) { sonext = TAILQ_NEXT(sp, so_list); @@ -319,38 +342,49 @@ soclose(so) /* Dequeue from so_comp since sofree() won't do it */ TAILQ_REMOVE(&so->so_comp, sp, so_list); so->so_qlen--; + SOCK_LOCK(sp); sp->so_state &= ~SS_COMP; + SOCK_UNLOCK(sp); sp->so_head = NULL; (void) soabort(sp); } + SOCK_LOCK(so); } if (so->so_pcb == 0) goto discard; if (so->so_state & SS_ISCONNECTED) { if ((so->so_state & SS_ISDISCONNECTING) == 0) { error = sodisconnect(so); - if (error) + if (error) { + SOCK_UNLOCK(so); goto drop; + } } if (so->so_options & SO_LINGER) { if ((so->so_state & SS_ISDISCONNECTING) && - (so->so_state & SS_NBIO)) + (so->so_state & SS_NBIO)) { + SOCK_UNLOCK(so); goto drop; + } while (so->so_state & SS_ISCONNECTED) { - error = tsleep((caddr_t)&so->so_timeo, + error = msleep((caddr_t)&so->so_timeo, SOCK_MTX(so), PSOCK | PCATCH, "soclos", so->so_linger * hz); if (error) break; } } } + SOCK_UNLOCK(so); drop: + SOCK_ASSERT(so, MA_NOTOWNED); if (so->so_pcb) { int error2 = (*so->so_proto->pr_usrreqs->pru_detach)(so); if (error == 0) error = error2; } + SOCK_LOCK(so); discard: + SOCK_ASSERT(so, MA_OWNED); if (so->so_state & SS_NOFDREF) panic("soclose: NOFDREF"); so->so_state |= SS_NOFDREF; @@ -370,6 +404,7 @@ soabort(so) error = (*so->so_proto->pr_usrreqs->pru_abort)(so); if (error) { + SOCK_LOCK(so); sotryfree(so); /* note: does not decrement the ref count */ return error; } @@ -384,9 +419,11 @@ soaccept(so, nam) int s = splnet(); int error; + SOCK_LOCK(so); 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); @@ -401,8 +438,11 @@ soconnect(so, nam, td) int s; int error; - if (so->so_options & SO_ACCEPTCONN) + SOCK_LOCK(so); + if (so->so_options & SO_ACCEPTCONN) { + SOCK_UNLOCK(so); return (EOPNOTSUPP); + } s = splnet(); /* * If protocol is connection-based, can only connect once. @@ -410,12 +450,23 @@ soconnect(so, nam, td) * This allows user to disconnect by connecting to, e.g., * a null address. */ - if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && - ((so->so_proto->pr_flags & PR_CONNREQUIRED) || - (error = sodisconnect(so)))) - error = EISCONN; - else - error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam, td); + if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { + if (so->so_proto->pr_flags & PR_CONNREQUIRED) { + SOCK_UNLOCK(so); + error = EISCONN; + goto done; + } else { + error = sodisconnect(so); + if (error) { + SOCK_UNLOCK(so); + error = EISCONN; + goto done; + } + } + } + SOCK_UNLOCK(so); + error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam, td); +done: splx(s); return (error); } @@ -440,6 +491,7 @@ sodisconnect(so) int s = splnet(); int error; + SOCK_ASSERT(so, MA_OWNED); if ((so->so_state & SS_ISCONNECTED) == 0) { error = ENOTCONN; goto bad; @@ -448,7 +500,9 @@ sodisconnect(so) error = EALREADY; goto bad; } + SOCK_UNLOCK(so); error = (*so->so_proto->pr_usrreqs->pru_disconnect)(so); + SOCK_LOCK(so); bad: splx(s); return (error); @@ -507,14 +561,22 @@ sosend(so, addr, uio, top, control, flags, td) goto out; } + SOCK_LOCK(so); dontroute = (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && (so->so_proto->pr_flags & PR_ATOMIC); + SOCK_UNLOCK(so); if (td) td->td_proc->p_stats->p_ru.ru_msgsnd++; if (control) clen = control->m_len; -#define snderr(errno) { error = errno; splx(s); goto release; } +#define snderr(errno) \ + do { \ + error = errno; \ + SOCK_UNLOCK(so); \ + splx(s); \ + goto release; \ + } while(0); restart: error = sblock(&so->so_snd, SBLOCKWAIT(flags)); @@ -522,11 +584,13 @@ sosend(so, addr, uio, top, control, flags, td) goto out; do { s = splnet(); + SOCK_LOCK(so); if (so->so_state & SS_CANTSENDMORE) snderr(EPIPE); if (so->so_error) { error = so->so_error; so->so_error = 0; + SOCK_UNLOCK(so); splx(s); goto release; } @@ -546,16 +610,21 @@ sosend(so, addr, uio, top, control, flags, td) snderr(so->so_proto->pr_flags & PR_CONNREQUIRED ? ENOTCONN : EDESTADDRREQ); } + SOCK_UNLOCK(so); space = sbspace(&so->so_snd); if (flags & MSG_OOB) space += 1024; if ((atomic && resid > so->so_snd.sb_hiwat) || - clen > so->so_snd.sb_hiwat) + clen > so->so_snd.sb_hiwat) { + SOCK_LOCK(so); snderr(EMSGSIZE); + } if (space < resid + clen && (atomic || space < so->so_snd.sb_lowat || space < clen)) { + SOCK_LOCK(so); if (so->so_state & SS_NBIO) snderr(EWOULDBLOCK); + SOCK_UNLOCK(so); sbunlock(&so->so_snd); error = sbwait(&so->so_snd); splx(s); @@ -623,8 +692,11 @@ sosend(so, addr, uio, top, control, flags, td) break; } } while (space > 0 && atomic); - if (dontroute) + if (dontroute) { + SOCK_LOCK(so); so->so_options |= SO_DONTROUTE; + SOCK_UNLOCK(so); + } s = splnet(); /* XXX */ /* * XXX all the SS_CANTSENDMORE checks previously @@ -650,8 +722,11 @@ sosend(so, addr, uio, top, control, flags, td) (resid > 0 && space > 0) ? PRUS_MORETOCOME : 0, top, addr, control, td); splx(s); - if (dontroute) + if (dontroute) { + SOCK_LOCK(so); so->so_options &= ~SO_DONTROUTE; + SOCK_UNLOCK(so); + } clen = 0; control = 0; top = 0; @@ -731,10 +806,15 @@ soreceive(so, psa, uio, mp0, controlp, flagsp) } if (mp) *mp = (struct mbuf *)0; - if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) + SOCK_LOCK(so); + if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) { + SOCK_UNLOCK(so); (*pr->pr_usrreqs->pru_rcvd)(so, 0); + } else + SOCK_UNLOCK(so); restart: + SOCK_ASSERT(so, MA_NOTOWNED); error = sblock(&so->so_rcv, SBLOCKWAIT(flags)); if (error) return (error); @@ -768,28 +848,37 @@ soreceive(so, psa, uio, mp0, controlp, flagsp) so->so_error = 0; goto release; } + SOCK_LOCK(so); if (so->so_state & SS_CANTRCVMORE) { + SOCK_UNLOCK(so); if (m) goto dontblock; else goto release; } + SOCK_UNLOCK(so); 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; } + SOCK_LOCK(so); if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && (so->so_proto->pr_flags & PR_CONNREQUIRED)) { + SOCK_UNLOCK(so); error = ENOTCONN; goto release; } - if (uio->uio_resid == 0) + if (uio->uio_resid == 0) { + SOCK_UNLOCK(so); goto release; + } if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) { + SOCK_UNLOCK(so); error = EWOULDBLOCK; goto release; } + SOCK_UNLOCK(so); sbunlock(&so->so_rcv); error = sbwait(&so->so_rcv); splx(s); @@ -859,7 +948,9 @@ soreceive(so, psa, uio, mp0, controlp, flagsp) else KASSERT(m->m_type == MT_DATA || m->m_type == MT_HEADER, ("m->m_type == %d", m->m_type)); + SOCK_LOCK(so); so->so_state &= ~SS_RCVATMARK; + SOCK_UNLOCK(so); len = uio->uio_resid; if (so->so_oobmark && len > so->so_oobmark - offset) len = so->so_oobmark - offset; @@ -917,7 +1008,9 @@ soreceive(so, psa, uio, mp0, controlp, flagsp) if ((flags & MSG_PEEK) == 0) { so->so_oobmark -= len; if (so->so_oobmark == 0) { + SOCK_LOCK(so); so->so_state |= SS_RCVATMARK; + SOCK_UNLOCK(so); break; } } else { @@ -937,8 +1030,12 @@ soreceive(so, psa, uio, mp0, controlp, flagsp) */ while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 && !sosendallatonce(so) && !nextrecord) { - if (so->so_error || so->so_state & SS_CANTRCVMORE) + SOCK_LOCK(so); + if (so->so_error || so->so_state & SS_CANTRCVMORE) { + SOCK_UNLOCK(so); break; + } + SOCK_UNLOCK(so); /* * Notify the protocol that some data has been * drained before blocking. @@ -968,12 +1065,15 @@ soreceive(so, psa, uio, mp0, controlp, flagsp) if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) (*pr->pr_usrreqs->pru_rcvd)(so, flags); } + SOCK_LOCK(so); if (orig_resid == uio->uio_resid && orig_resid && (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { + SOCK_UNLOCK(so); sbunlock(&so->so_rcv); splx(s); goto restart; } + SOCK_UNLOCK(so); if (flagsp) *flagsp |= flags; @@ -1015,7 +1115,10 @@ sorflush(so) socantrcvmore(so); sbunlock(sb); asb = *sb; - bzero((caddr_t)sb, sizeof (*sb)); +#define RANGEOF(type, start, end) (offsetof(type, end) - offsetof(type, start)) + bzero((caddr_t)&sb->sb_startzero, + (unsigned) RANGEOF(struct sockbuf, sb_startzero, sb_endzero)); +#undef RANGEOF splx(s); if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) (*pr->pr_domain->dom_dispose)(asb.sb_mb); @@ -1034,10 +1137,13 @@ do_setopt_accept_filter(so, sopt) int error = 0; /* do not set/remove accept filters on non listen sockets */ + SOCK_LOCK(so); if ((so->so_options & SO_ACCEPTCONN) == 0) { + SOCK_UNLOCK(so); error = EINVAL; goto out; } + SOCK_UNLOCK(so); /* removing the filter */ if (sopt == NULL) { @@ -1052,7 +1158,9 @@ do_setopt_accept_filter(so, sopt) FREE(af, M_ACCF); so->so_accf = NULL; } + SOCK_LOCK(so); so->so_options &= ~SO_ACCEPTFILTER; + SOCK_UNLOCK(so); return (0); } /* adding a filter */ @@ -1092,7 +1200,9 @@ do_setopt_accept_filter(so, sopt) } af->so_accept_filter = afp; so->so_accf = af; + SOCK_LOCK(so); so->so_options |= SO_ACCEPTFILTER; + SOCK_UNLOCK(so); out: if (afap != NULL) FREE(afap, M_TEMP); @@ -1164,11 +1274,13 @@ sosetopt(so, sopt) 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: @@ -1184,10 +1296,12 @@ sosetopt(so, sopt) 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: @@ -1334,23 +1448,30 @@ sogetopt(so, sopt) switch (sopt->sopt_name) { #ifdef INET case SO_ACCEPTFILTER: - if ((so->so_options & SO_ACCEPTCONN) == 0) - return (EINVAL); MALLOC(afap, struct accept_filter_arg *, sizeof(*afap), M_TEMP, M_WAITOK | M_ZERO); + SOCK_LOCK(so); + if ((so->so_options & SO_ACCEPTCONN) == 0) { + SOCK_UNLOCK(so); + FREE(afap, M_TEMP); + return (EINVAL); + } 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); } + SOCK_UNLOCK(so); error = sooptcopyout(sopt, afap, sizeof(*afap)); FREE(afap, M_TEMP); break; #endif 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; @@ -1363,7 +1484,9 @@ sogetopt(so, sopt) case SO_BROADCAST: case SO_OOBINLINE: case SO_TIMESTAMP: + SOCK_LOCK(so); optval = so->so_options & sopt->sopt_name; + SOCK_UNLOCK(so); integer: error = sooptcopyout(sopt, &optval, sizeof optval); break; @@ -1537,22 +1660,31 @@ sopoll(struct socket *so, int events, struct ucred *cred, struct thread *td) int revents = 0; int s = splnet(); - if (events & (POLLIN | POLLRDNORM)) + if (events & (POLLIN | POLLRDNORM)) { + SOCK_LOCK(so); if (soreadable(so)) revents |= events & (POLLIN | POLLRDNORM); + SOCK_UNLOCK(so); + } 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 (events & (POLLOUT | POLLWRNORM)) { + SOCK_LOCK(so); if (sowriteable(so)) revents |= events & (POLLOUT | POLLWRNORM); + SOCK_UNLOCK(so); + } - if (events & (POLLPRI | POLLRDBAND)) + if (events & (POLLPRI | POLLRDBAND)) { + SOCK_LOCK(so); if (so->so_oobmark || (so->so_state & SS_RCVATMARK)) revents |= events & (POLLPRI | POLLRDBAND); + SOCK_UNLOCK(so); + } if (revents == 0) { if (events & @@ -1581,10 +1713,12 @@ sokqfilter(struct file *fp, struct knote *kn) switch (kn->kn_filter) { case EVFILT_READ: + SOCK_LOCK(so); if (so->so_options & SO_ACCEPTCONN) kn->kn_fop = &solisten_filtops; else kn->kn_fop = &soread_filtops; + SOCK_UNLOCK(so); sb = &so->so_rcv; break; case EVFILT_WRITE: @@ -1621,13 +1755,18 @@ filt_soread(struct knote *kn, long hint) struct socket *so = (struct socket *)kn->kn_fp->f_data; kn->kn_data = so->so_rcv.sb_cc; + SOCK_LOCK(so); if (so->so_state & SS_CANTRCVMORE) { + SOCK_UNLOCK(so); kn->kn_flags |= EV_EOF; kn->kn_fflags = so->so_error; return (1); } - if (so->so_error) /* temporary udp error */ + if (so->so_error) { /* temporary udp error */ + SOCK_UNLOCK(so); return (1); + } + SOCK_UNLOCK(so); if (kn->kn_sfflags & NOTE_LOWAT) return (kn->kn_data >= kn->kn_sdata); return (kn->kn_data >= so->so_rcv.sb_lowat); @@ -1652,16 +1791,23 @@ filt_sowrite(struct knote *kn, long hint) struct socket *so = (struct socket *)kn->kn_fp->f_data; kn->kn_data = sbspace(&so->so_snd); + SOCK_LOCK(so); if (so->so_state & SS_CANTSENDMORE) { + SOCK_UNLOCK(so); kn->kn_flags |= EV_EOF; kn->kn_fflags = so->so_error; return (1); } - if (so->so_error) /* temporary udp error */ + if (so->so_error) { /* temporary udp error */ + SOCK_UNLOCK(so); return (1); + } if (((so->so_state & SS_ISCONNECTED) == 0) && - (so->so_proto->pr_flags & PR_CONNREQUIRED)) + (so->so_proto->pr_flags & PR_CONNREQUIRED)) { + SOCK_UNLOCK(so); return (0); + } + SOCK_UNLOCK(so); if (kn->kn_sfflags & NOTE_LOWAT) return (kn->kn_data >= kn->kn_sdata); return (kn->kn_data >= so->so_snd.sb_lowat); diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c index 34779f84aac0..c395d878b8eb 100644 --- a/sys/kern/uipc_socket2.c +++ b/sys/kern/uipc_socket2.c @@ -102,71 +102,56 @@ soisconnecting(so) register struct socket *so; { + SOCK_ASSERT(so, MA_OWNED); so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING); so->so_state |= SS_ISCONNECTING; } -void -soisconnected_locked(so) - struct socket *so; -{ - struct socket *head = so->so_head; - - so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); - so->so_state |= SS_ISCONNECTED; - if (head && (so->so_state & SS_INCOMP)) { - if ((so->so_options & SO_ACCEPTFILTER) != 0) { - so->so_upcall = head->so_accf->so_accept_filter->accf_callback; - so->so_upcallarg = head->so_accf->so_accept_filter_arg; - so->so_rcv.sb_flags |= SB_UPCALL; - so->so_options &= ~SO_ACCEPTFILTER; - so->so_upcall(so, so->so_upcallarg, 0); - return; - } - TAILQ_REMOVE(&head->so_incomp, so, so_list); - head->so_incqlen--; - so->so_state &= ~SS_INCOMP; - TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); - head->so_qlen++; - so->so_state |= SS_COMP; - sorwakeup_locked(head); - wakeup_one(&head->so_timeo); - } else { - wakeup(&so->so_timeo); - sorwakeup_locked(so); - sowwakeup_locked(so); - } -} - void soisconnected(so) struct socket *so; { - struct socket *head = so->so_head; + struct socket *head; + so_upcall_t *upcp; + void *upcarg; + SOCK_ASSERT(so, MA_OWNED); + head = so->so_head; so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); so->so_state |= SS_ISCONNECTED; if (head && (so->so_state & SS_INCOMP)) { if ((so->so_options & SO_ACCEPTFILTER) != 0) { - so->so_upcall = head->so_accf->so_accept_filter->accf_callback; - so->so_upcallarg = head->so_accf->so_accept_filter_arg; + SOCK_UNLOCK(so); + SOCK_LOCK(head); + upcp = head->so_accf->so_accept_filter->accf_callback; + upcarg = head->so_accf->so_accept_filter_arg; + SOCK_UNLOCK(head); + SOCK_LOCK(so); + so->so_upcall = upcp; + so->so_upcallarg = upcarg; so->so_rcv.sb_flags |= SB_UPCALL; so->so_options &= ~SO_ACCEPTFILTER; - so->so_upcall(so, so->so_upcallarg, 0); + SOCK_UNLOCK(so); + so->so_upcall(so, upcarg, 0); + SOCK_LOCK(so); return; } + so->so_state &= ~SS_INCOMP; + so->so_state |= SS_COMP; + SOCK_UNLOCK(so); + SOCK_LOCK(head); TAILQ_REMOVE(&head->so_incomp, so, so_list); head->so_incqlen--; - so->so_state &= ~SS_INCOMP; TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); head->so_qlen++; - so->so_state |= SS_COMP; - sorwakeup_locked(head); + sorwakeup(head); wakeup_one(&head->so_timeo); + SOCK_UNLOCK(head); + SOCK_LOCK(so); } else { wakeup(&so->so_timeo); - sorwakeup_locked(so); - sowwakeup_locked(so); + sorwakeup(so); + sowwakeup(so); } } @@ -175,23 +160,12 @@ soisdisconnecting(so) register struct socket *so; { + SOCK_ASSERT(so, MA_OWNED); so->so_state &= ~SS_ISCONNECTING; so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE); wakeup((caddr_t)&so->so_timeo); - sowwakeup_locked(so); - sorwakeup_locked(so); -} - -void -soisdisconnected_locked(so) - register struct socket *so; -{ - - so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); - so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED); - wakeup((caddr_t)&so->so_timeo); - sowwakeup_locked(so); - sorwakeup_locked(so); + sowwakeup(so); + sorwakeup(so); } void @@ -199,7 +173,12 @@ soisdisconnected(so) register struct socket *so; { - soisdisconnected_locked(so); + SOCK_ASSERT(so, MA_OWNED); + so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); + so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED); + wakeup((caddr_t)&so->so_timeo); + sowwakeup(so); + sorwakeup(so); } /* @@ -224,25 +203,32 @@ sonewconn(head, connstatus) so = soalloc(0); if (so == NULL) return ((struct socket *)0); + SOCK_LOCK(head); if ((head->so_options & SO_ACCEPTFILTER) != 0) connstatus = 0; + SOCK_UNLOCK(head); so->so_head = head; so->so_type = head->so_type; + SOCK_LOCK(so); so->so_options = head->so_options &~ SO_ACCEPTCONN; so->so_linger = head->so_linger; so->so_state = head->so_state | SS_NOFDREF; + SOCK_UNLOCK(so); so->so_proto = head->so_proto; so->so_timeo = head->so_timeo; so->so_cred = crhold(head->so_cred); if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat) || (*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) { + SOCK_LOCK(so); sotryfree(so); return ((struct socket *)0); } if (connstatus) { TAILQ_INSERT_TAIL(&head->so_comp, so, so_list); + SOCK_LOCK(so); so->so_state |= SS_COMP; + SOCK_UNLOCK(so); head->so_qlen++; } else { if (head->so_incqlen >= head->so_qlimit) { @@ -251,13 +237,19 @@ sonewconn(head, connstatus) (void) soabort(sp); } TAILQ_INSERT_TAIL(&head->so_incomp, so, so_list); + SOCK_LOCK(so); so->so_state |= SS_INCOMP; + SOCK_UNLOCK(so); head->so_incqlen++; } if (connstatus) { - sorwakeup_locked(head); + SOCK_LOCK(head); + sorwakeup(head); wakeup((caddr_t)&head->so_timeo); + SOCK_UNLOCK(head); + SOCK_LOCK(so); so->so_state |= connstatus; + SOCK_UNLOCK(so); } return (so); } @@ -277,8 +269,10 @@ socantsendmore(so) struct socket *so; { + SOCK_LOCK(so); so->so_state |= SS_CANTSENDMORE; - sowwakeup_locked(so); + sowwakeup(so); + SOCK_UNLOCK(so); } void @@ -286,8 +280,10 @@ socantrcvmore(so) struct socket *so; { + SOCK_LOCK(so); so->so_state |= SS_CANTRCVMORE; - sorwakeup_locked(so); + sorwakeup(so); + SOCK_UNLOCK(so); } /* @@ -336,6 +332,7 @@ sowakeup(so, sb) register struct socket *so; register struct sockbuf *sb; { + SOCK_ASSERT(so, MA_OWNED); selwakeup(&sb->sb_sel); sb->sb_flags &= ~SB_SEL; @@ -343,13 +340,23 @@ sowakeup(so, sb) sb->sb_flags &= ~SB_WAIT; wakeup((caddr_t)&sb->sb_cc); } - if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL) + if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL) { + SOCK_UNLOCK(so); pgsigio(&so->so_sigio, SIGIO, 0); - if (sb->sb_flags & SB_UPCALL) + SOCK_LOCK(so); + } + if (sb->sb_flags & SB_UPCALL) { + SOCK_UNLOCK(so); (*so->so_upcall)(so, so->so_upcallarg, M_DONTWAIT); - if (sb->sb_flags & SB_AIO) + SOCK_LOCK(so); + } + if (sb->sb_flags & SB_AIO) { + SOCK_UNLOCK(so); aio_swake(so, sb); + } else + SOCK_UNLOCK(so); KNOTE(&sb->sb_sel.si_note, 0); + SOCK_LOCK(so); } /* @@ -959,9 +966,11 @@ sotoxsocket(struct socket *so, struct xsocket *xso) xso->xso_len = sizeof *xso; xso->xso_so = so; xso->so_type = so->so_type; + SOCK_LOCK(so); xso->so_options = so->so_options; xso->so_linger = so->so_linger; xso->so_state = so->so_state; + SOCK_UNLOCK(so); xso->so_pcb = so->so_pcb; xso->xso_protocol = so->so_proto->pr_protocol; xso->xso_family = so->so_proto->pr_domain->dom_family; diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index f80dcc9f9084..0c00fe510956 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -245,12 +245,15 @@ accept1(td, uap, compat) if (error) goto done2; s = splnet(); + SOCK_LOCK(head); if ((head->so_options & SO_ACCEPTCONN) == 0) { + SOCK_UNLOCK(head); splx(s); error = EINVAL; goto done; } if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->so_comp)) { + SOCK_UNLOCK(head); splx(s); error = EWOULDBLOCK; goto done; @@ -260,13 +263,16 @@ accept1(td, uap, compat) head->so_error = ECONNABORTED; break; } - error = tsleep((caddr_t)&head->so_timeo, PSOCK | PCATCH, + error = msleep((caddr_t)&head->so_timeo, + SOCK_MTX(head), PSOCK | PCATCH, "accept", 0); if (error) { + SOCK_UNLOCK(head); splx(s); goto done; } } + SOCK_UNLOCK(head); if (head->so_error) { error = head->so_error; head->so_error = 0; @@ -305,13 +311,17 @@ accept1(td, uap, compat) /* connection has been removed from the listen queue */ KNOTE(&head->so_rcv.sb_sel.si_note, 0); + SOCK_LOCK(so); so->so_state &= ~SS_COMP; + SOCK_UNLOCK(so); so->so_head = NULL; if (head->so_sigio != NULL) fsetown(fgetown(head->so_sigio), &so->so_sigio); FILE_LOCK(nfp); + SOCK_LOCK(so); soref(so); /* file descriptor reference */ + SOCK_UNLOCK(so); nfp->f_data = (caddr_t)so; /* nfp has ref count from falloc */ nfp->f_flag = fflag; nfp->f_ops = &socketops; @@ -432,24 +442,30 @@ connect(td, uap) mtx_lock(&Giant); if ((error = fgetsock(td, uap->s, &so, NULL)) != 0) goto done2; + SOCK_LOCK(so); if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { + SOCK_UNLOCK(so); error = EALREADY; goto done1; } + SOCK_UNLOCK(so); error = getsockaddr(&sa, uap->name, uap->namelen); if (error) goto done1; error = soconnect(so, sa, td); if (error) goto bad; + SOCK_LOCK(so); if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) { + SOCK_UNLOCK(so); FREE(sa, M_SONAME); error = EINPROGRESS; goto done1; } s = splnet(); while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { - error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH, "connec", 0); + error = msleep((caddr_t)&so->so_timeo, + SOCK_MTX(so), PSOCK | PCATCH, "connec", 0); if (error) break; } @@ -457,9 +473,12 @@ connect(td, uap) error = so->so_error; so->so_error = 0; } + SOCK_UNLOCK(so); splx(s); bad: + SOCK_LOCK(so); so->so_state &= ~SS_ISCONNECTING; + SOCK_UNLOCK(so); FREE(sa, M_SONAME); if (error == ERESTART) error = EINTR; @@ -1412,10 +1431,13 @@ getpeername1(td, uap, compat) mtx_lock(&Giant); if ((error = fgetsock(td, uap->fdes, &so, NULL)) != 0) goto done2; + SOCK_LOCK(so); if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) { + SOCK_UNLOCK(so); error = ENOTCONN; goto done1; } + SOCK_UNLOCK(so); error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len)); if (error) goto done1; @@ -1673,10 +1695,13 @@ sendfile(struct thread *td, struct sendfile_args *uap) error = EINVAL; goto done; } + SOCK_LOCK(so); if ((so->so_state & SS_ISCONNECTED) == 0) { + SOCK_UNLOCK(so); error = ENOTCONN; goto done; } + SOCK_UNLOCK(so); if (uap->offset < 0) { error = EINVAL; goto done; @@ -1739,14 +1764,17 @@ sendfile(struct thread *td, struct sendfile_args *uap) * Optimize the non-blocking case by looking at the socket space * before going to the extra work of constituting the sf_buf. */ + SOCK_LOCK(so); if ((so->so_state & SS_NBIO) && sbspace(&so->so_snd) <= 0) { if (so->so_state & SS_CANTSENDMORE) error = EPIPE; else error = EAGAIN; + SOCK_UNLOCK(so); sbunlock(&so->so_snd); goto done; } + SOCK_UNLOCK(so); /* * Attempt to look up the page. * @@ -1869,6 +1897,7 @@ sendfile(struct thread *td, struct sendfile_args *uap) * blocks before the pru_send (or more accurately, any blocking * results in a loop back to here to re-check). */ + SOCK_LOCK(so); if ((so->so_state & SS_CANTSENDMORE) || so->so_error) { if (so->so_state & SS_CANTSENDMORE) { error = EPIPE; @@ -1876,6 +1905,7 @@ sendfile(struct thread *td, struct sendfile_args *uap) error = so->so_error; so->so_error = 0; } + SOCK_UNLOCK(so); m_freem(m); sbunlock(&so->so_snd); splx(s); @@ -1888,12 +1918,14 @@ sendfile(struct thread *td, struct sendfile_args *uap) */ if (sbspace(&so->so_snd) < so->so_snd.sb_lowat) { if (so->so_state & SS_NBIO) { + SOCK_UNLOCK(so); m_freem(m); sbunlock(&so->so_snd); splx(s); error = EAGAIN; goto done; } + SOCK_UNLOCK(so); error = sbwait(&so->so_snd); /* * An error from sbwait usually indicates that we've @@ -1908,6 +1940,7 @@ sendfile(struct thread *td, struct sendfile_args *uap) } goto retry_space; } + SOCK_UNLOCK(so); error = (*so->so_proto->pr_usrreqs->pru_send)(so, 0, m, 0, 0, td); splx(s); if (error) { diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 04d670c1fb0d..55e7c45c8121 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -104,6 +104,7 @@ uipc_abort(struct socket *so) return EINVAL; unp_drop(unp, ECONNABORTED); unp_detach(unp); + SOCK_LOCK(so); sotryfree(so); return 0; } @@ -249,7 +250,9 @@ uipc_rcvd(struct socket *so, int flags) (void)chgsbsize(so2->so_cred->cr_uidinfo, &so2->so_snd.sb_hiwat, newhiwat, RLIM_INFINITY); unp->unp_cc = so->so_rcv.sb_cc; + SOCK_LOCK(so2); sowwakeup(so2); + SOCK_UNLOCK(so2); break; default: @@ -306,7 +309,9 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, else from = &sun_noname; if (sbappendaddr(&so2->so_rcv, from, m, control)) { + SOCK_LOCK(so2); sorwakeup(so2); + SOCK_UNLOCK(so2); m = 0; control = 0; } else @@ -322,7 +327,9 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, * Note: A better implementation would complain * if not equal to the peer's address. */ + SOCK_LOCK(so); if ((so->so_state & SS_ISCONNECTED) == 0) { + SOCK_UNLOCK(so); if (nam) { error = unp_connect(so, nam, td); if (error) @@ -334,9 +341,11 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, } if (so->so_state & SS_CANTSENDMORE) { + SOCK_UNLOCK(so); error = EPIPE; break; } + SOCK_UNLOCK(so); if (unp->unp_conn == 0) panic("uipc_send connected but no connection?"); so2 = unp->unp_conn->unp_socket; @@ -358,7 +367,9 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, (void)chgsbsize(so->so_cred->cr_uidinfo, &so->so_snd.sb_hiwat, newhiwat, RLIM_INFINITY); unp->unp_conn->unp_cc = so2->so_rcv.sb_cc; + SOCK_LOCK(so2); sorwakeup(so2); + SOCK_UNLOCK(so2); m = 0; break; @@ -563,7 +574,9 @@ unp_detach(unp) unp_disconnect(unp); while (!LIST_EMPTY(&unp->unp_refs)) unp_drop(LIST_FIRST(&unp->unp_refs), ECONNRESET); + SOCK_LOCK(unp->unp_socket); soisdisconnected(unp->unp_socket); + SOCK_UNLOCK(unp->unp_socket); unp->unp_socket->so_pcb = 0; if (unp_rights) { /* @@ -697,8 +710,14 @@ unp_connect(so, nam, td) goto bad; } if (so->so_proto->pr_flags & PR_CONNREQUIRED) { - if ((so2->so_options & SO_ACCEPTCONN) == 0 || - (so3 = sonewconn(so2, 0)) == 0) { + SOCK_LOCK(so2); + if ((so2->so_options & SO_ACCEPTCONN) == 0) { + SOCK_UNLOCK(so2); + error = ECONNREFUSED; + goto bad; + } + SOCK_UNLOCK(so2); + if ((so3 = sonewconn(so2, 0)) == 0) { error = ECONNREFUSED; goto bad; } @@ -756,13 +775,19 @@ unp_connect2(so, so2) case SOCK_DGRAM: LIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_reflink); + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); break; case SOCK_STREAM: unp2->unp_conn = unp; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); + SOCK_LOCK(so2); soisconnected(so2); + SOCK_UNLOCK(so2); break; default: @@ -784,13 +809,19 @@ unp_disconnect(unp) case SOCK_DGRAM: LIST_REMOVE(unp, unp_reflink); + SOCK_LOCK(unp->unp_socket); unp->unp_socket->so_state &= ~SS_ISCONNECTED; + SOCK_UNLOCK(unp->unp_socket); break; case SOCK_STREAM: + SOCK_LOCK(unp->unp_socket); soisdisconnected(unp->unp_socket); + SOCK_UNLOCK(unp->unp_socket); + SOCK_LOCK(unp2->unp_socket); unp2->unp_conn = 0; soisdisconnected(unp2->unp_socket); + SOCK_UNLOCK(unp2->unp_socket); break; } } diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c index 499d4b75595d..3e1fe8e94c98 100644 --- a/sys/kern/vfs_aio.c +++ b/sys/kern/vfs_aio.c @@ -1440,8 +1440,10 @@ _aio_aqueue(struct thread *td, struct aiocb *job, struct aio_liojob *lj, int typ */ so = (struct socket *)fp->f_data; s = splnet(); + SOCK_LOCK(so); if (((opcode == LIO_READ) && (!soreadable(so))) || ((opcode == LIO_WRITE) && (!sowriteable(so)))) { + SOCK_UNLOCK(so); TAILQ_INSERT_TAIL(&so->so_aiojobq, aiocbe, list); TAILQ_INSERT_TAIL(&ki->kaio_sockqueue, aiocbe, plist); if (opcode == LIO_READ) @@ -1455,6 +1457,7 @@ _aio_aqueue(struct thread *td, struct aiocb *job, struct aio_liojob *lj, int typ error = 0; goto done; } + SOCK_UNLOCK(so); splx(s); } diff --git a/sys/net/raw_cb.c b/sys/net/raw_cb.c index 0dac2e5ca62c..21bb1bebc78e 100644 --- a/sys/net/raw_cb.c +++ b/sys/net/raw_cb.c @@ -35,11 +35,13 @@ */ #include +#include +#include #include +#include +#include #include #include -#include -#include #include @@ -97,6 +99,7 @@ raw_detach(rp) struct socket *so = rp->rcb_socket; so->so_pcb = 0; + SOCK_LOCK(so); sotryfree(so); LIST_REMOVE(rp, list); #ifdef notdef @@ -120,8 +123,12 @@ raw_disconnect(rp) m_freem(dtom(rp->rcb_faddr)); rp->rcb_faddr = 0; #endif - if (rp->rcb_socket->so_state & SS_NOFDREF) + SOCK_LOCK(rp->rcb_socket); + if (rp->rcb_socket->so_state & SS_NOFDREF) { + SOCK_UNLOCK(rp->rcb_socket); raw_detach(rp); + } else + SOCK_UNLOCK(rp->rcb_socket); } #ifdef notdef diff --git a/sys/net/raw_usrreq.c b/sys/net/raw_usrreq.c index 7afab7071d6a..631b2e8c58f7 100644 --- a/sys/net/raw_usrreq.c +++ b/sys/net/raw_usrreq.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -105,7 +106,9 @@ raw_input(m0, proto, src, dst) /* should notify about lost packet */ m_freem(n); else { + SOCK_LOCK(last); sorwakeup(last); + SOCK_UNLOCK(last); sockets++; } } @@ -117,7 +120,9 @@ raw_input(m0, proto, src, dst) m, (struct mbuf *)0) == 0) m_freem(m); else { + SOCK_LOCK(last); sorwakeup(last); + SOCK_UNLOCK(last); sockets++; } } else @@ -145,8 +150,11 @@ raw_uabort(struct socket *so) if (rp == 0) return EINVAL; raw_disconnect(rp); + SOCK_LOCK(so); sotryfree(so); + SOCK_LOCK(so); soisdisconnected(so); /* XXX huh? called after the sofree()? */ + SOCK_UNLOCK(so); return 0; } @@ -203,7 +211,9 @@ raw_udisconnect(struct socket *so) return ENOTCONN; } raw_disconnect(rp); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); return 0; } diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index 47031c234354..407d6f301992 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -147,8 +147,10 @@ rts_attach(struct socket *so, int proto, struct thread *td) } rp->rcb_faddr = &route_src; route_cb.any_count++; - soisconnected_locked(so); + SOCK_LOCK(so); + soisconnected(so); so->so_options |= SO_USELOOPBACK; + SOCK_UNLOCK(so); splx(s); return 0; } @@ -472,7 +474,9 @@ route_output(m, so) /* * Check to see if we don't want our own messages. */ + SOCK_LOCK(so); if ((so->so_options & SO_USELOOPBACK) == 0) { + SOCK_UNLOCK(so); if (route_cb.any_count <= 1) { if (rtm) Free(rtm); @@ -481,7 +485,8 @@ route_output(m, so) } /* There is another listener, so construct message */ rp = sotorawcb(so); - } + } else + SOCK_UNLOCK(so); if (rtm) { m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); if (m->m_pkthdr.len < rtm->rtm_msglen) { diff --git a/sys/netatalk/ddp_input.c b/sys/netatalk/ddp_input.c index 4ef497b0503c..f9a06c8bea62 100644 --- a/sys/netatalk/ddp_input.c +++ b/sys/netatalk/ddp_input.c @@ -410,7 +410,9 @@ ddp_input( m, ifp, elh, phase ) /* * And wake up whatever might be waiting for it */ + SOCK_LOCK(ddp->ddp_socket); sorwakeup( ddp->ddp_socket ); + SOCK_UNLOCK(ddp->ddp_socket); } #if 0 diff --git a/sys/netatalk/ddp_pcb.c b/sys/netatalk/ddp_pcb.c index fa79cec9de4a..63932cc9cce4 100644 --- a/sys/netatalk/ddp_pcb.c +++ b/sys/netatalk/ddp_pcb.c @@ -110,8 +110,11 @@ ddp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) s = splnet(); error = at_pcbconnect( ddp, nam, td ); splx(s); - if ( error == 0 ) + if ( error == 0 ) { + SOCK_LOCK( so ); soisconnected( so ); + SOCK_UNLOCK( so ); + } return(error); } @@ -134,7 +137,9 @@ ddp_disconnect(struct socket *so) at_pcbdisconnect( ddp ); ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; splx(s); + SOCK_LOCK( so ); soisdisconnected( so ); + SOCK_UNLOCK( so ); return(0); } @@ -204,7 +209,9 @@ ddp_abort(struct socket *so) if ( ddp == NULL ) { return(EINVAL); } + SOCK_LOCK( so ); soisdisconnected( so ); + SOCK_UNLOCK( so ); s = splnet(); at_pcbdetach( so, ddp ); splx(s); @@ -440,6 +447,7 @@ at_pcballoc( struct socket *so ) static void at_pcbdetach( struct socket *so, struct ddpcb *ddp) { + SOCK_LOCK( so ); soisdisconnected( so ); so->so_pcb = 0; sotryfree(so); diff --git a/sys/netatalk/ddp_usrreq.c b/sys/netatalk/ddp_usrreq.c index fa79cec9de4a..63932cc9cce4 100644 --- a/sys/netatalk/ddp_usrreq.c +++ b/sys/netatalk/ddp_usrreq.c @@ -110,8 +110,11 @@ ddp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) s = splnet(); error = at_pcbconnect( ddp, nam, td ); splx(s); - if ( error == 0 ) + if ( error == 0 ) { + SOCK_LOCK( so ); soisconnected( so ); + SOCK_UNLOCK( so ); + } return(error); } @@ -134,7 +137,9 @@ ddp_disconnect(struct socket *so) at_pcbdisconnect( ddp ); ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; splx(s); + SOCK_LOCK( so ); soisdisconnected( so ); + SOCK_UNLOCK( so ); return(0); } @@ -204,7 +209,9 @@ ddp_abort(struct socket *so) if ( ddp == NULL ) { return(EINVAL); } + SOCK_LOCK( so ); soisdisconnected( so ); + SOCK_UNLOCK( so ); s = splnet(); at_pcbdetach( so, ddp ); splx(s); @@ -440,6 +447,7 @@ at_pcballoc( struct socket *so ) static void at_pcbdetach( struct socket *so, struct ddpcb *ddp) { + SOCK_LOCK( so ); soisdisconnected( so ); so->so_pcb = 0; sotryfree(so); diff --git a/sys/netatm/atm_aal5.c b/sys/netatm/atm_aal5.c index ab6a95a31d55..63caed2bf537 100644 --- a/sys/netatm/atm_aal5.c +++ b/sys/netatm/atm_aal5.c @@ -771,19 +771,24 @@ atm_aal5_cpcs_data(tok, m) * Ensure that the socket is able to receive data and * that there's room in the socket buffer */ + SOCK_LOCK(so); if (((so->so_state & SS_ISCONNECTED) == 0) || (so->so_state & SS_CANTRCVMORE) || (len > sbspace(&so->so_rcv))) { + SOCK_UNLOCK(so); atm_sock_stat.as_indrop[atp->atp_type]++; KB_FREEALL(m); return; } + SOCK_UNLOCK(so); /* * Queue the data and notify the user */ sbappendrecord(&so->so_rcv, m); + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); return; } @@ -835,9 +840,12 @@ atm_aal5_ctloutput(so, sopt) case T_ATM_ADD_LEAF: case T_ATM_DROP_LEAF: + SOCK_LOCK(so); if ((so->so_state & SS_ISCONNECTED) == 0) { + SOCK_UNLOCK(so); ATM_RETERR(ENOTCONN); - } + } else + SOCK_UNLOCK(so); break; case T_ATM_CAUSE: @@ -845,9 +853,12 @@ atm_aal5_ctloutput(so, sopt) break; default: + SOCK_LOCK(so); if (so->so_state & SS_ISCONNECTED) { + SOCK_UNLOCK(so); ATM_RETERR(EISCONN); - } + } else + SOCK_UNLOCK(so); break; } diff --git a/sys/netatm/atm_socket.c b/sys/netatm/atm_socket.c index 6ff6abcc4018..4862c47f5ac8 100644 --- a/sys/netatm/atm_socket.c +++ b/sys/netatm/atm_socket.c @@ -181,6 +181,7 @@ atm_sock_detach(so) * Break links and free control blocks */ so->so_pcb = NULL; + SOCK_LOCK(so); sotryfree(so); uma_zfree(atm_pcb_zone, atp); @@ -493,7 +494,9 @@ atm_sock_connect(so, addr, epp) /* * We're finally ready to initiate the ATM connection */ + SOCK_LOCK(so); soisconnecting(so); + SOCK_UNLOCK(so); atm_sock_stat.as_connreq[atp->atp_type]++; err = atm_cm_connect(epp, atp, &atp->atp_attr, &atp->atp_conn); if (err == 0) { @@ -501,7 +504,9 @@ atm_sock_connect(so, addr, epp) * Connection is setup */ atm_sock_stat.as_conncomp[atp->atp_type]++; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); } else if (err == EINPROGRESS) { /* @@ -514,7 +519,9 @@ atm_sock_connect(so, addr, epp) * Call failed... */ atm_sock_stat.as_connfail[atp->atp_type]++; + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); } return (err); @@ -564,7 +571,9 @@ atm_sock_disconnect(so) atp->atp_conn = NULL; } + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); return (0); } @@ -661,7 +670,9 @@ atm_sock_peeraddr(so, addr) satm->satm_family = AF_ATM; satm->satm_len = sizeof(*satm); saddr = &satm->satm_addr.t_atm_sap_addr; + SOCK_LOCK(so); if (so->so_state & SS_ISCONNECTED) { + SOCK_UNLOCK(so); cvp = atp->atp_conn->co_connvc; saddr->SVE_tag_addr = T_ATM_PRESENT; if (cvp->cvc_flags & CVCF_CALLER) { @@ -680,6 +691,7 @@ atm_sock_peeraddr(so, addr) else saddr->SVE_tag_selector = T_ATM_ABSENT; } else { + SOCK_UNLOCK(so); saddr->SVE_tag_addr = T_ATM_ABSENT; saddr->SVE_tag_selector = T_ATM_ABSENT; saddr->address_format = T_ATM_ABSENT; @@ -1087,10 +1099,12 @@ atm_sock_getopt(so, sopt, atp) * If socket is connected, return attributes for the VCC in use, * otherwise just return what the user has setup so far. */ + SOCK_LOCK(so); if (so->so_state & SS_ISCONNECTED) ap = &atp->atp_conn->co_connvc->cvc_attr; else ap = &atp->atp_attr; + SOCK_UNLOCK(so); switch (sopt->sopt_name) { @@ -1268,7 +1282,9 @@ atm_sock_connected(toku) * Connection is setup */ atm_sock_stat.as_conncomp[atp->atp_type]++; + SOCK_LOCK(atp->atp_socket); soisconnected(atp->atp_socket); + SOCK_UNLOCK(atp->atp_socket); } @@ -1302,6 +1318,7 @@ atm_sock_cleared(toku, cause) /* * Set user error code */ + SOCK_LOCK(so); if (so->so_state & SS_ISCONNECTED) { so->so_error = ECONNRESET; atm_sock_stat.as_connclr[atp->atp_type]++; @@ -1320,7 +1337,9 @@ atm_sock_cleared(toku, cause) * Cleanup failed incoming connection setup */ if (so->so_state & SS_NOFDREF) { + SOCK_UNLOCK(so); (void) atm_sock_detach(so); - } + } else + SOCK_UNLOCK(so); } diff --git a/sys/netgraph/ng_ksocket.c b/sys/netgraph/ng_ksocket.c index ba60213c8cd7..0badc93bc072 100644 --- a/sys/netgraph/ng_ksocket.c +++ b/sys/netgraph/ng_ksocket.c @@ -507,7 +507,17 @@ static struct ng_type ng_ksocket_typestruct = { }; NETGRAPH_INIT(ksocket, &ng_ksocket_typestruct); -#define ERROUT(x) do { error = (x); goto done; } while (0) +#define ERROUT(x) \ + do { \ + error = (x); \ + goto done; \ + } while (0) +#define ERROUT_SOCK(x) \ + do { \ + error = (x); \ + SOCK_UNLOCK(so); \ + goto done; \ + } while (0) /************************************************************************ NETGRAPH NODE STUFF @@ -613,7 +623,9 @@ ng_ksocket_connect(hook_p hook) priv->so->so_upcall = ng_ksocket_incoming; priv->so->so_rcv.sb_flags |= SB_UPCALL; priv->so->so_snd.sb_flags |= SB_UPCALL; + SOCK_LOCK(priv->so); priv->so->so_state |= SS_NBIO; + SOCK_UNLOCK(priv->so); /* * --Original comment-- * On a cloned socket we may have already received one or more @@ -708,8 +720,10 @@ ng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook) ERROUT(ENXIO); /* Make sure the socket is capable of accepting */ + SOCK_LOCK(so); if (!(so->so_options & SO_ACCEPTCONN)) - ERROUT(EINVAL); + ERROUT_SOCK(EINVAL); + SOCK_UNLOCK(so); if (priv->flags & KSF_ACCEPTING) ERROUT(EALREADY); @@ -744,18 +758,24 @@ ng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook) ERROUT(ENXIO); /* Do connect */ + SOCK_LOCK(so); if ((so->so_state & SS_ISCONNECTING) != 0) - ERROUT(EALREADY); + ERROUT_SOCK(EALREADY); + SOCK_UNLOCK(so); if ((error = soconnect(so, sa, td)) != 0) { + SOCK_LOCK(so); so->so_state &= ~SS_ISCONNECTING; - ERROUT(error); + ERROUT_SOCK(error); } - if ((so->so_state & SS_ISCONNECTING) != 0) + SOCK_LOCK(so); + if ((so->so_state & SS_ISCONNECTING) != 0) { /* We will notify the sender when we connect */ priv->response_token = msg->header.token; raddr = priv->response_addr; priv->flags |= KSF_CONNECTING; - ERROUT(EINPROGRESS); + ERROUT_SOCK(EINPROGRESS); + } + SOCK_UNLOCK(so); break; } @@ -774,9 +794,11 @@ ng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook) /* Get function */ if (msg->header.cmd == NGM_KSOCKET_GETPEERNAME) { + SOCK_LOCK(so); if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) - ERROUT(ENOTCONN); + ERROUT_SOCK(ENOTCONN); + SOCK_UNLOCK(so); func = so->so_proto->pr_usrreqs->pru_peeraddr; } else func = so->so_proto->pr_usrreqs->pru_sockaddr; @@ -1046,11 +1068,13 @@ ng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int waitflag) /* Check whether a pending connect operation has completed */ if (priv->flags & KSF_CONNECTING) { + SOCK_LOCK(so); if ((error = so->so_error) != 0) { so->so_error = 0; so->so_state &= ~SS_ISCONNECTING; } if (!(so->so_state & SS_ISCONNECTING)) { + SOCK_UNLOCK(so); NG_MKMESSAGE(response, NGM_KSOCKET_COOKIE, NGM_KSOCKET_CONNECT, sizeof(int32_t), waitflag); if (response != NULL) { @@ -1066,7 +1090,8 @@ ng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int waitflag) priv->response_addr, NULL); } priv->flags &= ~KSF_CONNECTING; - } + } else + SOCK_UNLOCK(so); } /* Check whether a pending accept operation has completed */ @@ -1096,10 +1121,14 @@ ng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int waitflag) struct sockaddr *sa = NULL; meta_p meta = NULL; struct mbuf *n; + int sostate; /* Try to get next packet from socket */ + SOCK_LOCK(so); + sostate = so->so_state & SS_ISCONNECTED; + SOCK_UNLOCK(so); if ((error = (*so->so_proto->pr_usrreqs->pru_soreceive) - (so, (so->so_state & SS_ISCONNECTED) ? NULL : &sa, + (so, sostate ? NULL : &sa, &auio, &m, (struct mbuf **)0, &flags)) != 0) break; @@ -1146,14 +1175,17 @@ ng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int waitflag) * If the peer has closed the connection, forward a 0-length mbuf * to indicate end-of-file. */ + SOCK_LOCK(so); if (so->so_state & SS_CANTRCVMORE && !(priv->flags & KSF_EOFSEEN)) { + SOCK_UNLOCK(so); MGETHDR(m, waitflag, MT_DATA); if (m != NULL) { m->m_len = m->m_pkthdr.len = 0; NG_SEND_DATA_ONLY(error, priv->hook, m); } priv->flags |= KSF_EOFSEEN; - } + } else + SOCK_UNLOCK(so); splx(s); } @@ -1172,8 +1204,12 @@ ng_ksocket_check_accept(priv_p priv) return error; } if (TAILQ_EMPTY(&head->so_comp)) { - if (head->so_state & SS_CANTRCVMORE) + SOCK_LOCK(head); + if (head->so_state & SS_CANTRCVMORE) { + SOCK_UNLOCK(head); return ECONNABORTED; + } + SOCK_UNLOCK(head); return EWOULDBLOCK; } return 0; @@ -1204,8 +1240,10 @@ ng_ksocket_finish_accept(priv_p priv) /* XXX KNOTE(&head->so_rcv.sb_sel.si_note, 0); */ + SOCK_LOCK(so); so->so_state &= ~SS_COMP; so->so_state |= SS_NBIO; + SOCK_UNLOCK(so); so->so_head = NULL; soaccept(so, &sa); diff --git a/sys/netgraph/ng_socket.c b/sys/netgraph/ng_socket.c index 09d1c46a7cf7..312b36b45e61 100644 --- a/sys/netgraph/ng_socket.c +++ b/sys/netgraph/ng_socket.c @@ -734,7 +734,9 @@ ship_msg(struct ngpcb *pcbp, struct ng_mesg *msg, struct sockaddr_ng *addr) m_freem(mdata); return (ENOBUFS); } + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); return (0); } @@ -770,9 +772,13 @@ ngs_connect(hook_p hook) if ((priv->datasock) && (priv->datasock->ng_socket)) { if (NG_NODE_NUMHOOKS(node) == 1) { + SOCK_LOCK(priv->datasock->ng_socket); priv->datasock->ng_socket->so_state |= SS_ISCONNECTED; + SOCK_UNLOCK(priv->datasock->ng_socket); } else { + SOCK_LOCK(priv->datasock->ng_socket); priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED; + SOCK_UNLOCK(priv->datasock->ng_socket); } } return (0); @@ -886,7 +892,9 @@ ngs_rcvdata(hook_p hook, item_p item) TRAP_ERROR; return (ENOBUFS); } + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); return (0); } @@ -905,9 +913,13 @@ ngs_disconnect(hook_p hook) if ((priv->datasock) && (priv->datasock->ng_socket)) { if (NG_NODE_NUMHOOKS(node) == 1) { + SOCK_LOCK(priv->datasock->ng_socket); priv->datasock->ng_socket->so_state |= SS_ISCONNECTED; + SOCK_UNLOCK(priv->datasock->ng_socket); } else { + SOCK_LOCK(priv->datasock->ng_socket); priv->datasock->ng_socket->so_state &= ~SS_ISCONNECTED; + SOCK_UNLOCK(priv->datasock->ng_socket); } } @@ -932,13 +944,17 @@ ngs_shutdown(node_p node) struct ngpcb *const pcbp = priv->ctlsock; if (dpcbp != NULL) { + SOCK_LOCK(dpcbp->ng_socket); soisdisconnected(dpcbp->ng_socket); + SOCK_UNLOCK(dpcbp->ng_socket); dpcbp->sockdata = NULL; priv->datasock = NULL; priv->refs--; } if (pcbp != NULL) { + SOCK_LOCK(pcbp->ng_socket); soisdisconnected(pcbp->ng_socket); + SOCK_UNLOCK(pcbp->ng_socket); pcbp->sockdata = NULL; priv->ctlsock = NULL; priv->refs--; diff --git a/sys/netinet/accf_data.c b/sys/netinet/accf_data.c index 46c92e3a3074..447073317889 100644 --- a/sys/netinet/accf_data.c +++ b/sys/netinet/accf_data.c @@ -30,6 +30,8 @@ #include #include +#include +#include #include #include #include @@ -57,11 +59,15 @@ static void sohasdata(struct socket *so, void *arg, int waitflag) { - if (!soreadable(so)) + SOCK_LOCK(so); + if (!soreadable(so)) { + SOCK_UNLOCK(so); return; + } so->so_upcall = NULL; so->so_rcv.sb_flags &= ~SB_UPCALL; - soisconnected_locked(so); + soisconnected(so); + SOCK_UNLOCK(so); return; } diff --git a/sys/netinet/accf_http.c b/sys/netinet/accf_http.c index 4a3e17ee0b8e..4849f6be25b8 100644 --- a/sys/netinet/accf_http.c +++ b/sys/netinet/accf_http.c @@ -31,7 +31,9 @@ #include #include +#include #include +#include #include #include #include @@ -160,11 +162,13 @@ static void sohashttpget(struct socket *so, void *arg, int waitflag) { + SOCK_LOCK(so); if ((so->so_state & SS_CANTRCVMORE) == 0 && !sbfull(&so->so_rcv)) { struct mbuf *m; char *cmp; int cmplen, cc; + SOCK_UNLOCK(so); m = so->so_rcv.sb_mb; cc = so->so_rcv.sb_cc - 1; if (cc < 1) @@ -197,13 +201,16 @@ sohashttpget(struct socket *so, void *arg, int waitflag) return; } DPRINT("mbufstrcmp bad"); - } + } else + SOCK_UNLOCK(so); fallout: DPRINT("fallout"); + SOCK_LOCK(so); so->so_upcall = NULL; so->so_rcv.sb_flags &= ~SB_UPCALL; - soisconnected_locked(so); + soisconnected(so); + SOCK_UNLOCK(so); return; } @@ -213,8 +220,12 @@ soparsehttpvers(struct socket *so, void *arg, int waitflag) struct mbuf *m, *n; int i, cc, spaces, inspaces; - if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv)) + SOCK_LOCK(so); + if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv)) { + SOCK_UNLOCK(so); goto fallout; + } + SOCK_UNLOCK(so); m = so->so_rcv.sb_mb; cc = so->so_rcv.sb_cc; @@ -283,9 +294,11 @@ soparsehttpvers(struct socket *so, void *arg, int waitflag) fallout: DPRINT("fallout"); + SOCK_LOCK(so); so->so_upcall = NULL; so->so_rcv.sb_flags &= ~SB_UPCALL; - soisconnected_locked(so); + soisconnected(so); + SOCK_UNLOCK(so); return; } @@ -300,8 +313,12 @@ soishttpconnected(struct socket *so, void *arg, int waitflag) int ccleft, copied; DPRINT("start"); - if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv)) + SOCK_LOCK(so); + if ((so->so_state & SS_CANTRCVMORE) != 0 || sbfull(&so->so_rcv)) { + SOCK_UNLOCK(so); goto gotit; + } + SOCK_UNLOCK(so); /* * Walk the socketbuffer and copy the last NCHRS (3) into a, b, and c @@ -353,8 +370,10 @@ soishttpconnected(struct socket *so, void *arg, int waitflag) return; gotit: + SOCK_LOCK(so); so->so_upcall = NULL; so->so_rcv.sb_flags &= ~SB_UPCALL; - soisconnected_locked(so); + soisconnected(so); + SOCK_UNLOCK(so); return; } diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index b4de80a3ade0..bd4bac958d00 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -183,15 +183,20 @@ in_pcbbind(inp, nam, td) struct sockaddr_in *sin; struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; u_short lport = 0; - int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); + int wild = 0, reuseport; int error, prison = 0; + SOCK_LOCK(so); + reuseport = (so->so_options & SO_REUSEPORT); + SOCK_UNLOCK(so); if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */ return (EADDRNOTAVAIL); if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY) return (EINVAL); + SOCK_LOCK(so); if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) wild = 1; + SOCK_UNLOCK(so); if (nam) { sin = (struct sockaddr_in *)nam; if (nam->sa_len != sizeof (*sin)) @@ -216,8 +221,10 @@ in_pcbbind(inp, nam, td) * and a multicast address is bound on both * new and duplicated sockets. */ + SOCK_LOCK(so); if (so->so_options & SO_REUSEADDR) reuseport = SO_REUSEADDR|SO_REUSEPORT; + SOCK_UNLOCK(so); } else if (sin->sin_addr.s_addr != INADDR_ANY) { sin->sin_port = 0; /* yech... */ bzero(&sin->sin_zero, sizeof(sin->sin_zero)); @@ -237,13 +244,37 @@ in_pcbbind(inp, nam, td) t = in_pcblookup_local(inp->inp_pcbinfo, sin->sin_addr, lport, prison ? 0 : INPLOOKUP_WILDCARD); - if (t && - (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || - ntohl(t->inp_laddr.s_addr) != INADDR_ANY || - (t->inp_socket->so_options & - SO_REUSEPORT) == 0) && - (so->so_cred->cr_uid != - t->inp_socket->so_cred->cr_uid)) { + if (t != NULL) { + SOCK_LOCK(t->inp_socket); + if ((ntohl(sin->sin_addr.s_addr) != INADDR_ANY || + ntohl(t->inp_laddr.s_addr) != INADDR_ANY || + (t->inp_socket->so_options & + SO_REUSEPORT) == 0) && + (so->so_cred->cr_uid != + t->inp_socket->so_cred->cr_uid)) { + SOCK_UNLOCK(t->inp_socket); +#if defined(INET6) + if (ntohl(sin->sin_addr.s_addr) != + INADDR_ANY || + ntohl(t->inp_laddr.s_addr) != + INADDR_ANY || + INP_SOCKAF(so) == + INP_SOCKAF(t->inp_socket)) +#endif /* defined(INET6) */ + return (EADDRINUSE); + } else + SOCK_UNLOCK(t->inp_socket); + } + } + if (prison && + prison_ip(td->td_ucred, 0, &sin->sin_addr.s_addr)) + return (EADDRNOTAVAIL); + t = in_pcblookup_local(pcbinfo, sin->sin_addr, + lport, prison ? 0 : wild); + if (t != NULL) { + SOCK_LOCK(t->inp_socket); + if ((reuseport & t->inp_socket->so_options) == 0) { + SOCK_UNLOCK(t->inp_socket); #if defined(INET6) if (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || @@ -253,24 +284,8 @@ in_pcbbind(inp, nam, td) INP_SOCKAF(t->inp_socket)) #endif /* defined(INET6) */ return (EADDRINUSE); - } - } - if (prison && - prison_ip(td->td_ucred, 0, &sin->sin_addr.s_addr)) - return (EADDRNOTAVAIL); - t = in_pcblookup_local(pcbinfo, sin->sin_addr, - lport, prison ? 0 : wild); - if (t && - (reuseport & t->inp_socket->so_options) == 0) { -#if defined(INET6) - if (ntohl(sin->sin_addr.s_addr) != - INADDR_ANY || - ntohl(t->inp_laddr.s_addr) != - INADDR_ANY || - INP_SOCKAF(so) == - INP_SOCKAF(t->inp_socket)) -#endif /* defined(INET6) */ - return (EADDRINUSE); + } else + SOCK_UNLOCK(t->inp_socket); } } inp->inp_laddr = sin->sin_addr; @@ -416,17 +431,21 @@ in_pcbladdr(inp, nam, plocal_sin) * destination, in case of sharing the cache with IPv6. */ ro = &inp->inp_route; + SOCK_LOCK(inp->inp_socket); if (ro->ro_rt && (ro->ro_dst.sa_family != AF_INET || satosin(&ro->ro_dst)->sin_addr.s_addr != sin->sin_addr.s_addr || inp->inp_socket->so_options & SO_DONTROUTE)) { + SOCK_UNLOCK(inp->inp_socket); RTFREE(ro->ro_rt); ro->ro_rt = (struct rtentry *)0; + SOCK_LOCK(inp->inp_socket); } if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ (ro->ro_rt == (struct rtentry *)0 || ro->ro_rt->rt_ifp == (struct ifnet *)0)) { + SOCK_UNLOCK(inp->inp_socket); /* No route yet, so try to acquire one */ bzero(&ro->ro_dst, sizeof(struct sockaddr_in)); ro->ro_dst.sa_family = AF_INET; @@ -434,7 +453,8 @@ in_pcbladdr(inp, nam, plocal_sin) ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = sin->sin_addr; rtalloc(ro); - } + } else + SOCK_UNLOCK(inp->inp_socket); /* * If we found a route, use the address * corresponding to the outgoing interface @@ -548,8 +568,12 @@ in_pcbdisconnect(inp) inp->inp_faddr.s_addr = INADDR_ANY; inp->inp_fport = 0; in_pcbrehash(inp); - if (inp->inp_socket->so_state & SS_NOFDREF) + SOCK_LOCK(inp->inp_socket); + if (inp->inp_socket->so_state & SS_NOFDREF) { + SOCK_UNLOCK(inp->inp_socket); in_pcbdetach(inp); + } else + SOCK_UNLOCK(inp->inp_socket); } void @@ -565,6 +589,7 @@ in_pcbdetach(inp) inp->inp_gencnt = ++ipi->ipi_gencnt; in_pcbremlists(inp); so->so_pcb = 0; + SOCK_LOCK(so); sotryfree(so); if (inp->inp_options) (void)m_free(inp->inp_options); diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index 8f56d2c580c6..e29739019d7f 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -228,8 +228,11 @@ divert_packet(struct mbuf *m, int incoming, int port) if (sbappendaddr(&sa->so_rcv, (struct sockaddr *)&divsrc, m, (struct mbuf *)0) == 0) m_freem(m); - else + else { + SOCK_LOCK(sa); sorwakeup(sa); + SOCK_UNLOCK(sa); + } } else { m_freem(m); ipstat.ips_noproto++; @@ -255,6 +258,7 @@ div_output(so, m, addr, control) register struct ip *const ip = mtod(m, struct ip *); struct sockaddr_in *sin = (struct sockaddr_in *)addr; int error = 0; + int soopts; if (control) m_freem(control); /* XXX */ @@ -300,8 +304,11 @@ div_output(so, m, addr, control) /* Send packet to output processing */ ipstat.ips_rawout++; /* XXX */ + SOCK_LOCK(so); + soopts = so->so_options & SO_DONTROUTE; + SOCK_UNLOCK(so); error = ip_output(m, inp->inp_options, &inp->inp_route, - (so->so_options & SO_DONTROUTE) | + soopts | IP_ALLOWBROADCAST | IP_RAWOUTPUT, inp->inp_moptions); } else { @@ -365,7 +372,9 @@ div_attach(struct socket *so, int proto, struct thread *td) inp->inp_flags |= INP_HDRINCL; /* The socket is always "connected" because we always know "where" to send the packet */ + SOCK_LOCK(so); so->so_state |= SS_ISCONNECTED; + SOCK_UNLOCK(so); return 0; } @@ -384,15 +393,21 @@ div_detach(struct socket *so) static int div_abort(struct socket *so) { + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); return div_detach(so); } static int div_disconnect(struct socket *so) { - if ((so->so_state & SS_ISCONNECTED) == 0) + SOCK_LOCK(so); + if ((so->so_state & SS_ISCONNECTED) == 0) { + SOCK_UNLOCK(so); return ENOTCONN; + } + SOCK_UNLOCK(so); return div_abort(so); } diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index b7a882f4884d..36278321d876 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1837,15 +1837,18 @@ ip_savecontrol(inp, mp, ip, m) register struct ip *ip; register struct mbuf *m; { + SOCK_LOCK(inp->inp_socket); if (inp->inp_socket->so_options & SO_TIMESTAMP) { struct timeval tv; + SOCK_UNLOCK(inp->inp_socket); microtime(&tv); *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), SCM_TIMESTAMP, SOL_SOCKET); if (*mp) mp = &(*mp)->m_next; - } + } else + SOCK_UNLOCK(inp->inp_socket); if (inp->inp_flags & INP_RECVDSTADDR) { *mp = sbcreatecontrol((caddr_t) &ip->ip_dst, sizeof(struct in_addr), IP_RECVDSTADDR, IPPROTO_IP); diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c index 0be45ea52bed..e2f85f25bbaf 100644 --- a/sys/netinet/ip_mroute.c +++ b/sys/netinet/ip_mroute.c @@ -1133,7 +1133,9 @@ socket_send(s, mm, src) if (sbappendaddr(&s->so_rcv, (struct sockaddr *)src, mm, (struct mbuf *)0) != 0) { + SOCK_LOCK(s); sorwakeup(s); + SOCK_UNLOCK(s); return 0; } } diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 86915fc27605..aaeb61c526e0 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -153,9 +153,16 @@ rip_input(m, off) } else #endif /*IPSEC*/ if (n) { - if (last->inp_flags & INP_CONTROLOPTS || - last->inp_socket->so_options & SO_TIMESTAMP) - ip_savecontrol(last, &opts, ip, n); + if (last->inp_flags & INP_CONTROLOPTS) + ip_savecontrol(last, &opts, ip, n); + else { + SOCK_LOCK(last->inp_socket); + if(last->inp_socket->so_options & SO_TIMESTAMP) { + SOCK_UNLOCK(last->inp_socket); + ip_savecontrol(last, &opts, ip, n); + } else + SOCK_UNLOCK(last->inp_socket); + } if (sbappendaddr(&last->inp_socket->so_rcv, (struct sockaddr *)&ripsrc, n, opts) == 0) { @@ -163,8 +170,11 @@ rip_input(m, off) m_freem(n); if (opts) m_freem(opts); - } else + } else { + SOCK_LOCK(last->inp_socket); sorwakeup(last->inp_socket); + SOCK_UNLOCK(last->inp_socket); + } opts = 0; } } @@ -180,16 +190,26 @@ rip_input(m, off) } else #endif /*IPSEC*/ if (last) { - if (last->inp_flags & INP_CONTROLOPTS || - last->inp_socket->so_options & SO_TIMESTAMP) + if (last->inp_flags & INP_CONTROLOPTS) ip_savecontrol(last, &opts, ip, m); + else { + SOCK_LOCK(last->inp_socket); + if (last->inp_socket->so_options & SO_TIMESTAMP) { + SOCK_UNLOCK(last->inp_socket); + ip_savecontrol(last, &opts, ip, m); + } else + SOCK_UNLOCK(last->inp_socket); + } if (sbappendaddr(&last->inp_socket->so_rcv, (struct sockaddr *)&ripsrc, m, opts) == 0) { m_freem(m); if (opts) m_freem(opts); - } else + } else { + SOCK_LOCK(last->inp_socket); sorwakeup(last->inp_socket); + SOCK_UNLOCK(last->inp_socket); + } } else { m_freem(m); ipstat.ips_noproto++; @@ -209,8 +229,11 @@ rip_output(m, so, dst) { register struct ip *ip; register struct inpcb *inp = sotoinpcb(so); - int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; + int flags; + SOCK_LOCK(so); + flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; + SOCK_UNLOCK(so); /* * If the user handed us a complete IP packet, use it. * Otherwise, allocate an mbuf for a header and fill it in. @@ -508,15 +531,21 @@ rip_detach(struct socket *so) static int rip_abort(struct socket *so) { + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); return rip_detach(so); } static int rip_disconnect(struct socket *so) { - if ((so->so_state & SS_ISCONNECTED) == 0) + SOCK_LOCK(so); + if ((so->so_state & SS_ISCONNECTED) == 0) { + SOCK_UNLOCK(so); return ENOTCONN; + } + SOCK_UNLOCK(so); return rip_abort(so); } @@ -552,7 +581,9 @@ rip_connect(struct socket *so, struct sockaddr *nam, struct thread *td) (addr->sin_family != AF_IMPLINK)) return EAFNOSUPPORT; inp->inp_faddr = addr->sin_addr; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); return 0; } @@ -570,13 +601,16 @@ rip_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct inpcb *inp = sotoinpcb(so); register u_long dst; + SOCK_LOCK(so); if (so->so_state & SS_ISCONNECTED) { + SOCK_UNLOCK(so); if (nam) { m_freem(m); return EISCONN; } dst = inp->inp_faddr.s_addr; } else { + SOCK_UNLOCK(so); if (nam == NULL) { m_freem(m); return ENOTCONN; diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index b193327f3197..b5c6dafc3de4 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -281,15 +281,21 @@ tcp_reass(tp, th, tlenp, m) flags = q->tqe_th->th_flags & TH_FIN; nq = LIST_NEXT(q, tqe_q); LIST_REMOVE(q, tqe_q); - if (so->so_state & SS_CANTRCVMORE) + SOCK_LOCK(so); + if (so->so_state & SS_CANTRCVMORE) { + SOCK_UNLOCK(so); m_freem(q->tqe_m); - else + } else { + SOCK_UNLOCK(so); sbappend(&so->so_rcv, q->tqe_m); + } FREE(q, M_TSEGQ); q = nq; } while (q && q->tqe_th->th_seq == tp->rcv_nxt); ND6_HINT(tp); + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); return (flags); } @@ -638,6 +644,7 @@ tcp_input(m, off0) tiwin = th->th_win; so = inp->inp_socket; + SOCK_LOCK(so); if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) { struct in_conninfo inc; #ifdef TCPDEBUG @@ -654,8 +661,11 @@ tcp_input(m, off0) } #endif /* skip if this isn't a listen socket */ - if ((so->so_options & SO_ACCEPTCONN) == 0) + if ((so->so_options & SO_ACCEPTCONN) == 0) { + SOCK_UNLOCK(so); goto after_listen; + } + SOCK_UNLOCK(so); #ifdef INET6 inc.inc_isipv6 = isipv6; if (isipv6) { @@ -868,11 +878,14 @@ tcp_input(m, off0) tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN); tcpstat.tcps_connects++; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); goto trimthenstep6; } goto drop; - } + } else + SOCK_UNLOCK(so); after_listen: /* XXX temp debugging */ @@ -1004,7 +1017,9 @@ tcp_input(m, off0) tp->t_rxtcur, tcp_timer_rexmt, tp); + SOCK_LOCK(so); sowwakeup(so); + SOCK_UNLOCK(so); if (so->so_snd.sb_cc) (void) tcp_output(tp); return; @@ -1027,7 +1042,9 @@ tcp_input(m, off0) */ m_adj(m, drop_hdrlen); /* delayed header drop */ sbappend(&so->so_rcv, m); + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); if (DELAY_ACK(tp)) { callout_reset(tp->tt_delack, tcp_delacktime, tcp_timer_delack, tp); @@ -1137,7 +1154,9 @@ tcp_input(m, off0) } else tp->t_flags &= ~TF_RCVD_CC; tcpstat.tcps_connects++; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); /* Do window scaling on this connection? */ if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -1467,13 +1486,16 @@ tcp_input(m, off0) * If new data are received on a connection after the * user processes are gone, then RST the other end. */ + SOCK_LOCK(so); if ((so->so_state & SS_NOFDREF) && tp->t_state > TCPS_CLOSE_WAIT && tlen) { + SOCK_UNLOCK(so); tp = tcp_close(tp); tcpstat.tcps_rcvafterclose++; rstreason = BANDLIM_UNLIMITED; goto dropwithreset; } + SOCK_UNLOCK(so); /* * If segment ends after window, drop trailing data @@ -1563,7 +1585,9 @@ tcp_input(m, off0) case TCPS_SYN_RECEIVED: tcpstat.tcps_connects++; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); /* Do window scaling? */ if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -1822,7 +1846,9 @@ tcp_input(m, off0) tp->snd_wnd -= acked; ourfinisacked = 0; } + SOCK_LOCK(so); sowwakeup(so); + SOCK_UNLOCK(so); tp->snd_una = th->th_ack; if (SEQ_LT(tp->snd_nxt, tp->snd_una)) tp->snd_nxt = tp->snd_una; @@ -1843,11 +1869,14 @@ tcp_input(m, off0) * specification, but if we don't get a FIN * we'll hang forever. */ + SOCK_LOCK(so); if (so->so_state & SS_CANTRCVMORE) { - soisdisconnected_locked(so); + soisdisconnected(so); + SOCK_UNLOCK(so); callout_reset(tp->tt_2msl, tcp_maxidle, tcp_timer_2msl, tp); - } + } else + SOCK_UNLOCK(so); tp->t_state = TCPS_FIN_WAIT_2; } break; @@ -1872,7 +1901,9 @@ tcp_input(m, off0) else callout_reset(tp->tt_2msl, 2 * tcp_msl, tcp_timer_2msl, tp); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); } break; @@ -1956,8 +1987,11 @@ tcp_input(m, off0) tp->rcv_up = th->th_seq + th->th_urp; so->so_oobmark = so->so_rcv.sb_cc + (tp->rcv_up - tp->rcv_nxt) - 1; - if (so->so_oobmark == 0) + if (so->so_oobmark == 0) { + SOCK_LOCK(so); so->so_state |= SS_RCVATMARK; + SOCK_UNLOCK(so); + } sohasoutofband(so); tp->t_oobflags &= ~(TCPOOB_HAVEDATA | TCPOOB_HADDATA); } @@ -1967,13 +2001,19 @@ tcp_input(m, off0) * but if two URG's are pending at once, some out-of-band * data may creep in... ick. */ - if (th->th_urp <= (u_long)tlen + if (th->th_urp <= (u_long)tlen) { #ifdef SO_OOBINLINE - && (so->so_options & SO_OOBINLINE) == 0 + SOCK_LOCK(so); + if ((so->so_options & SO_OOBINLINE) == 0) { + SOCK_UNLOCK(so); #endif - ) - tcp_pulloutofband(so, th, m, - drop_hdrlen); /* hdr drop is delayed */ + tcp_pulloutofband(so, th, m, + drop_hdrlen); /* hdr drop is delayed */ +#ifdef SO_OOBINLINE + } else + SOCK_UNLOCK(so); +#endif + } } else /* * If no out of band data is expected, @@ -2019,7 +2059,9 @@ tcp_input(m, off0) tcpstat.tcps_rcvbyte += tlen; ND6_HINT(tp); sbappend(&so->so_rcv, m); + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); } else { thflags = tcp_reass(tp, th, &tlen, m); tp->t_flags |= TF_ACKNOW; @@ -2098,7 +2140,9 @@ tcp_input(m, off0) else callout_reset(tp->tt_2msl, 2 * tcp_msl, tcp_timer_2msl, tp); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); break; /* @@ -2111,9 +2155,13 @@ tcp_input(m, off0) } } #ifdef TCPDEBUG - if (so->so_options & SO_DEBUG) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG) { + SOCK_UNLOCK(so); tcp_trace(TA_INPUT, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + } else + SOCK_UNLOCK(so); #endif /* @@ -2146,9 +2194,13 @@ tcp_input(m, off0) goto dropwithreset; } #ifdef TCPDEBUG - if (so->so_options & SO_DEBUG) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG) { + SOCK_UNLOCK(so); tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + } else + SOCK_UNLOCK(so); #endif m_freem(m); tp->t_flags |= TF_ACKNOW; @@ -2184,9 +2236,18 @@ tcp_input(m, off0) goto drop; #ifdef TCPDEBUG - if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp == 0) tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + else { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, + &tcp_savetcp, 0); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif if (thflags & TH_ACK) /* mtod() below is safe as long as hdr dropping is delayed */ @@ -2206,9 +2267,18 @@ tcp_input(m, off0) * Drop space held by incoming segment and return. */ #ifdef TCPDEBUG - if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp == 0) tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + else { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, + &tcp_savetcp, 0); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif m_freem(m); return; diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 40ed7ee41141..dd2832b18fc5 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -126,6 +126,7 @@ tcp_output(tp) #ifdef INET6 int isipv6; #endif + int soopts; #ifdef INET6 isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) != 0; @@ -819,8 +820,12 @@ tcp_output(tp) /* * Trace. */ - if (so->so_options & SO_DEBUG) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG) { + SOCK_UNLOCK(so); tcp_trace(TA_OUTPUT, tp->t_state, tp, mtod(m, void *), th, 0); + } else + SOCK_UNLOCK(so); #endif /* @@ -854,10 +859,13 @@ tcp_output(tp) goto out; } #endif /*IPSEC*/ + SOCK_LOCK(so); + soopts = (so->so_options & SO_DONTROUTE); + SOCK_UNLOCK(so); error = ip6_output(m, tp->t_inpcb->in6p_outputopts, &tp->t_inpcb->in6p_route, - (so->so_options & SO_DONTROUTE), NULL, NULL); + soopts, NULL, NULL); } else #endif /* INET6 */ { @@ -889,8 +897,11 @@ tcp_output(tp) #ifdef IPSEC ipsec_setsocket(m, so); #endif /*IPSEC*/ + SOCK_LOCK(so); + soopts = (so->so_options & SO_DONTROUTE); + SOCK_UNLOCK(so); error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, - (so->so_options & SO_DONTROUTE), 0); + soopts, 0); } if (error) { diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index b193327f3197..b5c6dafc3de4 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -281,15 +281,21 @@ tcp_reass(tp, th, tlenp, m) flags = q->tqe_th->th_flags & TH_FIN; nq = LIST_NEXT(q, tqe_q); LIST_REMOVE(q, tqe_q); - if (so->so_state & SS_CANTRCVMORE) + SOCK_LOCK(so); + if (so->so_state & SS_CANTRCVMORE) { + SOCK_UNLOCK(so); m_freem(q->tqe_m); - else + } else { + SOCK_UNLOCK(so); sbappend(&so->so_rcv, q->tqe_m); + } FREE(q, M_TSEGQ); q = nq; } while (q && q->tqe_th->th_seq == tp->rcv_nxt); ND6_HINT(tp); + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); return (flags); } @@ -638,6 +644,7 @@ tcp_input(m, off0) tiwin = th->th_win; so = inp->inp_socket; + SOCK_LOCK(so); if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) { struct in_conninfo inc; #ifdef TCPDEBUG @@ -654,8 +661,11 @@ tcp_input(m, off0) } #endif /* skip if this isn't a listen socket */ - if ((so->so_options & SO_ACCEPTCONN) == 0) + if ((so->so_options & SO_ACCEPTCONN) == 0) { + SOCK_UNLOCK(so); goto after_listen; + } + SOCK_UNLOCK(so); #ifdef INET6 inc.inc_isipv6 = isipv6; if (isipv6) { @@ -868,11 +878,14 @@ tcp_input(m, off0) tp->t_flags |= (TF_ACKNOW | TF_NEEDSYN); tcpstat.tcps_connects++; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); goto trimthenstep6; } goto drop; - } + } else + SOCK_UNLOCK(so); after_listen: /* XXX temp debugging */ @@ -1004,7 +1017,9 @@ tcp_input(m, off0) tp->t_rxtcur, tcp_timer_rexmt, tp); + SOCK_LOCK(so); sowwakeup(so); + SOCK_UNLOCK(so); if (so->so_snd.sb_cc) (void) tcp_output(tp); return; @@ -1027,7 +1042,9 @@ tcp_input(m, off0) */ m_adj(m, drop_hdrlen); /* delayed header drop */ sbappend(&so->so_rcv, m); + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); if (DELAY_ACK(tp)) { callout_reset(tp->tt_delack, tcp_delacktime, tcp_timer_delack, tp); @@ -1137,7 +1154,9 @@ tcp_input(m, off0) } else tp->t_flags &= ~TF_RCVD_CC; tcpstat.tcps_connects++; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); /* Do window scaling on this connection? */ if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -1467,13 +1486,16 @@ tcp_input(m, off0) * If new data are received on a connection after the * user processes are gone, then RST the other end. */ + SOCK_LOCK(so); if ((so->so_state & SS_NOFDREF) && tp->t_state > TCPS_CLOSE_WAIT && tlen) { + SOCK_UNLOCK(so); tp = tcp_close(tp); tcpstat.tcps_rcvafterclose++; rstreason = BANDLIM_UNLIMITED; goto dropwithreset; } + SOCK_UNLOCK(so); /* * If segment ends after window, drop trailing data @@ -1563,7 +1585,9 @@ tcp_input(m, off0) case TCPS_SYN_RECEIVED: tcpstat.tcps_connects++; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); /* Do window scaling? */ if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == (TF_RCVD_SCALE|TF_REQ_SCALE)) { @@ -1822,7 +1846,9 @@ tcp_input(m, off0) tp->snd_wnd -= acked; ourfinisacked = 0; } + SOCK_LOCK(so); sowwakeup(so); + SOCK_UNLOCK(so); tp->snd_una = th->th_ack; if (SEQ_LT(tp->snd_nxt, tp->snd_una)) tp->snd_nxt = tp->snd_una; @@ -1843,11 +1869,14 @@ tcp_input(m, off0) * specification, but if we don't get a FIN * we'll hang forever. */ + SOCK_LOCK(so); if (so->so_state & SS_CANTRCVMORE) { - soisdisconnected_locked(so); + soisdisconnected(so); + SOCK_UNLOCK(so); callout_reset(tp->tt_2msl, tcp_maxidle, tcp_timer_2msl, tp); - } + } else + SOCK_UNLOCK(so); tp->t_state = TCPS_FIN_WAIT_2; } break; @@ -1872,7 +1901,9 @@ tcp_input(m, off0) else callout_reset(tp->tt_2msl, 2 * tcp_msl, tcp_timer_2msl, tp); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); } break; @@ -1956,8 +1987,11 @@ tcp_input(m, off0) tp->rcv_up = th->th_seq + th->th_urp; so->so_oobmark = so->so_rcv.sb_cc + (tp->rcv_up - tp->rcv_nxt) - 1; - if (so->so_oobmark == 0) + if (so->so_oobmark == 0) { + SOCK_LOCK(so); so->so_state |= SS_RCVATMARK; + SOCK_UNLOCK(so); + } sohasoutofband(so); tp->t_oobflags &= ~(TCPOOB_HAVEDATA | TCPOOB_HADDATA); } @@ -1967,13 +2001,19 @@ tcp_input(m, off0) * but if two URG's are pending at once, some out-of-band * data may creep in... ick. */ - if (th->th_urp <= (u_long)tlen + if (th->th_urp <= (u_long)tlen) { #ifdef SO_OOBINLINE - && (so->so_options & SO_OOBINLINE) == 0 + SOCK_LOCK(so); + if ((so->so_options & SO_OOBINLINE) == 0) { + SOCK_UNLOCK(so); #endif - ) - tcp_pulloutofband(so, th, m, - drop_hdrlen); /* hdr drop is delayed */ + tcp_pulloutofband(so, th, m, + drop_hdrlen); /* hdr drop is delayed */ +#ifdef SO_OOBINLINE + } else + SOCK_UNLOCK(so); +#endif + } } else /* * If no out of band data is expected, @@ -2019,7 +2059,9 @@ tcp_input(m, off0) tcpstat.tcps_rcvbyte += tlen; ND6_HINT(tp); sbappend(&so->so_rcv, m); + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); } else { thflags = tcp_reass(tp, th, &tlen, m); tp->t_flags |= TF_ACKNOW; @@ -2098,7 +2140,9 @@ tcp_input(m, off0) else callout_reset(tp->tt_2msl, 2 * tcp_msl, tcp_timer_2msl, tp); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); break; /* @@ -2111,9 +2155,13 @@ tcp_input(m, off0) } } #ifdef TCPDEBUG - if (so->so_options & SO_DEBUG) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG) { + SOCK_UNLOCK(so); tcp_trace(TA_INPUT, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + } else + SOCK_UNLOCK(so); #endif /* @@ -2146,9 +2194,13 @@ tcp_input(m, off0) goto dropwithreset; } #ifdef TCPDEBUG - if (so->so_options & SO_DEBUG) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG) { + SOCK_UNLOCK(so); tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + } else + SOCK_UNLOCK(so); #endif m_freem(m); tp->t_flags |= TF_ACKNOW; @@ -2184,9 +2236,18 @@ tcp_input(m, off0) goto drop; #ifdef TCPDEBUG - if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp == 0) tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + else { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, + &tcp_savetcp, 0); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif if (thflags & TH_ACK) /* mtod() below is safe as long as hdr dropping is delayed */ @@ -2206,9 +2267,18 @@ tcp_input(m, off0) * Drop space held by incoming segment and return. */ #ifdef TCPDEBUG - if (tp == 0 || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp == 0) tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); + else { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, + &tcp_savetcp, 0); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif m_freem(m); return; diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 13d8300cb862..20d3bf55bae6 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -469,8 +469,16 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); } #ifdef TCPDEBUG - if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp == NULL) tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); + else { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif #ifdef IPSEC if (ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL) != 0) { @@ -720,7 +728,9 @@ tcp_close(tp) FREE(q, M_TSEGQ); } inp->inp_ppcb = NULL; + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); #ifdef INET6 if (INP_CHECK_SOCKAF(so, AF_INET6)) in6_pcbdetach(inp); @@ -793,9 +803,11 @@ tcp_notify(inp, error) else tp->t_softerror = error; #if 0 + SOCK_LOCK(so); wakeup((caddr_t) &so->so_timeo); sorwakeup(so); sowwakeup(so); + SOCK_UNLOCK(so); #endif } diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c index 087e243a513e..5ee54cfbf901 100644 --- a/sys/netinet/tcp_timer.c +++ b/sys/netinet/tcp_timer.c @@ -39,13 +39,15 @@ #include "opt_tcpdebug.h" #include -#include #include +#include #include -#include +#include +#include #include #include -#include +#include +#include #include /* before tcp_seq.h, for tcp_random18() */ @@ -211,9 +213,15 @@ tcp_timer_2msl(xtp) tp = tcp_close(tp); #ifdef TCPDEBUG - if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) - tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, - PRU_SLOWTIMO); + if (tp != 0) { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, + PRU_SLOWTIMO); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif splx(s); } @@ -243,9 +251,11 @@ tcp_timer_keep(xtp) tcpstat.tcps_keeptimeo++; if (tp->t_state < TCPS_ESTABLISHED) goto dropit; + SOCK_LOCK(tp->t_inpcb->inp_socket); if ((always_keepalive || tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE) && tp->t_state <= TCPS_CLOSING) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); if ((ticks - tp->t_rcvtime) >= tcp_keepidle + tcp_maxidle) goto dropit; /* @@ -269,13 +279,19 @@ tcp_timer_keep(xtp) (void) m_free(dtom(t_template)); } callout_reset(tp->tt_keep, tcp_keepintvl, tcp_timer_keep, tp); - } else + } else { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); callout_reset(tp->tt_keep, tcp_keepidle, tcp_timer_keep, tp); + } #ifdef TCPDEBUG - if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) + SOCK_LOCK(tp->t_inpcb->inp_socket); + if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, PRU_SLOWTIMO); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); #endif splx(s); return; @@ -285,9 +301,15 @@ tcp_timer_keep(xtp) tp = tcp_drop(tp, ETIMEDOUT); #ifdef TCPDEBUG - if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) - tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, - PRU_SLOWTIMO); + if (tp != 0) { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, + PRU_SLOWTIMO); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif splx(s); } @@ -335,9 +357,15 @@ tcp_timer_persist(xtp) out: #ifdef TCPDEBUG - if (tp && tp->t_inpcb->inp_socket->so_options & SO_DEBUG) - tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, - PRU_SLOWTIMO); + if (tp != 0) { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, + PRU_SLOWTIMO); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif splx(s); } @@ -470,9 +498,15 @@ tcp_timer_rexmt(xtp) out: #ifdef TCPDEBUG - if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) - tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, - PRU_SLOWTIMO); + if (tp != 0) { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, + PRU_SLOWTIMO); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif splx(s); } diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index 13d8300cb862..20d3bf55bae6 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -469,8 +469,16 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) m->m_pkthdr.csum_data = offsetof(struct tcphdr, th_sum); } #ifdef TCPDEBUG - if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp == NULL) tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); + else { + SOCK_LOCK(tp->t_inpcb->inp_socket); + if ((tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) { + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); + } else + SOCK_UNLOCK(tp->t_inpcb->inp_socket); + } #endif #ifdef IPSEC if (ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL) != 0) { @@ -720,7 +728,9 @@ tcp_close(tp) FREE(q, M_TSEGQ); } inp->inp_ppcb = NULL; + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); #ifdef INET6 if (INP_CHECK_SOCKAF(so, AF_INET6)) in6_pcbdetach(inp); @@ -793,9 +803,11 @@ tcp_notify(inp, error) else tp->t_softerror = error; #if 0 + SOCK_LOCK(so); wakeup((caddr_t) &so->so_timeo); sorwakeup(so); sowwakeup(so); + SOCK_UNLOCK(so); #endif } diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index e1f4c1a8a9e5..5d8934cbffc0 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -103,8 +103,17 @@ static struct tcpcb * #ifdef TCPDEBUG #define TCPDEBUG0 int ostate = 0 #define TCPDEBUG1() ostate = tp ? tp->t_state : 0 -#define TCPDEBUG2(req) if (tp && (so->so_options & SO_DEBUG)) \ - tcp_trace(TA_USER, ostate, tp, 0, 0, req) +#define TCPDEBUG2(req) \ + do { \ + if (tp != 0) { \ + SOCK_LOCK(so); \ + if (so->so_options & SO_DEBUG) { \ + SOCK_UNLOCK(so); \ + tcp_trace(TA_USER, ostate, tp, 0, 0, req); \ + } else \ + SOCK_UNLOCK(so); \ + } \ + } while(0) #else #define TCPDEBUG0 #define TCPDEBUG1() @@ -134,8 +143,10 @@ tcp_usr_attach(struct socket *so, int proto, struct thread *td) if (error) goto out; + SOCK_LOCK(so); if ((so->so_options & SO_LINGER) && so->so_linger == 0) so->so_linger = TCP_LINGERTIME; + SOCK_UNLOCK(so); tp = sototcpcb(so); out: TCPDEBUG2(PRU_ATTACH); @@ -424,10 +435,13 @@ tcp_usr_accept(struct socket *so, struct sockaddr **nam) struct tcpcb *tp = NULL; TCPDEBUG0; + SOCK_LOCK(so); if (so->so_state & SS_ISDISCONNECTED) { + SOCK_UNLOCK(so); error = ECONNABORTED; goto out; } + SOCK_UNLOCK(so); if (inp == 0) { splx(s); return (EINVAL); @@ -448,10 +462,13 @@ tcp6_usr_accept(struct socket *so, struct sockaddr **nam) struct tcpcb *tp = NULL; TCPDEBUG0; + SOCK_LOCK(so); if (so->so_state & SS_ISDISCONNECTED) { + SOCK_UNLOCK(so); error = ECONNABORTED; goto out; } + SOCK_UNLOCK(so); if (inp == 0) { splx(s); return (EINVAL); @@ -654,10 +671,16 @@ tcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags) struct tcpcb *tp; COMMON_START(); + SOCK_LOCK(so); if ((so->so_oobmark == 0 && (so->so_state & SS_RCVATMARK) == 0) || - so->so_options & SO_OOBINLINE || - tp->t_oobflags & TCPOOB_HADDATA) { + so->so_options & SO_OOBINLINE) { + SOCK_UNLOCK(so); + error = EINVAL; + goto out; + } + SOCK_UNLOCK(so); + if (tp->t_oobflags & TCPOOB_HADDATA) { error = EINVAL; goto out; } @@ -755,7 +778,9 @@ tcp_connect(tp, nam, td) (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) tp->request_r_scale++; + SOCK_LOCK(so); soisconnecting(so); + SOCK_UNLOCK(so); tcpstat.tcps_connattempt++; tp->t_state = TCPS_SYN_SENT; callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp); @@ -841,7 +866,9 @@ tcp6_connect(tp, nam, td) (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) tp->request_r_scale++; + SOCK_LOCK(so); soisconnecting(so); + SOCK_UNLOCK(so); tcpstat.tcps_connattempt++; tp->t_state = TCPS_SYN_SENT; callout_reset(tp->tt_keep, tcp_keepinit, tcp_timer_keep, tp); @@ -1039,16 +1066,21 @@ tcp_attach(so, td) inp->inp_vflag |= INP_IPV4; tp = tcp_newtcpcb(inp); if (tp == 0) { - int nofd = so->so_state & SS_NOFDREF; /* XXX */ + int nofd; + SOCK_LOCK(so); + nofd = so->so_state & SS_NOFDREF; /* XXX */ so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */ + SOCK_UNLOCK(so); #ifdef INET6 if (isipv6) in6_pcbdetach(inp); else #endif in_pcbdetach(inp); + SOCK_LOCK(so); so->so_state |= nofd; + SOCK_UNLOCK(so); return (ENOBUFS); } tp->t_state = TCPS_CLOSED; @@ -1071,14 +1103,19 @@ tcp_disconnect(tp) if (tp->t_state < TCPS_ESTABLISHED) tp = tcp_close(tp); - else if ((so->so_options & SO_LINGER) && so->so_linger == 0) - tp = tcp_drop(tp, 0); else { - soisdisconnecting(so); - sbflush(&so->so_rcv); - tp = tcp_usrclosed(tp); - if (tp) - (void) tcp_output(tp); + SOCK_LOCK(so); + if ((so->so_options & SO_LINGER) && so->so_linger == 0) { + SOCK_UNLOCK(so); + tp = tcp_drop(tp, 0); + } else { + soisdisconnecting(so); + SOCK_UNLOCK(so); + sbflush(&so->so_rcv); + tp = tcp_usrclosed(tp); + if (tp) + (void) tcp_output(tp); + } } return (tp); } @@ -1120,7 +1157,9 @@ tcp_usrclosed(tp) break; } if (tp && tp->t_state >= TCPS_FIN_WAIT_2) { + SOCK_LOCK(tp->t_inpcb->inp_socket); soisdisconnected(tp->t_inpcb->inp_socket); + SOCK_UNLOCK(tp->t_inpcb->inp_socket); /* To prevent the connection hanging in FIN_WAIT_2 forever. */ if (tp->t_state == TCPS_FIN_WAIT_2) callout_reset(tp->tt_2msl, tcp_maxidle, diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index af4769fd0d5c..152296669775 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -319,8 +319,12 @@ udp_input(m, off) * port. It * assumes that an application will never * clear these options after setting them. */ - if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0) + SOCK_LOCK(last->inp_socket); + if ((last->inp_socket->so_options&(SO_REUSEPORT|SO_REUSEADDR)) == 0) { + SOCK_UNLOCK(last->inp_socket); break; + } else + SOCK_UNLOCK(last->inp_socket); } if (last == NULL) { @@ -384,8 +388,10 @@ udp_input(m, off) */ udp_in.sin_port = uh->uh_sport; udp_in.sin_addr = ip->ip_src; + SOCK_LOCK(inp->inp_socket); if (inp->inp_flags & INP_CONTROLOPTS || inp->inp_socket->so_options & SO_TIMESTAMP) { + SOCK_UNLOCK(inp->inp_socket); #ifdef INET6 if (inp->inp_vflag & INP_IPV6) { int savedflags; @@ -398,7 +404,8 @@ udp_input(m, off) } else #endif ip_savecontrol(inp, &opts, ip, m); - } + } else + SOCK_UNLOCK(inp->inp_socket); m_adj(m, iphlen + sizeof(struct udphdr)); #ifdef INET6 if (inp->inp_vflag & INP_IPV6) { @@ -411,7 +418,9 @@ udp_input(m, off) udpstat.udps_fullsock++; goto bad; } + SOCK_LOCK(inp->inp_socket); sorwakeup(inp->inp_socket); + SOCK_UNLOCK(inp->inp_socket); return; bad: m_freem(m); @@ -453,8 +462,10 @@ udp_append(last, ip, n, off) struct sockaddr *append_sa; struct mbuf *opts = 0; + SOCK_LOCK(last->inp_socket); if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) { + SOCK_UNLOCK(last->inp_socket); #ifdef INET6 if (last->inp_vflag & INP_IPV6) { int savedflags; @@ -470,7 +481,8 @@ udp_append(last, ip, n, off) } else #endif ip_savecontrol(last, &opts, ip, n); - } + } else + SOCK_UNLOCK(last->inp_socket); #ifdef INET6 if (last->inp_vflag & INP_IPV6) { if (udp_in6.uin6_init_done == 0) { @@ -487,8 +499,11 @@ udp_append(last, ip, n, off) if (opts) m_freem(opts); udpstat.udps_fullsock++; - } else + } else { + SOCK_LOCK(last->inp_socket); sorwakeup(last->inp_socket); + SOCK_UNLOCK(last->inp_socket); + } } /* @@ -501,8 +516,10 @@ udp_notify(inp, errno) int errno; { inp->inp_socket->so_error = errno; + SOCK_LOCK(inp->inp_socket); sorwakeup(inp->inp_socket); sowwakeup(inp->inp_socket); + SOCK_UNLOCK(inp->inp_socket); } void @@ -678,7 +695,7 @@ udp_output(inp, m, addr, control, td) register int len = m->m_pkthdr.len; struct in_addr laddr; struct sockaddr_in *sin; - int s = 0, error = 0; + int s = 0, error = 0, soopts; if (control) m_freem(control); /* XXX */ @@ -759,8 +776,11 @@ udp_output(inp, m, addr, control, td) goto release; } #endif /*IPSEC*/ + SOCK_LOCK(inp->inp_socket); + soopts = inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST); + SOCK_UNLOCK(inp->inp_socket); error = ip_output(m, inp->inp_options, &inp->inp_route, - (inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)), + soopts, inp->inp_moptions); if (addr) { @@ -799,7 +819,9 @@ udp_abort(struct socket *so) inp = sotoinpcb(so); if (inp == 0) return EINVAL; /* ??? possible? panic instead? */ + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); s = splnet(); in_pcbdetach(inp); splx(s); @@ -864,8 +886,11 @@ udp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) prison_remote_ip(td->td_ucred, 0, &sin->sin_addr.s_addr); error = in_pcbconnect(inp, nam, td); splx(s); - if (error == 0) + if (error == 0) { + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); + } return error; } @@ -900,7 +925,9 @@ udp_disconnect(struct socket *so) in_pcbdisconnect(inp); inp->inp_laddr.s_addr = INADDR_ANY; splx(s); + SOCK_LOCK(so); so->so_state &= ~SS_ISCONNECTED; /* XXX */ + SOCK_UNLOCK(so); return 0; } diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 38332b29dc05..f9994c6a941f 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -1941,8 +1941,11 @@ icmp6_rip6_input(mp, off) if (opts) { m_freem(opts); } - } else + } else { + SOCK_LOCK(last->in6p_socket); sorwakeup(last->in6p_socket); + SOCK_UNLOCK(last->in6p_socket); + } opts = NULL; } } @@ -1958,8 +1961,11 @@ icmp6_rip6_input(mp, off) m_freem(m); if (opts) m_freem(opts); - } else + } else { + SOCK_LOCK(last->in6p_socket); sorwakeup(last->in6p_socket); + SOCK_UNLOCK(last->in6p_socket); + } } else { m_freem(m); ip6stat.ip6s_delivered--; diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 09a5c2996296..ab3724927664 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -124,14 +124,19 @@ in6_pcbbind(inp, nam, td) struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL; struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; u_short lport = 0; - int wild = 0, reuseport = (so->so_options & SO_REUSEPORT); + int wild = 0, reuseport; + SOCK_LOCK(so); + reuseport = (so->so_options & SO_REUSEPORT); + SOCK_UNLOCK(so); if (!in6_ifaddr) /* XXX broken! */ return (EADDRNOTAVAIL); if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) return(EINVAL); + SOCK_LOCK(so); if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) wild = 1; + SOCK_UNLOCK(so); if (nam) { sin6 = (struct sockaddr_in6 *)nam; if (nam->sa_len != sizeof(*sin6)) @@ -157,8 +162,10 @@ in6_pcbbind(inp, nam, td) * and a multicast address is bound on both * new and duplicated sockets. */ + SOCK_LOCK(so); if (so->so_options & SO_REUSEADDR) reuseport = SO_REUSEADDR|SO_REUSEPORT; + SOCK_UNLOCK(so); } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { struct ifaddr *ia = NULL; @@ -190,14 +197,19 @@ in6_pcbbind(inp, nam, td) t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr, lport, INPLOOKUP_WILDCARD); - if (t && - (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || - !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) || - (t->inp_socket->so_options & - SO_REUSEPORT) == 0) && - (so->so_cred->cr_uid != - t->inp_socket->so_cred->cr_uid)) - return (EADDRINUSE); + if (t != NULL) { + SOCK_LOCK(t->inp_socket); + if ((!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || + !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) || + (t->inp_socket->so_options & + SO_REUSEPORT) == 0) && + (so->so_cred->cr_uid != + t->inp_socket->so_cred->cr_uid)) { + SOCK_UNLOCK(t->inp_socket); + return (EADDRINUSE); + } + SOCK_UNLOCK(t->inp_socket); + } if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { struct sockaddr_in sin; @@ -218,8 +230,14 @@ in6_pcbbind(inp, nam, td) } t = in6_pcblookup_local(pcbinfo, &sin6->sin6_addr, lport, wild); - if (t && (reuseport & t->inp_socket->so_options) == 0) - return(EADDRINUSE); + if (t != NULL) { + SOCK_LOCK(t->inp_socket); + if ((reuseport & t->inp_socket->so_options) == 0) { + SOCK_UNLOCK(t->inp_socket); + return(EADDRINUSE); + } + SOCK_UNLOCK(t->inp_socket); + } if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 && IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { struct sockaddr_in sin; @@ -227,14 +245,19 @@ in6_pcbbind(inp, nam, td) in6_sin6_2_sin(&sin, sin6); t = in_pcblookup_local(pcbinfo, sin.sin_addr, lport, wild); - if (t && - (reuseport & t->inp_socket->so_options) - == 0 && - (ntohl(t->inp_laddr.s_addr) - != INADDR_ANY || - INP_SOCKAF(so) == - INP_SOCKAF(t->inp_socket))) - return (EADDRINUSE); + if (t != NULL) { + SOCK_LOCK(t->inp_socket); + if ((reuseport & t->inp_socket->so_options) + == 0 && + (ntohl(t->inp_laddr.s_addr) + != INADDR_ANY || + INP_SOCKAF(so) == + INP_SOCKAF(t->inp_socket))) { + SOCK_UNLOCK(t->inp_socket); + return (EADDRINUSE); + } + SOCK_UNLOCK(t->inp_socket); + } } } inp->in6p_laddr = sin6->sin6_addr; @@ -589,8 +612,12 @@ in6_pcbdisconnect(inp) /* clear flowinfo - draft-itojun-ipv6-flowlabel-api-00 */ inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; in_pcbrehash(inp); - if (inp->inp_socket->so_state & SS_NOFDREF) + SOCK_LOCK(inp->inp_socket); + if (inp->inp_socket->so_state & SS_NOFDREF) { + SOCK_UNLOCK(inp->inp_socket); in6_pcbdetach(inp); + } else + SOCK_UNLOCK(inp->inp_socket); } void @@ -607,6 +634,7 @@ in6_pcbdetach(inp) inp->inp_gencnt = ++ipi->ipi_gencnt; in_pcbremlists(inp); sotoinpcb(so) = 0; + SOCK_LOCK(so); sotryfree(so); if (inp->in6p_options) diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c index 3dd2212805ca..910e66db6245 100644 --- a/sys/netinet6/in6_src.c +++ b/sys/netinet6/in6_src.c @@ -338,9 +338,11 @@ in6_pcbsetport(laddr, inp, td) int count, error = 0, wild = 0; struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; + SOCK_LOCK(so); /* XXX: this is redundant when called from in6_pcbbind */ if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) wild = INPLOOKUP_WILDCARD; + SOCK_UNLOCK(so); inp->inp_flags |= INP_ANONPORT; diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 16df5bb830b1..f237cdfda6f5 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1147,16 +1147,19 @@ ip6_savecontrol(in6p, mp, ip6, m) privileged++; #ifdef SO_TIMESTAMP + SOCK_LOCK(in6p->in6p_socket); if ((in6p->in6p_socket->so_options & SO_TIMESTAMP) != 0) { struct timeval tv; + SOCK_UNLOCK(in6p->in6p_socket); microtime(&tv); *mp = sbcreatecontrol((caddr_t) &tv, sizeof(tv), SCM_TIMESTAMP, SOL_SOCKET); if (*mp) { mp = &(*mp)->m_next; } - } + } else + SOCK_UNLOCK(in6p->in6p_socket); #endif /* RFC 2292 sec. 5 */ diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c index 9af7e819888a..513e3076cce9 100644 --- a/sys/netinet6/ip6_mroute.c +++ b/sys/netinet6/ip6_mroute.c @@ -892,7 +892,9 @@ socket_send(s, mm, src) if (sbappendaddr(&s->so_rcv, (struct sockaddr *)src, mm, (struct mbuf *)0) != 0) { + SOCK_LOCK(s); sorwakeup(s); + SOCK_UNLOCK(s); return 0; } } diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 2dcec0cf880f..5fbd7c9f630d 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -182,9 +182,16 @@ rip6_input(mp, offp, proto) } else #endif /*IPSEC*/ if (n) { - if (last->in6p_flags & IN6P_CONTROLOPTS || - last->in6p_socket->so_options & SO_TIMESTAMP) + if (last->in6p_flags & IN6P_CONTROLOPTS) ip6_savecontrol(last, &opts, ip6, n); + else { + SOCK_LOCK(last->in6p_socket); + if (last->in6p_socket->so_options & SO_TIMESTAMP) { + SOCK_UNLOCK(last->in6p_socket); + ip6_savecontrol(last, &opts, ip6, n); + } else + SOCK_UNLOCK(last->in6p_socket); + } /* strip intermediate headers */ m_adj(n, *offp); if (sbappendaddr(&last->in6p_socket->so_rcv, @@ -194,8 +201,11 @@ rip6_input(mp, offp, proto) if (opts) m_freem(opts); rip6stat.rip6s_fullsock++; - } else + } else { + SOCK_LOCK(last->in6p_socket); sorwakeup(last->in6p_socket); + SOCK_UNLOCK(last->in6p_socket); + } opts = NULL; } } @@ -213,9 +223,16 @@ rip6_input(mp, offp, proto) } else #endif /*IPSEC*/ if (last) { - if (last->in6p_flags & IN6P_CONTROLOPTS || - last->in6p_socket->so_options & SO_TIMESTAMP) + if (last->in6p_flags & IN6P_CONTROLOPTS) ip6_savecontrol(last, &opts, ip6, m); + else { + SOCK_LOCK(last->in6p_socket); + if (last->in6p_socket->so_options & SO_TIMESTAMP) { + SOCK_UNLOCK(last->in6p_socket); + ip6_savecontrol(last, &opts, ip6, m); + } else + SOCK_UNLOCK(last->in6p_socket); + } /* strip intermediate headers */ m_adj(m, *offp); if (sbappendaddr(&last->in6p_socket->so_rcv, @@ -224,8 +241,11 @@ rip6_input(mp, offp, proto) if (opts) m_freem(opts); rip6stat.rip6s_fullsock++; - } else + } else { + SOCK_LOCK(last->in6p_socket); sorwakeup(last->in6p_socket); + SOCK_UNLOCK(last->in6p_socket); + } } else { rip6stat.rip6s_nosock++; if (m->m_flags & M_MCAST) @@ -591,7 +611,9 @@ rip6_detach(struct socket *so) static int rip6_abort(struct socket *so) { + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); return rip6_detach(so); } @@ -600,8 +622,12 @@ rip6_disconnect(struct socket *so) { struct inpcb *inp = sotoinpcb(so); - if ((so->so_state & SS_ISCONNECTED) == 0) + SOCK_LOCK(so); + if ((so->so_state & SS_ISCONNECTED) == 0) { + SOCK_UNLOCK(so); return ENOTCONN; + } + SOCK_UNLOCK(so); inp->in6p_faddr = in6addr_any; return rip6_abort(so); } @@ -669,7 +695,9 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) return (error ? error : EADDRNOTAVAIL); inp->in6p_laddr = *in6a; inp->in6p_faddr = addr->sin6_addr; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); return 0; } @@ -689,7 +717,9 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct sockaddr_in6 *dst; /* always copy sockaddr to avoid overwrites */ + SOCK_LOCK(so); if (so->so_state & SS_ISCONNECTED) { + SOCK_UNLOCK(so); if (nam) { m_freem(m); return EISCONN; @@ -702,6 +732,7 @@ rip6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, sizeof(struct in6_addr)); dst = &tmp; } else { + SOCK_UNLOCK(so); if (nam == NULL) { m_freem(m); return ENOTCONN; diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index 20913e64154b..0e58be50b7da 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -269,10 +269,18 @@ udp6_input(mp, offp, proto) * and m_copy() will copy M_PKTHDR * only if offset is 0. */ - if (last->in6p_flags & IN6P_CONTROLOPTS - || last->in6p_socket->so_options & SO_TIMESTAMP) + if (last->in6p_flags & IN6P_CONTROLOPTS) ip6_savecontrol(last, &opts, ip6, n); + else { + SOCK_LOCK(last->in6p_socket); + if (last->in6p_socket->so_options & SO_TIMESTAMP) { + SOCK_UNLOCK(last->in6p_socket); + ip6_savecontrol(last, &opts, + ip6, n); + } else + SOCK_UNLOCK(last->in6p_socket); + } m_adj(n, off + sizeof(struct udphdr)); if (sbappendaddr(&last->in6p_socket->so_rcv, @@ -282,8 +290,11 @@ udp6_input(mp, offp, proto) if (opts) m_freem(opts); udpstat.udps_fullsock++; - } else + } else { + SOCK_LOCK(last->in6p_socket); sorwakeup(last->in6p_socket); + SOCK_UNLOCK(last->in6p_socket); + } opts = NULL; } } @@ -296,9 +307,13 @@ udp6_input(mp, offp, proto) * port. It assumes that an application will never * clear these options after setting them. */ + SOCK_LOCK(last->in6p_socket); if ((last->in6p_socket->so_options & - (SO_REUSEPORT|SO_REUSEADDR)) == 0) + (SO_REUSEPORT|SO_REUSEADDR)) == 0) { + SOCK_UNLOCK(last->in6p_socket); break; + } else + SOCK_UNLOCK(last->in6p_socket); } if (last == NULL) { @@ -320,9 +335,16 @@ udp6_input(mp, offp, proto) goto bad; } #endif /* IPSEC */ - if (last->in6p_flags & IN6P_CONTROLOPTS - || last->in6p_socket->so_options & SO_TIMESTAMP) + if (last->in6p_flags & IN6P_CONTROLOPTS) ip6_savecontrol(last, &opts, ip6, m); + else { + SOCK_LOCK(last->in6p_socket); + if (last->in6p_socket->so_options & SO_TIMESTAMP) { + SOCK_UNLOCK(last->in6p_socket); + ip6_savecontrol(last, &opts, ip6, m); + } else + SOCK_UNLOCK(last->in6p_socket); + } m_adj(m, off + sizeof(struct udphdr)); if (sbappendaddr(&last->in6p_socket->so_rcv, @@ -331,7 +353,9 @@ udp6_input(mp, offp, proto) udpstat.udps_fullsock++; goto bad; } + SOCK_LOCK(last->in6p_socket); sorwakeup(last->in6p_socket); + SOCK_UNLOCK(last->in6p_socket); return IPPROTO_DONE; } /* @@ -375,9 +399,16 @@ udp6_input(mp, offp, proto) */ init_sin6(&udp_in6, m); /* general init */ udp_in6.sin6_port = uh->uh_sport; - if (in6p->in6p_flags & IN6P_CONTROLOPTS - || in6p->in6p_socket->so_options & SO_TIMESTAMP) + if (in6p->in6p_flags & IN6P_CONTROLOPTS) ip6_savecontrol(in6p, &opts, ip6, m); + else { + SOCK_LOCK(in6p->in6p_socket); + if (in6p->in6p_socket->so_options & SO_TIMESTAMP) { + SOCK_UNLOCK(in6p->in6p_socket); + ip6_savecontrol(in6p, &opts, ip6, m); + } else + SOCK_UNLOCK(in6p->in6p_socket); + } m_adj(m, off + sizeof(struct udphdr)); if (sbappendaddr(&in6p->in6p_socket->so_rcv, (struct sockaddr *)&udp_in6, @@ -385,7 +416,9 @@ udp6_input(mp, offp, proto) udpstat.udps_fullsock++; goto bad; } + SOCK_LOCK(in6p->in6p_socket); sorwakeup(in6p->in6p_socket); + SOCK_UNLOCK(in6p->in6p_socket); return IPPROTO_DONE; bad: if (m) @@ -509,7 +542,9 @@ udp6_abort(struct socket *so) inp = sotoinpcb(so); if (inp == 0) return EINVAL; /* ??? possible? panic instead? */ + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); s = splnet(); in6_pcbdetach(inp); splx(s); @@ -614,7 +649,9 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) if (error == 0) { inp->inp_vflag |= INP_IPV4; inp->inp_vflag &= ~INP_IPV6; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); } return error; } @@ -629,7 +666,9 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td) inp->inp_vflag &= ~INP_IPV4; inp->inp_vflag |= INP_IPV6; } + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); } return error; } @@ -673,7 +712,9 @@ udp6_disconnect(struct socket *so) in6_pcbdisconnect(inp); inp->in6p_laddr = in6addr_any; splx(s); + SOCK_LOCK(so); so->so_state &= ~SS_ISCONNECTED; /* XXX */ + SOCK_UNLOCK(so); return 0; } diff --git a/sys/netipx/ipx_pcb.c b/sys/netipx/ipx_pcb.c index 8fe97963ac0c..ebe20bdb0e4b 100644 --- a/sys/netipx/ipx_pcb.c +++ b/sys/netipx/ipx_pcb.c @@ -156,8 +156,12 @@ ipx_pcbconnect(ipxp, nam, td) */ ro = &ipxp->ipxp_route; dst = &satoipx_addr(ro->ro_dst); - if (ipxp->ipxp_socket->so_options & SO_DONTROUTE) + SOCK_LOCK(ipxp->ipxp_socket); + if (ipxp->ipxp_socket->so_options & SO_DONTROUTE) { + SOCK_UNLOCK(ipxp->ipxp_socket); goto flush; + } + SOCK_UNLOCK(ipxp->ipxp_socket); if (!ipx_neteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) goto flush; if (!ipx_hosteq(ipxp->ipxp_lastdst, sipx->sipx_addr)) { @@ -172,15 +176,18 @@ ipx_pcbconnect(ipxp, nam, td) } }/* else cached route is ok; do nothing */ ipxp->ipxp_lastdst = sipx->sipx_addr; + SOCK_LOCK(ipxp->ipxp_socket); if ((ipxp->ipxp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL)) { + SOCK_UNLOCK(ipxp->ipxp_socket); /* No route yet, so try to acquire one */ ro->ro_dst.sa_family = AF_IPX; ro->ro_dst.sa_len = sizeof(ro->ro_dst); *dst = sipx->sipx_addr; dst->x_port = 0; rtalloc(ro); - } + } else + SOCK_UNLOCK(ipxp->ipxp_socket); if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) { /* * If route is known or can be allocated now, @@ -257,8 +264,12 @@ ipx_pcbdisconnect(ipxp) { ipxp->ipxp_faddr = zeroipx_addr; - if (ipxp->ipxp_socket->so_state & SS_NOFDREF) + SOCK_LOCK(ipxp->ipxp_socket); + if (ipxp->ipxp_socket->so_state & SS_NOFDREF) { + SOCK_UNLOCK(ipxp->ipxp_socket); ipx_pcbdetach(ipxp); + } else + SOCK_UNLOCK(ipxp->ipxp_socket); } void @@ -268,6 +279,7 @@ ipx_pcbdetach(ipxp) struct socket *so = ipxp->ipxp_socket; so->so_pcb = 0; + SOCK_LOCK(so); sotryfree(so); if (ipxp->ipxp_route.ro_rt != NULL) rtfree(ipxp->ipxp_route.ro_rt); diff --git a/sys/netipx/ipx_usrreq.c b/sys/netipx/ipx_usrreq.c index f0c803a90b9a..68d9f10bc738 100644 --- a/sys/netipx/ipx_usrreq.c +++ b/sys/netipx/ipx_usrreq.c @@ -146,7 +146,9 @@ ipx_input(m, ipxp) if (sbappendaddr(&ipxp->ipxp_socket->so_rcv, (struct sockaddr *)&ipx_ipx, m, (struct mbuf *)NULL) == 0) goto bad; + SOCK_LOCK(ipxp->ipxp_socket); sorwakeup(ipxp->ipxp_socket); + SOCK_UNLOCK(ipxp->ipxp_socket); return; bad: m_freem(m); @@ -159,7 +161,9 @@ ipx_abort(ipxp) struct socket *so = ipxp->ipxp_socket; ipx_pcbdisconnect(ipxp); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); } /* @@ -186,7 +190,9 @@ ipx_drop(ipxp, errno) }*/ so->so_error = errno; ipx_pcbdisconnect(ipxp); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); } static int @@ -200,6 +206,7 @@ ipx_output(ipxp, m0) register struct route *ro; struct mbuf *m; struct mbuf *mprev = NULL; + int soopts; /* * Calculate data length. @@ -261,9 +268,14 @@ ipx_output(ipxp, m0) * Output datagram. */ so = ipxp->ipxp_socket; - if (so->so_options & SO_DONTROUTE) + SOCK_LOCK(so); + if (so->so_options & SO_DONTROUTE) { + soopts = so->so_options & SO_BROADCAST; + SOCK_UNLOCK(so); return (ipx_outputfl(m, (struct route *)NULL, - (so->so_options & SO_BROADCAST) | IPX_ROUTETOIF)); + soopts | IPX_ROUTETOIF)); + } + SOCK_UNLOCK(so); /* * Use cached route for previous datagram if * possible. If the previous net was the same @@ -306,7 +318,10 @@ ipx_output(ipxp, m0) } ipxp->ipxp_lastdst = ipx->ipx_dna; #endif /* ancient_history */ - return (ipx_outputfl(m, ro, so->so_options & SO_BROADCAST)); + SOCK_LOCK(so); + soopts = so->so_options & SO_BROADCAST; + SOCK_UNLOCK(so); + return (ipx_outputfl(m, ro, soopts)); } int @@ -429,8 +444,11 @@ ipx_usr_abort(so) s = splnet(); ipx_pcbdetach(ipxp); splx(s); + SOCK_LOCK(so); sotryfree(so); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); return (0); } @@ -480,8 +498,11 @@ ipx_connect(so, nam, td) s = splnet(); error = ipx_pcbconnect(ipxp, nam, td); splx(s); - if (error == 0) + if (error == 0) { + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); + } return (error); } @@ -512,7 +533,9 @@ ipx_disconnect(so) s = splnet(); ipx_pcbdisconnect(ipxp); splx(s); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); return (0); } diff --git a/sys/netipx/spx_usrreq.c b/sys/netipx/spx_usrreq.c index 189d741d09fa..4bdfa55361df 100644 --- a/sys/netipx/spx_usrreq.c +++ b/sys/netipx/spx_usrreq.c @@ -163,6 +163,7 @@ spx_input(m, ipxp) so = ipxp->ipxp_socket; + SOCK_LOCK(so); if (so->so_options & SO_DEBUG || traceallspxs) { ostate = cb->s_state; spx_savesi = *si; @@ -170,6 +171,7 @@ spx_input(m, ipxp) if (so->so_options & SO_ACCEPTCONN) { struct spxpcb *ocb = cb; + SOCK_UNLOCK(so); so = sonewconn(so, 0); if (so == NULL) { goto drop; @@ -193,7 +195,8 @@ spx_input(m, ipxp) cb->s_flags = ocb->s_flags; /* preserve sockopts */ cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */ cb->s_state = TCPS_LISTEN; - } + } else + SOCK_UNLOCK(so); /* * Packet received on connection. @@ -258,7 +261,9 @@ spx_input(m, ipxp) ipxp->ipxp_fport = si->si_sport; cb->s_timer[SPXT_REXMT] = 0; cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); cb->s_state = TCPS_ESTABLISHED; spxstat.spxs_accepts++; } @@ -285,7 +290,9 @@ spx_input(m, ipxp) cb->s_dport = ipxp->ipxp_fport = si->si_sport; cb->s_timer[SPXT_REXMT] = 0; cb->s_flags |= SF_ACKNOW; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); cb->s_state = TCPS_ESTABLISHED; /* Use roundtrip time of connection request for initial rtt */ if (cb->s_rtt) { @@ -297,8 +304,12 @@ spx_input(m, ipxp) cb->s_rtt = 0; } } - if (so->so_options & SO_DEBUG || traceallspxs) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG || traceallspxs) { + SOCK_UNLOCK(so); spx_trace(SA_INPUT, (u_char)ostate, cb, &spx_savesi, 0); + } else + SOCK_UNLOCK(so); m->m_len -= sizeof(struct ipx); m->m_pkthdr.len -= sizeof(struct ipx); @@ -319,15 +330,23 @@ spx_input(m, ipxp) si->si_ack = ntohs(si->si_ack); si->si_alo = ntohs(si->si_alo); m_freem(dtom(si)); - if (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs) + SOCK_LOCK(cb->s_ipxpcb->ipxp_socket); + if (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs) { + SOCK_UNLOCK(cb->s_ipxpcb->ipxp_socket); spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); + } else + SOCK_UNLOCK(cb->s_ipxpcb->ipxp_socket); return; drop: bad: + SOCK_LOCK(cb->s_ipxpcb->ipxp_socket); if (cb == 0 || cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || - traceallspxs) + traceallspxs) { + SOCK_UNLOCK(cb->s_ipxpcb->ipxp_socket); spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); + } else + SOCK_UNLOCK(cb->s_ipxpcb->ipxp_socket); m_freem(m); } @@ -462,7 +481,9 @@ register struct spx *si; else break; } + SOCK_LOCK(so); sowwakeup(so); + SOCK_UNLOCK(so); cb->s_rack = si->si_ack; update_window: if (SSEQ_LT(cb->s_snxt, cb->s_rack)) @@ -501,10 +522,13 @@ register struct spx *si; } /* else queue this packet; */ } else { /*register struct socket *so = cb->s_ipxpcb->ipxp_socket; + SOCK_LOCK(so); if (so->so_state && SS_NOFDREF) { + SOCK_UNLOCK(so); spx_close(cb); - } else - would crash system*/ + } else { + SOCK_UNLOCK(so); + would crash system } */ spx_istat.notyet++; m_freem(dtom(si)); return (0); @@ -565,8 +589,11 @@ register struct spx *si; cb->s_oobflags &= ~SF_IOOB; if (so->so_rcv.sb_cc) so->so_oobmark = so->so_rcv.sb_cc; - else + else { + SOCK_LOCK(so); so->so_state |= SS_RCVATMARK; + SOCK_UNLOCK(so); + } } q = q->si_prev; remque(q->si_next); @@ -596,7 +623,9 @@ register struct spx *si; MCHTYPE(m, MT_OOBDATA); spx_newchecks[1]++; so->so_oobmark = 0; + SOCK_LOCK(so); so->so_state &= ~SS_RCVATMARK; + SOCK_UNLOCK(so); } if (packetp == 0) { m->m_data += SPINC; @@ -622,8 +651,11 @@ register struct spx *si; } else break; } - if (wakeup) + if (wakeup) { + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); + } return (0); } @@ -1027,8 +1059,12 @@ spx_output(cb, m0) si->si_cc |= SPX_SP; } else { cb->s_outx = 3; - if (so->so_options & SO_DEBUG || traceallspxs) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG || traceallspxs) { + SOCK_UNLOCK(so); spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); + } else + SOCK_UNLOCK(so); return (0); } /* @@ -1090,13 +1126,20 @@ spx_output(cb, m0) si->si_sum = 0xffff; cb->s_outx = 4; - if (so->so_options & SO_DEBUG || traceallspxs) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG || traceallspxs) { + SOCK_UNLOCK(so); spx_trace(SA_OUTPUT, cb->s_state, cb, si, 0); + SOCK_LOCK(so); + } - if (so->so_options & SO_DONTROUTE) + if (so->so_options & SO_DONTROUTE) { + SOCK_UNLOCK(so); error = ipx_outputfl(m, (struct route *)NULL, IPX_ROUTETOIF); - else + } else { + SOCK_UNLOCK(so); error = ipx_outputfl(m, &cb->s_ipxpcb->ipxp_route, 0); + } } if (error) { return (error); @@ -1413,7 +1456,9 @@ spx_connect(so, nam, td) error = ipx_pcbconnect(ipxp, nam, td); if (error) goto spx_connect_end; + SOCK_LOCK(so); soisconnecting(so); + SOCK_UNLOCK(so); spxstat.spxs_connattempt++; cb->s_state = TCPS_SYN_SENT; cb->s_did = 0; @@ -1535,12 +1580,15 @@ spx_rcvoob(so, m, flags) ipxp = sotoipxpcb(so); cb = ipxtospxpcb(ipxp); + SOCK_LOCK(so); if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || (so->so_state & SS_RCVATMARK)) { + SOCK_UNLOCK(so); m->m_len = 1; *mtod(m, caddr_t) = cb->s_iobc; return (0); } + SOCK_UNLOCK(so); return (EINVAL); } @@ -1684,7 +1732,9 @@ spx_close(cb) m_free(dtom(cb->s_ipx)); FREE(cb, M_PCB); ipxp->ipxp_pcb = 0; + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); ipx_pcbdetach(ipxp); spxstat.spxs_closed++; return ((struct spxpcb *)NULL); @@ -1887,13 +1937,17 @@ spx_timers(cb, timer) spxstat.spxs_keeptimeo++; if (cb->s_state < TCPS_ESTABLISHED) goto dropit; + SOCK_LOCK(cb->s_ipxpcb->ipxp_socket); if (cb->s_ipxpcb->ipxp_socket->so_options & SO_KEEPALIVE) { + SOCK_UNLOCK(cb->s_ipxpcb->ipxp_socket); if (cb->s_idle >= SPXTV_MAXIDLE) goto dropit; spxstat.spxs_keepprobe++; spx_output(cb, (struct mbuf *)NULL); - } else + } else { + SOCK_UNLOCK(cb->s_ipxpcb->ipxp_socket); cb->s_idle = 0; + } cb->s_timer[SPXT_KEEP] = SPXTV_KEEP; break; dropit: diff --git a/sys/netkey/keysock.c b/sys/netkey/keysock.c index 68f104533aa6..c69af30ffe78 100644 --- a/sys/netkey/keysock.c +++ b/sys/netkey/keysock.c @@ -174,7 +174,9 @@ key_sendup0(rp, m, promisc) error = ENOBUFS; } else error = 0; + SOCK_LOCK(rp->rcb_socket); sorwakeup(rp->rcb_socket); + SOCK_UNLOCK(rp->rcb_socket); return error; } @@ -427,8 +429,10 @@ key_attach(struct socket *so, int proto, struct thread *td) key_cb.any_count++; kp->kp_raw.rcb_laddr = &key_src; kp->kp_raw.rcb_faddr = &key_dst; - soisconnected_locked(so); + SOCK_LOCK(so); + soisconnected(so); so->so_options |= SO_USELOOPBACK; + SOCK_UNLOCK(so); splx(s); return 0; diff --git a/sys/netnatm/natm.c b/sys/netnatm/natm.c index e0535b6d5fbf..27a9bd43e419 100644 --- a/sys/netnatm/natm.c +++ b/sys/netnatm/natm.c @@ -134,6 +134,7 @@ natm_usr_detach(struct socket *so) */ npcb_free(npcb, NPCB_DESTROY); /* drain */ so->so_pcb = NULL; + SOCK_LOCK(so); sotryfree(so); out: splx(s); @@ -216,7 +217,9 @@ natm_usr_connect(struct socket *so, struct sockaddr *nam, d_thread_t *p) } splx(s2); + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); out: splx(s); @@ -259,7 +262,9 @@ natm_usr_disconnect(struct socket *so) splx(s2); npcb_free(npcb, NPCB_REMOVE); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); out: splx(s); @@ -482,6 +487,7 @@ struct proc *p; npcb_free(npcb, NPCB_DESTROY); /* drain */ so->so_pcb = NULL; + SOCK_LOCK(so); sotryfree(so); break; @@ -552,7 +558,9 @@ struct proc *p; } splx(s2); + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); break; @@ -579,7 +587,9 @@ struct proc *p; splx(s2); npcb_free(npcb, NPCB_REMOVE); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); break; @@ -752,7 +762,9 @@ m->m_pkthdr.rcvif = NULL; /* null it out to be safe */ natm_sookbytes += m->m_pkthdr.len; #endif sbappendrecord(&so->so_rcv, m); + SOCK_LOCK(so); sorwakeup(so); + SOCK_UNLOCK(so); } else { #ifdef NATM_STAT natm_sodropcnt++; diff --git a/sys/netncp/ncp_sock.c b/sys/netncp/ncp_sock.c index 3d585b38c181..a16964d63df2 100644 --- a/sys/netncp/ncp_sock.c +++ b/sys/netncp/ncp_sock.c @@ -86,15 +86,18 @@ ncp_soconnect(struct socket *so,struct sockaddr *target, struct proc *p) { */ error = EIO; s = splnet(); + SOCK_LOCK(so); while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { - (void) tsleep((caddr_t)&so->so_timeo, PSOCK, "ncpcon", 2 * hz); + (void) msleep((caddr_t)&so->so_timeo, SOCK_MTX(so), PSOCK, "ncpcon", 2 * hz); if ((so->so_state & SS_ISCONNECTING) && so->so_error == 0 /*&& rep &&*/) { so->so_state &= ~SS_ISCONNECTING; + SOCK_UNLOCK(so); splx(s); goto bad; } } + SOCK_UNLOCK(so); if (so->so_error) { error = so->so_error; so->so_error = 0; diff --git a/sys/netns/idp_usrreq.c b/sys/netns/idp_usrreq.c index 52039619597d..6ca054db1996 100644 --- a/sys/netns/idp_usrreq.c +++ b/sys/netns/idp_usrreq.c @@ -97,7 +97,9 @@ idp_input(m, nsp) if (sbappendaddr(&nsp->nsp_socket->so_rcv, (struct sockaddr *)&idp_ns, m, (struct mbuf *)0) == 0) goto bad; + SOCK_LOCK(nsp->nsp_socket); sorwakeup(nsp->nsp_socket); + SOCK_UNLOCK(nsp->nsp_socket); return; bad: m_freem(m); @@ -109,7 +111,9 @@ idp_abort(nsp) struct socket *so = nsp->nsp_socket; ns_pcbdisconnect(nsp); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); } /* * Drop connection, reporting @@ -133,7 +137,9 @@ idp_drop(nsp, errno) }*/ so->so_error = errno; ns_pcbdisconnect(nsp); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); } int noIdpRoute; @@ -148,6 +154,7 @@ idp_output(nsp, m0) register struct route *ro; struct mbuf *mprev; extern int idpcksum; + int soopts; /* * Calculate data length. @@ -211,9 +218,14 @@ idp_output(nsp, m0) * Output datagram. */ so = nsp->nsp_socket; - if (so->so_options & SO_DONTROUTE) + SOCK_LOCK(so); + if (so->so_options & SO_DONTROUTE) { + soopts = so->so_options & SO_BROADCAST; + SO_UNLOCK(so); return (ns_output(m, (struct route *)0, - (so->so_options & SO_BROADCAST) | NS_ROUTETOIF)); + soopts | NS_ROUTETOIF)); + } + SO_UNLOCK(so); /* * Use cached route for previous datagram if * possible. If the previous net was the same @@ -257,7 +269,10 @@ idp_output(nsp, m0) nsp->nsp_lastdst = idp->idp_dna; #endif /* ancient_history */ if (noIdpRoute) ro = 0; - return (ns_output(m, ro, so->so_options & SO_BROADCAST)); + SOCK_LOCK(so); + soopts = so->so_options & SO_BROADCAST; + SOCK_UNLOCK(so); + return (ns_output(m, ro, soopts)); } /* ARGSUSED */ idp_ctloutput(req, so, level, name, value) @@ -427,8 +442,11 @@ idp_usrreq(so, req, m, nam, control) break; } error = ns_pcbconnect(nsp, nam); - if (error == 0) + if (error == 0) { + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); + } break; case PRU_CONNECT2: @@ -445,7 +463,9 @@ idp_usrreq(so, req, m, nam, control) break; } ns_pcbdisconnect(nsp); + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); break; case PRU_SHUTDOWN: @@ -491,8 +511,11 @@ idp_usrreq(so, req, m, nam, control) case PRU_ABORT: ns_pcbdetach(nsp); + SOCK_LOCK(so); sotryfree(so); + SOCK_LOCK(so); soisdisconnected(so); /* XXX huh, called after sofree()? */ + SOCK_UNLOCK(so); break; case PRU_SOCKADDR: @@ -546,10 +569,13 @@ idp_raw_usrreq(so, req, m, nam, control) case PRU_ATTACH: + SOCK_LOCK(so); if (!(so->so_state & SS_PRIV) || (nsp != NULL)) { + SOCK_UNLOCK(so); error = EINVAL; break; } + SOCK_UNLOCK(so); error = ns_pcballoc(so, &nsrawpcb); if (error) break; diff --git a/sys/netns/ns.c b/sys/netns/ns.c index 7af5acf12ac9..0c1d2726e2a4 100644 --- a/sys/netns/ns.c +++ b/sys/netns/ns.c @@ -107,8 +107,12 @@ ns_control(so, cmd, data, ifp) return (0); } - if ((so->so_state & SS_PRIV) == 0) + SOCK_LOCK(so); + if ((so->so_state & SS_PRIV) == 0) { + SOCK_UNLOCK(so); return (EPERM); + } + SOCK_UNLOCK(so); switch (cmd) { case SIOCAIFADDR: diff --git a/sys/netns/ns_pcb.c b/sys/netns/ns_pcb.c index 01301c087827..9e06710ed6df 100644 --- a/sys/netns/ns_pcb.c +++ b/sys/netns/ns_pcb.c @@ -94,9 +94,13 @@ ns_pcbbind(nsp, nam) if (lport) { u_short aport = ntohs(lport); + SOCK_LOCK(so); if (aport < NSPORT_RESERVED && - (nsp->nsp_socket->so_state & SS_PRIV) == 0) + (nsp->nsp_socket->so_state & SS_PRIV) == 0) { + SOCK_UNLOCK(so); return (EACCES); + } + SOCK_UNLOCK(so); if (ns_pcblookup(&zerons_addr, lport, 0)) return (EADDRINUSE); } @@ -148,8 +152,12 @@ ns_pcbconnect(nsp, nam) */ ro = &nsp->nsp_route; dst = &satons_addr(ro->ro_dst); - if (nsp->nsp_socket->so_options & SO_DONTROUTE) + SOCK_LOCK(nsp->nsp_socket); + if (nsp->nsp_socket->so_options & SO_DONTROUTE) { + SOCK_UNLOCK(nsp->nsp_socket); goto flush; + } + SOCK_UNLOCK(nsp->nsp_socket); if (!ns_neteq(nsp->nsp_lastdst, sns->sns_addr)) goto flush; if (!ns_hosteq(nsp->nsp_lastdst, sns->sns_addr)) { @@ -165,16 +173,19 @@ ns_pcbconnect(nsp, nam) } }/* else cached route is ok; do nothing */ nsp->nsp_lastdst = sns->sns_addr; + SOCK_LOCK(nsp->nsp_socket); if ((nsp->nsp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/ (ro->ro_rt == (struct rtentry *)0 || ro->ro_rt->rt_ifp == (struct ifnet *)0)) { + SOCK_UNLOCK(nsp->nsp_socket); /* No route yet, so try to acquire one */ ro->ro_dst.sa_family = AF_NS; ro->ro_dst.sa_len = sizeof(ro->ro_dst); *dst = sns->sns_addr; dst->x_port = 0; rtalloc(ro); - } + } else + SOCK_UNLOCK(nsp->nsp_socket); if (ns_neteqnn(nsp->nsp_laddr.x_net, ns_zeronet)) { /* * If route is known or can be allocated now, @@ -222,8 +233,12 @@ ns_pcbdisconnect(nsp) { nsp->nsp_faddr = zerons_addr; - if (nsp->nsp_socket->so_state & SS_NOFDREF) + SOCK_LOCK(so); + if (nsp->nsp_socket->so_state & SS_NOFDREF) { + SOCK_UNLOCK(so); ns_pcbdetach(nsp); + } else + SOCK_UNLOCK(so); } ns_pcbdetach(nsp) @@ -232,6 +247,7 @@ ns_pcbdetach(nsp) struct socket *so = nsp->nsp_socket; so->so_pcb = 0; + SOCK_LOCK(so); sotryfree(so); if (nsp->nsp_route.ro_rt) rtfree(nsp->nsp_route.ro_rt); diff --git a/sys/netns/spp_usrreq.c b/sys/netns/spp_usrreq.c index 8a14ff039f76..78bfec7e529a 100644 --- a/sys/netns/spp_usrreq.c +++ b/sys/netns/spp_usrreq.c @@ -106,6 +106,7 @@ spp_input(m, nsp) si->si_alo = ntohs(si->si_alo); so = nsp->nsp_socket; + SOCK_LOCK(so); if (so->so_options & SO_DEBUG || traceallspps) { ostate = cb->s_state; spp_savesi = *si; @@ -113,6 +114,7 @@ spp_input(m, nsp) if (so->so_options & SO_ACCEPTCONN) { struct sppcb *ocb = cb; + SOCK_UNLOCK(so); so = sonewconn(so, 0); if (so == 0) { goto drop; @@ -136,7 +138,8 @@ spp_input(m, nsp) cb->s_flags = ocb->s_flags; /* preserve sockopts */ cb->s_flags2 = ocb->s_flags2; /* preserve sockopts */ cb->s_state = TCPS_LISTEN; - } + } else + SOCK_UNLOCK(so); /* * Packet received on connection. @@ -207,7 +210,9 @@ spp_input(m, nsp) nsp->nsp_fport = si->si_sport; cb->s_timer[SPPT_REXMT] = 0; cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); cb->s_state = TCPS_ESTABLISHED; sppstat.spps_accepts++; } @@ -234,7 +239,9 @@ spp_input(m, nsp) cb->s_dport = nsp->nsp_fport = si->si_sport; cb->s_timer[SPPT_REXMT] = 0; cb->s_flags |= SF_ACKNOW; + SOCK_LOCK(so); soisconnected(so); + SOCK_UNLOCK(so); cb->s_state = TCPS_ESTABLISHED; /* Use roundtrip time of connection request for initial rtt */ if (cb->s_rtt) { @@ -246,8 +253,12 @@ spp_input(m, nsp) cb->s_rtt = 0; } } - if (so->so_options & SO_DEBUG || traceallspps) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG || traceallspps) { + SOCK_UNLOCK(so); spp_trace(SA_INPUT, (u_char)ostate, cb, &spp_savesi, 0); + } else + SOCK_UNLOCK(so); m->m_len -= sizeof (struct idp); m->m_pkthdr.len -= sizeof (struct idp); @@ -268,15 +279,23 @@ spp_input(m, nsp) si->si_ack = ntohs(si->si_ack); si->si_alo = ntohs(si->si_alo); ns_error(dtom(si), NS_ERR_NOSOCK, 0); - if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) + SOCK_LOCK(cb->s_nspcb->nsp_socket); + if (cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || traceallspps) { + SOCK_UNLOCK(cb->s_nspcb->nsp_socket); spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); + } else + SOCK_UNLOCK(cb->s_nspcb->nsp_socket); return; drop: bad: + SOCK_LOCK(cb->s_nspcb->nsp_socket); if (cb == 0 || cb->s_nspcb->nsp_socket->so_options & SO_DEBUG || - traceallspps) + traceallspps) { + SOCK_UNLOCK(cb->s_nspcb->nsp_socket); spp_trace(SA_DROP, (u_char)ostate, cb, &spp_savesi, 0); + } else + SOCK_UNLOCK(cb->s_nspcb->nsp_socket); m_freem(m); } @@ -410,7 +429,9 @@ register struct spidp *si; else break; } + SOCK_LOCK(so); sowwakeup(so); + SOCK_UNLOCK(so); cb->s_rack = si->si_ack; update_window: if (SSEQ_LT(cb->s_snxt, cb->s_rack)) @@ -449,11 +470,14 @@ register struct spidp *si; } /* else queue this packet; */ } else { /*register struct socket *so = cb->s_nspcb->nsp_socket; + SOCK_LOCK(so); if (so->so_state && SS_NOFDREF) { + SOCK_UNLOCK(so); ns_error(dtom(si), NS_ERR_NOSOCK, 0); (void)spp_close(cb); - } else - would crash system*/ + } else { + SOCK_UNLOCK(so); + would crash system }*/ spp_istat.notyet++; ns_error(dtom(si), NS_ERR_FULLUP, 0); return (0); @@ -514,8 +538,11 @@ register struct spidp *si; cb->s_oobflags &= ~SF_IOOB; if (so->so_rcv.sb_cc) so->so_oobmark = so->so_rcv.sb_cc; - else + else { + SOCK_LOCK(so); so->so_state |= SS_RCVATMARK; + SOCK_UNLOCK(so); + } } q = q->si_prev; remque(q->si_next); @@ -545,7 +572,9 @@ register struct spidp *si; MCHTYPE(m, MT_OOBDATA); spp_newchecks[1]++; so->so_oobmark = 0; + SOCK_LOCK(so); so->so_state &= ~SS_RCVATMARK; + SOCK_UNLOCK(so); } if (packetp == 0) { m->m_data += SPINC; @@ -571,7 +600,11 @@ register struct spidp *si; } else break; } - if (wakeup) sorwakeup(so); + if (wakeup) { + SOCK_LOCK(so); + sorwakeup(so); + SOCK_UNLOCK(so); + } return (0); } @@ -1015,8 +1048,12 @@ spp_output(cb, m0) si->si_cc |= SP_SP; } else { cb->s_outx = 3; - if (so->so_options & SO_DEBUG || traceallspps) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG || traceallspps) { + SOCK_UNLOCK(so); spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); + } else + SOCK_UNLOCK(so); return (0); } /* @@ -1082,13 +1119,20 @@ spp_output(cb, m0) si->si_sum = 0xffff; cb->s_outx = 4; - if (so->so_options & SO_DEBUG || traceallspps) + SOCK_LOCK(so); + if (so->so_options & SO_DEBUG || traceallspps) { + SOCK_UNLOCK(so); spp_trace(SA_OUTPUT, cb->s_state, cb, si, 0); + SOCK_LOCK(so); + } - if (so->so_options & SO_DONTROUTE) + if (so->so_options & SO_DONTROUTE) { + SOCK_UNLOCK(so); error = ns_output(m, (struct route *)0, NS_ROUTETOIF); - else + } else { + SOCK_UNLOCK(so); error = ns_output(m, &cb->s_nspcb->nsp_route, 0); + } } if (error) { return (error); @@ -1369,7 +1413,9 @@ spp_usrreq(so, req, m, nam, controlp) error = ns_pcbconnect(nsp, nam); if (error) break; + SOCK_LOCK(so); soisconnecting(so); + SOCK_UNLOCK(so); sppstat.spps_connattempt++; cb->s_state = TCPS_SYN_SENT; cb->s_did = 0; @@ -1443,12 +1489,15 @@ spp_usrreq(so, req, m, nam, controlp) break; case PRU_RCVOOB: + SOCK_LOCK(so); if ((cb->s_oobflags & SF_IOOB) || so->so_oobmark || (so->so_state & SS_RCVATMARK)) { + SOCK_UNLOCK(so); m->m_len = 1; *mtod(m, caddr_t) = cb->s_iobc; break; - } + } else + SOCK_UNLOCK(so); error = EINVAL; break; @@ -1496,8 +1545,12 @@ spp_usrreq(so, req, m, nam, controlp) default: panic("sp_usrreq"); } - if (cb && (so->so_options & SO_DEBUG || traceallspps)) + SOCK_LOCK(so); + if (cb && (so->so_options & SO_DEBUG || traceallspps)) { + SOCK_UNLOCK(so); spp_trace(SA_USER, (u_char)ostate, cb, (struct spidp *)0, req); + } else + SOCK_UNLOCK(so); release: if (controlp != NULL) m_freem(controlp); @@ -1574,7 +1627,9 @@ spp_close(cb) (void) m_free(dtom(cb->s_idp)); (void) m_free(dtom(cb)); nsp->nsp_pcb = 0; + SOCK_LOCK(so); soisdisconnected(so); + SOCK_UNLOCK(so); ns_pcbdetach(nsp); sppstat.spps_closed++; return ((struct sppcb *)0); @@ -1783,13 +1838,17 @@ spp_timers(cb, timer) sppstat.spps_keeptimeo++; if (cb->s_state < TCPS_ESTABLISHED) goto dropit; + SOCK_LOCK(cb->s_nspcb->nsp_socket); if (cb->s_nspcb->nsp_socket->so_options & SO_KEEPALIVE) { + SOCK_UNLOCK(cb->s_nspcb->nsp_socket); if (cb->s_idle >= SPPTV_MAXIDLE) goto dropit; sppstat.spps_keepprobe++; (void) spp_output(cb, (struct mbuf *) 0); - } else + } else { + SOCK_UNLOCK(cb->s_nspcb->nsp_socket); cb->s_idle = 0; + } cb->s_timer[SPPT_KEEP] = SPPTV_KEEP; break; dropit: diff --git a/sys/netsmb/smb_trantcp.c b/sys/netsmb/smb_trantcp.c index bb017bfcfe00..53c918b7eb85 100644 --- a/sys/netsmb/smb_trantcp.c +++ b/sys/netsmb/smb_trantcp.c @@ -250,15 +250,18 @@ nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct thread *td) if (error) goto bad; s = splnet(); + SOCK_LOCK(so); while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { - tsleep(&so->so_timeo, PSOCK, "nbcon", 2 * hz); + msleep(&so->so_timeo, SOCK_MTX(so), PSOCK, "nbcon", 2 * hz); if ((so->so_state & SS_ISCONNECTING) && so->so_error == 0 && (error = nb_intr(nbp, td->td_proc)) != 0) { so->so_state &= ~SS_ISCONNECTING; + SOCK_UNLOCK(so); splx(s); goto bad; } } + SOCK_UNLOCK(so); if (so->so_error) { error = so->so_error; so->so_error = 0; @@ -408,12 +411,15 @@ nbssn_recv(struct nbpcb *nbp, struct mbuf **mpp, int *lenp, for(;;) { m = NULL; error = nbssn_recvhdr(nbp, &len, &rpcode, MSG_DONTWAIT, td); + SOCK_LOCK(so); if (so->so_state & (SS_ISDISCONNECTING | SS_ISDISCONNECTED | SS_CANTRCVMORE)) { + SOCK_UNLOCK(so); nbp->nbp_state = NBST_CLOSED; NBDEBUG("session closed by peer\n"); return ECONNRESET; } + SOCK_UNLOCK(so); if (error) return error; if (len == 0 && nbp->nbp_state != NBST_SESSION) @@ -639,8 +645,10 @@ smb_nbst_intr(struct smb_vc *vcp) if (nbp == NULL || nbp->nbp_tso == NULL) return; + SOCK_LOCK(nbp->nbp_tso); sorwakeup(nbp->nbp_tso); sowwakeup(nbp->nbp_tso); + SOCK_UNLOCK(nbp->nbp_tso); } static int diff --git a/sys/nfsclient/bootp_subr.c b/sys/nfsclient/bootp_subr.c index 124b09f58608..5e8e6bd9331f 100644 --- a/sys/nfsclient/bootp_subr.c +++ b/sys/nfsclient/bootp_subr.c @@ -751,8 +751,13 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td) error = sosend(so, (struct sockaddr *) &dst, &auio, NULL, NULL, 0, td); if (error != 0) { + int sostate; + + SOCK_LOCK(so); + sostate = (int)so->so_state; + SOCK_UNLOCK(so); printf("bootpc_call: sosend: %d state %08x\n", - error, (int) so->so_state); + error, sostate); } /* XXX: Is this needed ? */ diff --git a/sys/nfsclient/nfs_socket.c b/sys/nfsclient/nfs_socket.c index 0a4f849765f9..eda43db43051 100644 --- a/sys/nfsclient/nfs_socket.c +++ b/sys/nfsclient/nfs_socket.c @@ -230,6 +230,7 @@ nfs_connect(struct nfsmount *nmp, struct nfsreq *rep) * that interruptible mounts don't hang here for a long time. */ s = splnet(); + SOCK_LOCK(so); while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) { (void) tsleep((caddr_t)&so->so_timeo, PSOCK, "nfscon", 2 * hz); @@ -238,10 +239,12 @@ nfs_connect(struct nfsmount *nmp, struct nfsreq *rep) (error = nfs_sigintr(nmp, rep, (rep->r_td ? rep->r_td->td_proc : NULL))) != 0){ so->so_state &= ~SS_ISCONNECTING; + SOCK_UNLOCK(so); splx(s); goto bad; } } + SOCK_UNLOCK(so); if (so->so_error) { error = so->so_error; so->so_error = 0; @@ -414,10 +417,14 @@ nfs_send(struct socket *so, struct sockaddr *nam, struct mbuf *top, rep->r_flags &= ~R_MUSTRESEND; soflags = rep->r_nmp->nm_soflags; - if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED)) + SOCK_LOCK(so); + if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED)) { + SOCK_UNLOCK(so); sendnam = (struct sockaddr *)0; - else + } else { + SOCK_UNLOCK(so); sendnam = nam; + } if (so->so_type == SOCK_SEQPACKET) flags = MSG_EOR; else @@ -646,10 +653,14 @@ nfs_receive(struct nfsreq *rep, struct sockaddr **aname, struct mbuf **mp) } else { if ((so = rep->r_nmp->nm_so) == NULL) return (EACCES); - if (so->so_state & SS_ISCONNECTED) + SOCK_LOCK(so); + if (so->so_state & SS_ISCONNECTED) { + SOCK_UNLOCK(so); getnam = (struct sockaddr **)0; - else + } else { + SOCK_UNLOCK(so); getnam = aname; + } auio.uio_resid = len = 1000000; auio.uio_td = td; do { diff --git a/sys/nfsserver/nfs_srvsock.c b/sys/nfsserver/nfs_srvsock.c index 7091c82cef42..29c50a0e9043 100644 --- a/sys/nfsserver/nfs_srvsock.c +++ b/sys/nfsserver/nfs_srvsock.c @@ -714,10 +714,14 @@ nfsrv_send(struct socket *so, struct sockaddr *nam, struct mbuf *top) int error, soflags, flags; soflags = so->so_proto->pr_flags; - if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED)) + SOCK_LOCK(so); + if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED)) { + SOCK_UNLOCK(so); sendnam = (struct sockaddr *)0; - else + } else { + SOCK_UNLOCK(so); sendnam = nam; + } if (so->so_type == SOCK_SEQPACKET) flags = MSG_EOR; else diff --git a/sys/security/lomac/kernel_interface.c b/sys/security/lomac/kernel_interface.c index adaff99f86ce..9093ff3a9656 100644 --- a/sys/security/lomac/kernel_interface.c +++ b/sys/security/lomac/kernel_interface.c @@ -413,10 +413,15 @@ set_object_lattr(lomac_object_t *obj, lattr_t lattr) { case LO_TYPE_SOCKETPAIR: socket = obj->lo_object.socket; /* KASSERT that socket peer levels are synchronized */ - if (lattr.level == LOMAC_HIGHEST_LEVEL) + if (lattr.level == LOMAC_HIGHEST_LEVEL) { + SOCK_LOCK(socket); socket->so_state &= ~SOCKET_LEVEL_LOWEST; - else + SOCK_UNLOCK(socket); + } else { + SOCK_LOCK(socket); socket->so_state |= SOCKET_LEVEL_LOWEST; + SOCK_UNLOCK(socket); + } #ifdef NOT_YET pipe = pipe->pipe_peer; if (pipe != NULL) { @@ -474,8 +479,10 @@ get_object_lattr(const lomac_object_t *obj, lattr_t *lattr) { break; case LO_TYPE_SOCKETPAIR: socket = obj->lo_object.socket; + SOCK_LOCK(socket); lattr->level = (socket->so_state & SOCKET_LEVEL_LOWEST) ? LOMAC_LOWEST_LEVEL : LOMAC_HIGHEST_LEVEL; + SOCK_UNLOCK(socket); lattr->flags = 0; break; default: diff --git a/sys/security/lomac/kernel_socket.c b/sys/security/lomac/kernel_socket.c index 291ccc2e97e9..0c62f3222423 100644 --- a/sys/security/lomac/kernel_socket.c +++ b/sys/security/lomac/kernel_socket.c @@ -245,8 +245,14 @@ lomac_local_connect(struct socket *so, struct sockaddr *nam, struct thread *td) goto bad; } if (so->so_proto->pr_flags & PR_CONNREQUIRED) { - if ((so2->so_options & SO_ACCEPTCONN) == 0 || - (so3 = sonewconn(so2, 0)) == 0) { + SOCK_LOCK(so2); + if ((so2->so_options & SO_ACCEPTCONN) == 0) { + SOCK_UNLOCK(so2); + error = ECONNREFUSED; + goto bad; + } + SOCK_UNLOCK(so2); + if ((so3 = sonewconn(so2, 0)) == 0) { error = ECONNREFUSED; goto bad; } @@ -345,15 +351,20 @@ lomac_local_send( struct socket *so, int flags, struct mbuf *m, error = ENOTCONN; goto out; } - } else if ((so->so_state & SS_ISCONNECTED) == 0) { - if (addr != NULL) { - error = lomac_local_connect(so, addr, td); - if (error) - goto out; /* XXX */ - } else { - error = ENOTCONN; - goto out; - } + } else { + SOCK_LOCK(so); + if ((so->so_state & SS_ISCONNECTED) == 0) { + SOCK_UNLOCK(so); + if (addr != NULL) { + error = lomac_local_connect(so, addr, td); + if (error) + goto out; /* XXX */ + } else { + error = ENOTCONN; + goto out; + } + } else + SOCK_UNLOCK(so); } vp = unp->unp_vnode; if (vp != NULL) { @@ -560,8 +571,12 @@ monitored_soreceive(so, psa, uio, mp0, controlp, flagsp) } if (mp) *mp = (struct mbuf *)0; - if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) + SOCK_LOCK(so); + if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) { + SOCK_UNLOCK(so); (*pr->pr_usrreqs->pru_rcvd)(so, 0); + } else + SOCK_UNLOCK(so); restart: error = sblock(&so->so_rcv, SBLOCKWAIT(flags)); @@ -597,7 +612,9 @@ monitored_soreceive(so, psa, uio, mp0, controlp, flagsp) so->so_error = 0; goto release; } + SOCK_LOCK(so); if (so->so_state & SS_CANTRCVMORE) { + SOCK_UNLOCK(so); if (m) goto dontblock; else @@ -606,19 +623,25 @@ monitored_soreceive(so, psa, uio, mp0, controlp, flagsp) for (; m; m = m->m_next) if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) { m = so->so_rcv.sb_mb; + SOCK_UNLOCK(so); goto dontblock; } if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && (so->so_proto->pr_flags & PR_CONNREQUIRED)) { + SOCK_UNLOCK(so); error = ENOTCONN; goto release; } - if (uio->uio_resid == 0) + if (uio->uio_resid == 0) { + SOCK_UNLOCK(so); goto release; + } if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) { + SOCK_UNLOCK(so); error = EWOULDBLOCK; goto release; } + SOCK_LOCK(so); sbunlock(&so->so_rcv); error = sbwait(&so->so_rcv); splx(s); @@ -687,7 +710,9 @@ monitored_soreceive(so, psa, uio, mp0, controlp, flagsp) else KASSERT(m->m_type == MT_DATA || m->m_type == MT_HEADER, ("receive 3")); + SOCK_LOCK(so); so->so_state &= ~SS_RCVATMARK; + SOCK_UNLOCK(so); len = uio->uio_resid; if (so->so_oobmark && len > so->so_oobmark - offset) len = so->so_oobmark - offset; @@ -746,7 +771,9 @@ monitored_soreceive(so, psa, uio, mp0, controlp, flagsp) if ((flags & MSG_PEEK) == 0) { so->so_oobmark -= len; if (so->so_oobmark == 0) { + SOCK_LOCK(so); so->so_state |= SS_RCVATMARK; + SOCK_UNLOCK(so); break; } } else { @@ -766,8 +793,12 @@ monitored_soreceive(so, psa, uio, mp0, controlp, flagsp) */ while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 && !sosendallatonce(so) && !nextrecord) { - if (so->so_error || so->so_state & SS_CANTRCVMORE) + SOCK_LOCK(so); + if (so->so_error || so->so_state & SS_CANTRCVMORE) { + SOCK_UNLOCK(so); break; + } + SOCK_UNLOCK(so); /* * Notify the protocol that some data has been * drained before blocking. @@ -797,12 +828,15 @@ monitored_soreceive(so, psa, uio, mp0, controlp, flagsp) if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) (*pr->pr_usrreqs->pru_rcvd)(so, flags); } + SOCK_LOCK(so); if (orig_resid == uio->uio_resid && orig_resid && (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { + SOCK_UNLOCK(so); sbunlock(&so->so_rcv); splx(s); goto restart; } + SOCK_UNLOCK(so); if (flagsp) *flagsp |= flags; diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h index f4da0d370b74..27f7f396f971 100644 --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -38,6 +38,8 @@ #define _SYS_SOCKETVAR_H_ #include /* for TAILQ macros */ +#include +#include #include /* for struct selinfo */ /* @@ -48,27 +50,27 @@ */ typedef u_quad_t so_gen_t; +struct socket; +typedef void so_upcall_t(struct socket *, void *, int); + /* * List of locks: * (c) const, inited in either socreate() or sonewconn() * (m) sb_mtx mutex + * (mh) the mutex of so_head * (mr) so_rcv.sb_mtx mutex - * (sg) sigio_lock sx - * (sh) sohead_lock sx + * (sg) sigio_lock mutex * - * Lock of so_rcv.sb_mtx can duplicate, provided that sohead_lock - * is exclusively locked. - * - * Brackets mean that this data is not protected yet. + * Members marked by brackets are not locked yet. */ struct socket { - int so_count; /* reference count */ - short so_type; /* generic type, see socket.h */ - short so_options; /* from socket call, see socket.h */ - short so_linger; /* time to linger while closing */ - short so_state; /* internal state flags SS_*, below */ - caddr_t so_pcb; /* protocol control block */ - struct protosw *so_proto; /* protocol handle */ + int so_count; /* (mr) reference count */ + short so_type; /* (c) generic type, see socket.h */ + short so_options; /* (mr) from socket call, see socket.h */ + short so_linger; /* (mr) time to linger while closing */ + short so_state; /* (mr) internal state flags SS_*, below */ + caddr_t so_pcb; /* [mr] protocol control block */ + struct protosw *so_proto; /* (c) protocol handle */ /* * Variables for connection queuing. * Socket where accepts occur is so_head in all subsidiary sockets. @@ -80,33 +82,36 @@ struct socket { * We allow connections to queue up based on current queue lengths * and limit on number of queued connections for this socket. */ - struct socket *so_head; /* back pointer to accept socket */ - TAILQ_HEAD(, socket) so_incomp; /* queue of partial unaccepted connections */ - TAILQ_HEAD(, socket) so_comp; /* queue of complete unaccepted connections */ - TAILQ_ENTRY(socket) so_list; /* list of unaccepted connections */ - short so_qlen; /* number of unaccepted connections */ - short so_incqlen; /* number of unaccepted incomplete + struct socket *so_head; /* [mr] back pointer to accept socket */ + TAILQ_HEAD(, socket) so_incomp; /* [mr] queue of partial unaccepted connections */ + TAILQ_HEAD(, socket) so_comp; /* [mr] queue of complete unaccepted connections */ + TAILQ_ENTRY(socket) so_list; /* [mh] list of unaccepted connections */ + short so_qlen; /* [mr] number of unaccepted connections */ + short so_incqlen; /* [mr] number of unaccepted incomplete connections */ - short so_qlimit; /* max number queued connections */ - short so_timeo; /* connection timeout */ - u_short so_error; /* error affecting connection */ - struct sigio *so_sigio; /* [sg] information for async I/O or + short so_qlimit; /* [mr] max number queued connections */ + short so_timeo; /* [mr] connection timeout */ + u_short so_error; /* [mr] error affecting connection */ + struct sigio *so_sigio; /* (sg) information for async I/O or out of band data (SIGURG) */ - u_long so_oobmark; /* chars to oob mark */ - TAILQ_HEAD(, aiocblist) so_aiojobq; /* AIO ops waiting on socket */ + u_long so_oobmark; /* [mr] chars to oob mark */ + TAILQ_HEAD(, aiocblist) so_aiojobq; /* [mr] AIO ops waiting on socket */ /* * Variables for socket buffering. */ struct sockbuf { - u_long sb_cc; /* actual chars in buffer */ - u_long sb_hiwat; /* max actual char count */ - u_long sb_mbcnt; /* chars of mbufs used */ - u_long sb_mbmax; /* max chars of mbufs to use */ - long sb_lowat; /* low water mark */ - struct mbuf *sb_mb; /* the mbuf chain */ - struct selinfo sb_sel; /* process selecting read/write */ - short sb_flags; /* flags, see below */ - short sb_timeo; /* timeout for read/write */ +#define sb_startzero sb_cc + u_long sb_cc; /* [m] actual chars in buffer */ + u_long sb_hiwat; /* [m] max actual char count */ + u_long sb_mbcnt; /* [m] chars of mbufs used */ + u_long sb_mbmax; /* [m] max chars of mbufs to use */ + long sb_lowat; /* [m] low water mark */ + struct mbuf *sb_mb; /* [m] the mbuf chain */ + struct selinfo sb_sel; /* [m] process selecting read/write */ + short sb_flags; /* [m] flags, see below */ + short sb_timeo; /* [m] timeout for read/write */ +#define sb_endzero sb_timeo + struct mtx sb_mtx; /* mutex of this socket buffer */ } so_rcv, so_snd; #define SB_MAX (256*1024) /* default for max chars in sockbuf */ #define SB_LOCK 0x01 /* lock on data queue */ @@ -119,19 +124,35 @@ struct socket { #define SB_AIO 0x80 /* AIO operations queued */ #define SB_KNOTE 0x100 /* kernel note attached */ - void (*so_upcall)(struct socket *, void *, int); - void *so_upcallarg; - struct ucred *so_cred; /* user credentials */ + so_upcall_t *so_upcall; /* [mr] */ + void *so_upcallarg; /* [mr] */ + struct ucred *so_cred; /* (c) user credentials */ /* NB: generation count must not be first; easiest to make it last. */ - so_gen_t so_gencnt; /* generation count */ - void *so_emuldata; /* private data for emulators */ - struct so_accf { - struct accept_filter *so_accept_filter; - void *so_accept_filter_arg; /* saved filter args */ - char *so_accept_filter_str; /* saved user args */ - } *so_accf; + so_gen_t so_gencnt; /* [mr] generation count */ + void *so_emuldata; /* [mr] private data for emulators */ + struct so_accf { + struct accept_filter *so_accept_filter; /* [mr] */ + void *so_accept_filter_arg; /* [mr] saved filter args */ + char *so_accept_filter_str; /* [mr] saved user args */ + } *so_accf; /* [mr] */ }; +/* + * Macros to lock a socket. + */ +#define SOCKBUF_LOCK(sb) mtx_lock(&(sb)->sb_mtx) +#define SOCKBUF_TRYLOCK(sb) mtx_trylock(&(sb)->sb_mtx) +#define SOCKBUF_UNLOCK(sb) mtx_unlock(&(sb)->sb_mtx) +#define SOCKBUF_LOCKED(sb) mtx_owned(&(sb)->sb_mtx) +#define SOCKBUF_ASSERT(sb, type) mtx_assert(&(sb)->sb_mtx, type) + +#define SOCK_MTX(so) (&(so)->so_rcv.sb_mtx) +#define SOCK_LOCK(so) SOCKBUF_LOCK(&(so)->so_rcv) +#define SOCK_TRYLOCK(so) SOCKBUF_TRYLOCK(&(so)->so_rcv) +#define SOCK_UNLOCK(so) SOCKBUF_UNLOCK(&(so)->so_rcv) +#define SOCK_LOCKED(so) SOCKBUF_LOCKED(&(so)->so_rcv) +#define SOCK_ASSERT(so, type) SOCKBUF_ASSERT(&(so)->so_rcv, type) + /* * Socket state bits. */ @@ -260,39 +281,41 @@ struct xsocket { * still explicitly close the socket, but the last ref count will free * the structure. */ -#define soref(so) do { \ - ++(so)->so_count; \ + +#define soref(so) do { \ + SOCK_ASSERT(so, MA_OWNED); \ + ++(so)->so_count; \ } while (0) -#define sorele(so) do { \ +#define sorele(so) do { \ + SOCK_ASSERT(so, MA_OWNED); \ if ((so)->so_count <= 0) \ - panic("sorele");\ - if (--(so)->so_count == 0)\ - sofree(so); \ + panic("sorele"); \ + if (--(so)->so_count == 0) \ + sofree(so); \ + else \ + SOCK_UNLOCK(so); \ } while (0) -#define sotryfree(so) do { \ +#define sotryfree(so) do { \ + SOCK_ASSERT(so, MA_OWNED); \ if ((so)->so_count == 0) \ - sofree(so); \ + sofree(so); \ + else \ + SOCK_UNLOCK(so); \ } while(0) -#define sorwakeup_locked(so) do { \ - if (sb_notify(&(so)->so_rcv)) \ - sowakeup((so), &(so)->so_rcv); \ - } while (0) +#define sorwakeup(so) do { \ + SOCK_ASSERT(so, MA_OWNED); \ + if (sb_notify(&(so)->so_rcv)) \ + sowakeup((so), &(so)->so_rcv); \ + } while (0) -#define sorwakeup(so) do { \ - sorwakeup_locked(so); \ - } while (0) - -#define sowwakeup_locked(so) do { \ - if (sb_notify(&(so)->so_snd)) \ - sowakeup((so), &(so)->so_snd); \ - } while (0) - -#define sowwakeup(so) do { \ - sowwakeup_locked(so); \ - } while (0) +#define sowwakeup(so) do { \ + SOCK_ASSERT(so, MA_OWNED); \ + if (sb_notify(&(so)->so_snd)) \ + sowakeup((so), &(so)->so_snd); \ + } while (0) #ifdef _KERNEL @@ -402,14 +425,12 @@ int soconnect2(struct socket *so1, struct socket *so2); int socreate(int dom, struct socket **aso, int type, int proto, struct ucred *cred, struct thread *td); int sodisconnect(struct socket *so); -void soisconnected_locked(struct socket *so); void sofree(struct socket *so); int sogetopt(struct socket *so, struct sockopt *sopt); void sohasoutofband(struct socket *so); void soisconnected(struct socket *so); void soisconnecting(struct socket *so); void soisdisconnected(struct socket *so); -void soisdisconnected_locked(struct socket *so); void soisdisconnecting(struct socket *so); int solisten(struct socket *so, int backlog, struct thread *td); struct socket *