X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/91447636331957f3d9b5ca5b508f07c526b0074d..378393581903b274cb7a4d18e0d978071a6b592d:/bsd/kern/uipc_socket2.c diff --git a/bsd/kern/uipc_socket2.c b/bsd/kern/uipc_socket2.c index 2fb59d20f..30750607f 100644 --- a/bsd/kern/uipc_socket2.c +++ b/bsd/kern/uipc_socket2.c @@ -142,18 +142,22 @@ soisconnected(so) sflt_notify(so, sock_evt_connected, NULL); if (head && (so->so_state & SS_INCOMP)) { - if (head->so_proto->pr_getlock != NULL) + so->so_state &= ~SS_INCOMP; + so->so_state |= SS_COMP; + if (head->so_proto->pr_getlock != NULL) { + socket_unlock(so, 0); socket_lock(head, 1); + } postevent(head, 0, EV_RCONN); 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); - so->so_state |= SS_COMP; sorwakeup(head); wakeup_one((caddr_t)&head->so_timeo); - if (head->so_proto->pr_getlock != NULL) + if (head->so_proto->pr_getlock != NULL) { socket_unlock(head, 1); + socket_lock(so, 0); + } } else { postevent(so, 0, EV_WCONN); wakeup((caddr_t)&so->so_timeo); @@ -291,16 +295,19 @@ sonewconn_internal(head, connstatus) } /* - * Must be done with head unlocked to avoid deadlock with pcb list + * Must be done with head unlocked to avoid deadlock for protocol with per socket mutexes. */ - socket_unlock(head, 0); + if (head->so_proto->pr_unlock) + socket_unlock(head, 0); if (((*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL) != 0) || error) { sflt_termsock(so); sodealloc(so); - socket_lock(head, 0); + if (head->so_proto->pr_unlock) + socket_lock(head, 0); return ((struct socket *)0); } - socket_lock(head, 0); + if (head->so_proto->pr_unlock) + socket_lock(head, 0); #ifdef __APPLE__ so->so_proto->pr_domain->dom_refs++; #endif @@ -641,12 +648,15 @@ sbappend(sb, m) register struct mbuf *n, *sb_first; int result = 0; int error = 0; + int filtered = 0; KERNEL_DEBUG((DBG_FNC_SBAPPEND | DBG_FUNC_START), sb, m->m_len, 0, 0, 0); if (m == 0) return 0; + +again: sb_first = n = sb->sb_mb; if (n) { while (n->m_nextpkt) @@ -660,21 +670,22 @@ sbappend(sb, m) } while (n->m_next && (n = n->m_next)); } - if ((sb->sb_flags & SB_RECV) != 0) { - error = sflt_data_in(sb->sb_so, NULL, &m, NULL, 0); + if (!filtered && (sb->sb_flags & SB_RECV) != 0) { + error = sflt_data_in(sb->sb_so, NULL, &m, NULL, 0, &filtered); if (error) { /* no data was appended, caller should not call sowakeup */ return 0; } - } - - /* 3962537 - sflt_data_in may drop the lock, need to validate state again */ - if (sb_first != sb->sb_mb) { - n = sb->sb_mb; - if (n) { - while (n->m_nextpkt) - n = n->m_nextpkt; - } + + /* + If we any filters, the socket lock was dropped. n and sb_first + cached data from the socket buffer. This cache is not valid + since we dropped the lock. We must start over. Since filtered + is set we won't run through the filters a second time. We just + set n and sb_start again. + */ + if (filtered) + goto again; } result = sbcompress(sb, m, n); @@ -736,7 +747,7 @@ sbappendrecord(sb, m0) return 0; if ((sb->sb_flags & SB_RECV) != 0) { - int error = sflt_data_in(sb->sb_so, NULL, &m0, NULL, sock_data_filt_flag_record); + int error = sflt_data_in(sb->sb_so, NULL, &m0, NULL, sock_data_filt_flag_record, NULL); if (error != 0) { if (error != EJUSTRETURN) m_freem(m0); @@ -784,7 +795,7 @@ sbinsertoob(sb, m0) if ((sb->sb_flags & SB_RECV) != 0) { int error = sflt_data_in(sb->sb_so, NULL, &m0, NULL, - sock_data_filt_flag_oob); + sock_data_filt_flag_oob, NULL); if (error) { if (error != EJUSTRETURN) { @@ -895,7 +906,7 @@ sbappendaddr( /* Call socket data in filters */ if ((sb->sb_flags & SB_RECV) != 0) { int error; - error = sflt_data_in(sb->sb_so, asa, &m0, &control, 0); + error = sflt_data_in(sb->sb_so, asa, &m0, &control, 0, NULL); if (error) { if (error != EJUSTRETURN) { if (m0) m_freem(m0); @@ -964,7 +975,7 @@ sbappendcontrol( if (sb->sb_flags & SB_RECV) { int error; - error = sflt_data_in(sb->sb_so, NULL, &m0, &control, 0); + error = sflt_data_in(sb->sb_so, NULL, &m0, &control, 0, NULL); if (error) { if (error != EJUSTRETURN) { if (m0) m_freem(m0);