diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -3321,19 +3321,15 @@ /* mark any iterators on the list or being processed */ sctp_iterator_inp_being_freed(inp); SCTP_ITERATOR_UNLOCK(); - so = inp->sctp_socket; - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) { - /* been here before.. eeks.. get out of here */ - SCTP_PRINTF("This conflict in free SHOULD not be happening! from %d, imm %d\n", from, immediate); -#ifdef SCTP_LOG_CLOSING - sctp_log_closing(inp, NULL, 1); -#endif - return; - } + SCTP_ASOC_CREATE_LOCK(inp); SCTP_INP_INFO_WLOCK(); - SCTP_INP_WLOCK(inp); + so = inp->sctp_socket; + KASSERT((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) != 0, + ("%s: inp %p still has socket", __func__, inp)); + KASSERT((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0, + ("%s: double free of inp %p", __func__, inp)); if (from == SCTP_CALLED_AFTER_CMPSET_OFCLOSE) { inp->sctp_flags &= ~SCTP_PCB_FLAGS_CLOSE_IP; /* socket is gone, so no more wakeups allowed */ diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -416,24 +416,23 @@ { struct epoch_tracker et; struct sctp_inpcb *inp; - uint32_t flags; inp = (struct sctp_inpcb *)so->so_pcb; if (inp == NULL) { return; } + SCTP_INP_WLOCK(inp); NET_EPOCH_ENTER(et); -sctp_must_try_again: - flags = inp->sctp_flags; #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 17); #endif - if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && - (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { + if (((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0)) { + inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP; #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 16); #endif + SCTP_INP_WUNLOCK(inp); sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, SCTP_CALLED_AFTER_CMPSET_OFCLOSE); SOCK_LOCK(so); @@ -448,13 +447,9 @@ so->so_pcb = NULL; SOCK_UNLOCK(so); } else { - flags = inp->sctp_flags; - if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { - goto sctp_must_try_again; - } + SCTP_INP_WUNLOCK(inp); } NET_EPOCH_EXIT(et); - return; } static int @@ -516,7 +511,6 @@ { struct epoch_tracker et; struct sctp_inpcb *inp; - uint32_t flags; inp = (struct sctp_inpcb *)so->so_pcb; if (inp == NULL) @@ -525,25 +519,26 @@ /* * Inform all the lower layer assoc that we are done. */ + SCTP_INP_WLOCK(inp); NET_EPOCH_ENTER(et); -sctp_must_try_again: - flags = inp->sctp_flags; #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 17); #endif - if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && - (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { + if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { + inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP; if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || (so->so_rcv.sb_cc > 0)) { #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 13); #endif + SCTP_INP_WUNLOCK(inp); sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, SCTP_CALLED_AFTER_CMPSET_OFCLOSE); } else { #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 14); #endif + SCTP_INP_WUNLOCK(inp); sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, SCTP_CALLED_AFTER_CMPSET_OFCLOSE); } @@ -563,13 +558,9 @@ so->so_pcb = NULL; SOCK_UNLOCK(so); } else { - flags = inp->sctp_flags; - if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { - goto sctp_must_try_again; - } + SCTP_INP_WUNLOCK(inp); } NET_EPOCH_EXIT(et); - return; } int