diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index f0d282c..3c1a48b 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -617,6 +617,7 @@ uipc_close(struct socket *so) unp_disconnect(unp, unp2); UNP_PCB_UNLOCK(unp2); } + unp->unp_flags |= UNP_CLOSED; UNP_PCB_UNLOCK(unp); UNP_LINK_WUNLOCK(); } @@ -1382,12 +1383,36 @@ unp_connectat(int fd, struct socket *so, struct sockaddr *nam, goto bad2; } if (so->so_proto->pr_flags & PR_CONNREQUIRED) { + unp2 = NULL; if (so2->so_options & SO_ACCEPTCONN) { + unp2 = sotounpcb(so2); + UNP_PCB_LOCK(unp2); + unp2->unp_refcount++; + UNP_PCB_UNLOCK(unp2); + UNP_LINK_WUNLOCK(); + CURVNET_SET(so2->so_vnet); so3 = sonewconn(so2, 0); CURVNET_RESTORE(); + + UNP_LINK_WLOCK(); } else so3 = NULL; + if (unp2 != NULL) { + UNP_PCB_LOCK(unp2); + unp2->unp_refcount--; + + if ((unp2->unp_flags & UNP_CLOSED) != 0) + /* listening socket closed, so so3 is aborted */ + so3 = NULL; + + if (unp2->unp_refcount == 0) { + MPASS(so3 == NULL); + UNP_PCB_LOCK_DESTROY(unp2); + uma_zfree(unp_zone, unp2); + } else + UNP_PCB_UNLOCK(unp2); + } if (so3 == NULL) { error = ECONNREFUSED; goto bad2; diff --git a/sys/sys/unpcb.h b/sys/sys/unpcb.h index 41fd574..cf0215c 100644 --- a/sys/sys/unpcb.h +++ b/sys/sys/unpcb.h @@ -115,6 +115,7 @@ struct unpcb { */ #define UNP_CONNECTING 0x010 /* Currently connecting. */ #define UNP_BINDING 0x020 /* Currently binding. */ +#define UNP_CLOSED 0x040 /* Socket has been closed */ #define sotounpcb(so) ((struct unpcb *)((so)->so_pcb))