--- kern/uipc_socket.c	2006/02/12 15:00:33
+++ kern/uipc_socket.c	2006/02/21 23:55:13
@@ -1,6 +1,6 @@
 /*-
  * Copyright (c) 2004 The FreeBSD Foundation
- * Copyright (c) 2004-2005 Robert N. M. Watson
+ * Copyright (c) 2004-2006 Robert N. M. Watson
  * Copyright (c) 1982, 1986, 1988, 1990, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
@@ -31,6 +31,40 @@
  *	@(#)uipc_socket.c	8.3 (Berkeley) 4/15/94
  */
 
+/*
+ * Comments on the socket life cycle:
+ *
+ * soalloc() sets of socket layer state for a socket, called only by
+ * socreate().  Socket layer private.
+ *
+ * pru_attach() associates protocol layer state with an allocated socket;
+ * called only once, may fail, aborting socket allocation.  This is called
+ * from socreate().
+ *
+ * pru_detach() disassociates protocol layer state with an attached socket;
+ * this will be called only once, to notify the protocol that the socket
+ * layer is done with the socket.  However, if the protocol has acquired a
+ * strong socket reference by setting SS_PROTOREF, the socket layer will not
+ * allow sofree() to release the socket.  Once a pru_detach() has been
+ * received while holding a strong reference, the protocol is responsible for
+ * later calling sofree() to release the socket.  This is useful for
+ * protocols in which need for socket buffer contents may continue after
+ * socket close, in which case the protocol can take ownership of the socket
+ * until it is ready to release it.
+ *
+ * sodealloc() tears down socket layer state for a socket, called only by
+ * sofree().  Socket layer private.
+ *
+ * socreate() creates a socket and attaches protocol state.
+ * sonewconn() creates a socket and attaches protocol state.
+ * sofree() destroys a socket and detaches protocol layer state.
+ *
+ * soclose() destroys a socket after waiting for it to disconnect.
+ * soabort() destroys a socket without waiting for it to disconnect (used
+ * only for incoming connections that are already connected).  Calls
+ * pru_detach().
+ */
+
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/sys/kern/uipc_socket.c,v 1.257 2006/02/12 15:00:27 rwatson Exp $");
 
@@ -250,6 +284,8 @@
 {
 
 	KASSERT(so->so_count == 0, ("sodealloc(): so_count %d", so->so_count));
+	KASSERT(so->so_pcb == NULL, ("sodealloc(): so_pcb != NULL"));
+
 	mtx_lock(&so_global_mtx);
 	so->so_gencnt = ++so_gencnt;
 	mtx_unlock(&so_global_mtx);
@@ -328,13 +364,18 @@
 /*
  * Attempt to free a socket.  This should really be sotryfree().
  *
- * We free the socket if the protocol is no longer interested in the socket,
- * there's no file descriptor reference, and the refcount is 0.  While the
- * calling macro sotryfree() tests the refcount, sofree() has to test it
- * again as it's possible to race with an accept()ing thread if the socket is
- * in an listen queue of a listen socket, as being in the listen queue
- * doesn't elevate the reference count.  sofree() acquires the accept mutex
- * early for this test in order to avoid that race.
+ * sofree() will succeed if:
+ *
+ * - There are no outstanding file descriptor references or related consumers
+ *   (so_count == 0).
+ *
+ * - The socket has been closed by user space, if ever open (SS_NOFDREF).
+ *
+ * - The protocol does not have an outstanding strong reference on the socket
+ *   (SS_PROTOREF).
+ *
+ * Otherwise, it will quietly abort so that a future call to sofree(), when
+ * conditions are right, can succeed.
  */
 void
 sofree(so)
@@ -345,8 +386,8 @@
 	ACCEPT_LOCK_ASSERT();
 	SOCK_LOCK_ASSERT(so);
 
-	if (so->so_pcb != NULL || (so->so_state & SS_NOFDREF) == 0 ||
-	    so->so_count != 0) {
+	if ((so->so_state & SS_NOFDREF) == 0 || so->so_count != 0 ||
+	    (so->so_state & SS_PROTOREF)) {
 		SOCK_UNLOCK(so);
 		ACCEPT_UNLOCK();
 		return;
@@ -388,6 +429,7 @@
 	    so->so_qstate & SQ_COMP, so->so_qstate & SQ_INCOMP));
 	SOCK_UNLOCK(so);
 	ACCEPT_UNLOCK();
+
 	SOCKBUF_LOCK(&so->so_snd);
 	so->so_snd.sb_flags |= SB_NOINTR;
 	(void)sblock(&so->so_snd, M_WAITOK);
@@ -448,8 +490,6 @@
 		}
 		ACCEPT_UNLOCK();
 	}
-	if (so->so_pcb == NULL)
-		goto discard;
 	if (so->so_state & SS_ISCONNECTED) {
 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
 			error = sodisconnect(so);
@@ -468,13 +508,9 @@
 			}
 		}
 	}
+
 drop:
-	if (so->so_pcb != NULL) {
-		int error2 = (*so->so_proto->pr_usrreqs->pru_detach)(so);
-		if (error == 0)
-			error = error2;
-	}
-discard:
+	(*so->so_proto->pr_usrreqs->pru_detach)(so);
 	ACCEPT_LOCK();
 	SOCK_LOCK(so);
 	KASSERT((so->so_state & SS_NOFDREF) == 0, ("soclose: NOFDREF"));
@@ -488,21 +524,26 @@
  * into the protocol, which will call back into the socket code causing
  * it to acquire additional socket locks that may cause recursion or lock
  * order reversals.
+ *
+ * soabort() is used to abort a received but unaccepted connection, as
+ * it doesn't have any valid references yet.
+ *
+ * XXXRW: Why do we maintain a distinction between pru_abort() and
+ * pru_detach()?
+ *
+ * XXXRW: Right now we don't attempt to handle SS_PROTOREF here.
  */
-int
+void
 soabort(so)
 	struct socket *so;
 {
-	int error;
+
+	KASSERT(so->so_count == 0, ("soabort: so_count"));
 
-	error = (*so->so_proto->pr_usrreqs->pru_abort)(so);
-	if (error) {
-		ACCEPT_LOCK();
-		SOCK_LOCK(so);
-		sotryfree(so);	/* note: does not decrement the ref count */
-		return (error);
-	}
-	return (0);
+	(*so->so_proto->pr_usrreqs->pru_abort)(so);
+	ACCEPT_LOCK();
+	SOCK_LOCK(so);
+	sofree(so);
 }
 
 int
@@ -1527,7 +1568,7 @@
 			 * Notify the protocol that some data has been
 			 * drained before blocking.
 			 */
-			if (pr->pr_flags & PR_WANTRCVD && so->so_pcb != NULL) {
+			if (pr->pr_flags & PR_WANTRCVD) {
 				SOCKBUF_UNLOCK(&so->so_rcv);
 				(*pr->pr_usrreqs->pru_rcvd)(so, flags);
 				SOCKBUF_LOCK(&so->so_rcv);
@@ -1571,7 +1612,7 @@
 		 * ACK will be generated on return to TCP.
 		 */
 		if (!(flags & MSG_SOCALLBCK) && 
-		    (pr->pr_flags & PR_WANTRCVD) && so->so_pcb) {
+		    (pr->pr_flags & PR_WANTRCVD)) {
 			SOCKBUF_UNLOCK(&so->so_rcv);
 			(*pr->pr_usrreqs->pru_rcvd)(so, flags);
 			SOCKBUF_LOCK(&so->so_rcv);
--- kern/uipc_socket2.c	2005/11/22 01:56:03
+++ kern/uipc_socket2.c	2006/02/13 21:54:01
@@ -1282,10 +1282,10 @@
  * Some routines that return EOPNOTSUPP for entry points that are not
  * supported by a protocol.  Fill in as needed.
  */
-int
+void
 pru_abort_notsupp(struct socket *so)
 {
-	return EOPNOTSUPP;
+
 }
 
 int
@@ -1325,10 +1325,10 @@
 	return EOPNOTSUPP;
 }
 
-int
+void
 pru_detach_notsupp(struct socket *so)
 {
-	return EOPNOTSUPP;
+
 }
 
 int
--- kern/uipc_usrreq.c	2006/01/30 08:24:26
+++ kern/uipc_usrreq.c	2006/02/13 21:54:59
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 1982, 1986, 1989, 1991, 1993
  *	The Regents of the University of California.
- * Copyright 2004-2005 Robert N. M. Watson
+ * Copyright 2004-2006 Robert N. M. Watson
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -139,24 +139,17 @@
 static int     unp_listen(struct socket *, struct unpcb *, int,
 		   struct thread *);
 
-static int
+static void
 uipc_abort(struct socket *so)
 {
 	struct unpcb *unp;
 
+	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("uipc_abort: unp == NULL"));
 	UNP_LOCK();
-	unp = sotounpcb(so);
-	if (unp == NULL) {
-		UNP_UNLOCK();
-		return (EINVAL);
-	}
 	unp_drop(unp, ECONNABORTED);
 	unp_detach(unp);
 	UNP_UNLOCK_ASSERT();
-	ACCEPT_LOCK();
-	SOCK_LOCK(so);
-	sotryfree(so);
-	return (0);
 }
 
 static int
@@ -170,15 +163,10 @@
 	 * if it was bound and we are still connected
 	 * (our peer may have closed already!).
 	 */
+	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("uipc_accept: unp == NULL"));
 	*nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK);
 	UNP_LOCK();
-	unp = sotounpcb(so);
-	if (unp == NULL) {
-		UNP_UNLOCK();
-		free(*nam, M_SONAME);
-		*nam = NULL;
-		return (EINVAL);
-	}
 	if (unp->unp_conn != NULL && unp->unp_conn->unp_addr != NULL)
 		sa = (struct sockaddr *) unp->unp_conn->unp_addr;
 	else
@@ -191,10 +179,7 @@
 static int
 uipc_attach(struct socket *so, int proto, struct thread *td)
 {
-	struct unpcb *unp = sotounpcb(so);
 
-	if (unp != NULL)
-		return (EISCONN);
 	return (unp_attach(so));
 }
 
@@ -204,12 +189,9 @@
 	struct unpcb *unp;
 	int error;
 
+	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("uipc_bind: unp == NULL"));
 	UNP_LOCK();
-	unp = sotounpcb(so);
-	if (unp == NULL) {
-		UNP_UNLOCK();
-		return (EINVAL);
-	}
 	error = unp_bind(unp, nam, td);
 	UNP_UNLOCK();
 	return (error);
@@ -223,12 +205,9 @@
 
 	KASSERT(td == curthread, ("uipc_connect: td != curthread"));
 
+	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("uipc_connect: unp == NULL"));
 	UNP_LOCK();
-	unp = sotounpcb(so);
-	if (unp == NULL) {
-		UNP_UNLOCK();
-		return (EINVAL);
-	}
 	error = unp_connect(so, nam, td);
 	UNP_UNLOCK();
 	return (error);
@@ -240,12 +219,9 @@
 	struct unpcb *unp;
 	int error;
 
+	unp = sotounpcb(so1);
+	KASSERT(unp != NULL, ("uipc_connect2: unp == NULL"));
 	UNP_LOCK();
-	unp = sotounpcb(so1);
-	if (unp == NULL) {
-		UNP_UNLOCK();
-		return (EINVAL);
-	}
 	error = unp_connect2(so1, so2, PRU_CONNECT2);
 	UNP_UNLOCK();
 	return (error);
@@ -253,20 +229,16 @@
 
 /* control is EOPNOTSUPP */
 
-static int
+static void
 uipc_detach(struct socket *so)
 {
 	struct unpcb *unp;
 
+	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("uipc_detach: unp == NULL"));
 	UNP_LOCK();
-	unp = sotounpcb(so);
-	if (unp == NULL) {
-		UNP_UNLOCK();
-		return (EINVAL);
-	}
 	unp_detach(unp);
 	UNP_UNLOCK_ASSERT();
-	return (0);
 }
 
 static int
@@ -274,12 +246,9 @@
 {
 	struct unpcb *unp;
 
+	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("uipc_disconnect: unp == NULL"));
 	UNP_LOCK();
-	unp = sotounpcb(so);
-	if (unp == NULL) {
-		UNP_UNLOCK();
-		return (EINVAL);
-	}
 	unp_disconnect(unp);
 	UNP_UNLOCK();
 	return (0);
@@ -291,9 +260,10 @@
 	struct unpcb *unp;
 	int error;
 
+	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("uipc_listen: unp == NULL"));
 	UNP_LOCK();
-	unp = sotounpcb(so);
-	if (unp == NULL || unp->unp_vnode == NULL) {
+	if (unp->unp_vnode == NULL) {
 		UNP_UNLOCK();
 		return (EINVAL);
 	}
@@ -308,15 +278,10 @@
 	struct unpcb *unp;
 	const struct sockaddr *sa;
 
+	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("uipc_peeraddr: unp == NULL"));
 	*nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK);
 	UNP_LOCK();
-	unp = sotounpcb(so);
-	if (unp == NULL) {
-		UNP_UNLOCK();
-		free(*nam, M_SONAME);
-		*nam = NULL;
-		return (EINVAL);
-	}
 	if (unp->unp_conn != NULL && unp->unp_conn->unp_addr!= NULL)
 		sa = (struct sockaddr *) unp->unp_conn->unp_addr;
 	else {
@@ -339,12 +304,9 @@
 	struct socket *so2;
 	u_long newhiwat;
 
+	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("uipc_rcvd: unp == NULL"));
 	UNP_LOCK();
-	unp = sotounpcb(so);
-	if (unp == NULL) {
-		UNP_UNLOCK();
-		return (EINVAL);
-	}
 	switch (so->so_type) {
 	case SOCK_DGRAM:
 		panic("uipc_rcvd DGRAM?");
@@ -390,10 +352,7 @@
 	u_long newhiwat;
 
 	unp = sotounpcb(so);
-	if (unp == NULL) {
-		error = EINVAL;
-		goto release;
-	}
+	KASSERT(unp != NULL, ("uipc_send: unp == NULL"));
 	if (flags & PRUS_OOB) {
 		error = EOPNOTSUPP;
 		goto release;
@@ -403,13 +362,6 @@
 		goto release;
 
 	UNP_LOCK();
-	unp = sotounpcb(so);
-	if (unp == NULL) {
-		UNP_UNLOCK();
-		error = EINVAL;
-		goto dispose_release;
-	}
-
 	switch (so->so_type) {
 	case SOCK_DGRAM:
 	{
@@ -523,7 +475,6 @@
 	}
 	UNP_UNLOCK();
 
-dispose_release:
 	if (control != NULL && error != 0)
 		unp_dispose(control);
 
@@ -541,12 +492,9 @@
 	struct unpcb *unp;
 	struct socket *so2;
 
+	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("uipc_sense: unp == NULL"));
 	UNP_LOCK();
-	unp = sotounpcb(so);
-	if (unp == NULL) {
-		UNP_UNLOCK();
-		return (EINVAL);
-	}
 	sb->st_blksize = so->so_snd.sb_hiwat;
 	if (so->so_type == SOCK_STREAM && unp->unp_conn != NULL) {
 		so2 = unp->unp_conn->unp_socket;
@@ -565,12 +513,9 @@
 {
 	struct unpcb *unp;
 
+	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("uipc_shutdown: unp == NULL"));
 	UNP_LOCK();
-	unp = sotounpcb(so);
-	if (unp == NULL) {
-		UNP_UNLOCK();
-		return (EINVAL);
-	}
 	socantsendmore(so);
 	unp_shutdown(unp);
 	UNP_UNLOCK();
@@ -583,15 +528,10 @@
 	struct unpcb *unp;
 	const struct sockaddr *sa;
 
+	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("uipc_sockaddr: unp == NULL"));
 	*nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK);
 	UNP_LOCK();
-	unp = sotounpcb(so);
-	if (unp == NULL) {
-		UNP_UNLOCK();
-		free(*nam, M_SONAME);
-		*nam = NULL;
-		return (EINVAL);
-	}
 	if (unp->unp_addr != NULL)
 		sa = (struct sockaddr *) unp->unp_addr;
 	else
@@ -632,14 +572,10 @@
 	if (sopt->sopt_level != 0)
 		return (EINVAL);
 
+	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("uipc_ctloutput: unp == NULL"));
 	UNP_LOCK();
-	unp = sotounpcb(so);
-	if (unp == NULL) {
-		UNP_UNLOCK();
-		return (EINVAL);
-	}
 	error = 0;
-
 	switch (sopt->sopt_dir) {
 	case SOPT_GET:
 		switch (sopt->sopt_name) {
@@ -745,6 +681,8 @@
 	struct unpcb *unp;
 	int error;
 
+	KASSERT(so->so_pcb == NULL, ("unp_attach: so_pcb != NULL"));
+
 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
 		switch (so->so_type) {
 
@@ -926,7 +864,9 @@
 	struct sockaddr *sa;
 
 	UNP_LOCK_ASSERT();
+
 	unp = sotounpcb(so);
+	KASSERT(unp != NULL, ("unp_connect: unp == NULL"));
 
 	len = nam->sa_len - offsetof(struct sockaddr_un, sun_path);
 	if (len <= 0)
@@ -956,10 +896,7 @@
 	mtx_unlock(&Giant);
 	UNP_LOCK();
 	unp = sotounpcb(so);
-	if (unp == NULL) {
-		error = EINVAL;
-		goto bad2;
-	}
+	KASSERT(unp != NULL, ("unp_connect: unp == NULL"));
 	so2 = vp->v_socket;
 	if (so2 == NULL) {
 		error = ECONNREFUSED;
@@ -1049,6 +986,7 @@
 	if (so2->so_type != so->so_type)
 		return (EPROTOTYPE);
 	unp2 = sotounpcb(so2);
+	KASSERT(unp2 != NULL, ("unp_connect2: unp2 == NULL"));
 	unp->unp_conn = unp2;
 	switch (so->so_type) {
 
--- net/raw_cb.c	2005/01/24 23:00:55
+++ net/raw_cb.c	2006/02/12 16:46:58
@@ -98,10 +98,9 @@
 {
 	struct socket *so = rp->rcb_socket;
 
-	ACCEPT_LOCK();
-	SOCK_LOCK(so);
-	so->so_pcb = 0;
-	sotryfree(so);
+	KASSERT(so->so_pcb == rp, ("raw_detach: so_pcb != rp"));
+
+	so->so_pcb = NULL;
 	mtx_lock(&rawcb_mtx);
 	LIST_REMOVE(rp, list);
 	mtx_unlock(&rawcb_mtx);
--- net/raw_usrreq.c	2005/01/07 01:52:23
+++ net/raw_usrreq.c	2006/02/19 18:36:12
@@ -138,19 +138,14 @@
 	/* INCOMPLETE */
 }
 
-static int
+static void
 raw_uabort(struct socket *so)
 {
 	struct rawcb *rp = sotorawcb(so);
 
-	if (rp == 0)
-		return EINVAL;
+	KASSERT(rp != NULL, ("raw_uabort: rp == NULL"));
 	raw_disconnect(rp);
 	soisdisconnected(so);
-	ACCEPT_LOCK();
-	SOCK_LOCK(so);
-	sotryfree(so);
-	return 0;
 }
 
 /* pru_accept is EOPNOTSUPP */
@@ -158,11 +153,9 @@
 static int
 raw_uattach(struct socket *so, int proto, struct thread *td)
 {
-	struct rawcb *rp = sotorawcb(so);
 	int error;
 
-	if (rp == 0)
-		return EINVAL;
+	KASSERT(sotorawcb(so) == NULL, ("raw_uattach: rp != NULL"));
 	if (td && (error = suser(td)) != 0)
 		return error;
 	return raw_attach(so, proto);
@@ -183,16 +176,13 @@
 /* pru_connect2 is EOPNOTSUPP */
 /* pru_control is EOPNOTSUPP */
 
-static int
+static void
 raw_udetach(struct socket *so)
 {
 	struct rawcb *rp = sotorawcb(so);
 
-	if (rp == 0)
-		return EINVAL;
-
+	KASSERT(rp != NULL, ("raw_udetach: rp == NULL"));
 	raw_detach(rp);
-	return 0;
 }
 
 static int
@@ -200,8 +190,7 @@
 {
 	struct rawcb *rp = sotorawcb(so);
 
-	if (rp == 0)
-		return EINVAL;
+	KASSERT(rp != NULL, ("raw_udisconnect: rp == NULL"));
 	if (rp->rcb_faddr == 0) {
 		return ENOTCONN;
 	}
@@ -217,8 +206,7 @@
 {
 	struct rawcb *rp = sotorawcb(so);
 
-	if (rp == 0)
-		return EINVAL;
+	KASSERT(rp != NULL, ("raw_upeeraddr: rp == NULL"));
 	if (rp->rcb_faddr == 0) {
 		return ENOTCONN;
 	}
@@ -236,10 +224,7 @@
 	int error;
 	struct rawcb *rp = sotorawcb(so);
 
-	if (rp == 0) {
-		error = EINVAL;
-		goto release;
-	}
+	KASSERT(rp != NULL, ("raw_usend: rp == NULL"));
 
 	if (flags & PRUS_OOB) {
 		error = EOPNOTSUPP;
@@ -275,10 +260,8 @@
 static int
 raw_ushutdown(struct socket *so)
 {
-	struct rawcb *rp = sotorawcb(so);
 
-	if (rp == 0)
-		return EINVAL;
+	KASSERT(sotorawcb(so) != NULL, ("raw_ushutdown: rp == NULL"));
 	socantsendmore(so);
 	return 0;
 }
@@ -288,8 +271,7 @@
 {
 	struct rawcb *rp = sotorawcb(so);
 
-	if (rp == 0)
-		return EINVAL;
+	KASSERT(rp != NULL, ("raw_usockaddr: rp == NULL"));
 	if (rp->rcb_laddr == 0)
 		return EINVAL;
 	*nam = sodupsockaddr(rp->rcb_laddr, M_WAITOK);
--- net/rtsock.c	2005/11/11 16:05:46
+++ net/rtsock.c	2006/02/13 21:56:55
@@ -137,11 +137,11 @@
  * It really doesn't make any sense at all for this code to share much
  * with raw_usrreq.c, since its functionality is so restricted.  XXX
  */
-static int
+static void
 rts_abort(struct socket *so)
 {
 
-	return (raw_usrreqs.pru_abort(so));
+	raw_usrreqs.pru_abort(so);
 }
 
 /* pru_accept is EOPNOTSUPP */
@@ -152,8 +152,8 @@
 	struct rawcb *rp;
 	int s, error;
 
-	if (sotorawcb(so) != NULL)
-		return EISCONN;	/* XXX panic? */
+	KASSERT(so->so_pcb == NULL, ("rts_attach: so_pcb != NULL"));
+
 	/* XXX */
 	MALLOC(rp, struct rawcb *, sizeof *rp, M_PCB, M_WAITOK | M_ZERO);
 	if (rp == NULL)
@@ -214,32 +214,28 @@
 /* pru_connect2 is EOPNOTSUPP */
 /* pru_control is EOPNOTSUPP */
 
-static int
+static void
 rts_detach(struct socket *so)
 {
 	struct rawcb *rp = sotorawcb(so);
-	int s, error;
+
+	KASSERT(rp != NULL, ("rts_detach: rp == NULL"));
 
-	s = splnet();
-	if (rp != NULL) {
-		RTSOCK_LOCK();
-		switch(rp->rcb_proto.sp_protocol) {
-		case AF_INET:
-			route_cb.ip_count--;
-			break;
-		case AF_INET6:
-			route_cb.ip6_count--;
-			break;
-		case AF_IPX:
-			route_cb.ipx_count--;
-			break;
-		}
-		route_cb.any_count--;
-		RTSOCK_UNLOCK();
+	RTSOCK_LOCK();
+	switch(rp->rcb_proto.sp_protocol) {
+	case AF_INET:
+		route_cb.ip_count--;
+		break;
+	case AF_INET6:
+		route_cb.ip6_count--;
+		break;
+	case AF_IPX:
+		route_cb.ipx_count--;
+		break;
 	}
-	error = raw_usrreqs.pru_detach(so);
-	splx(s);
-	return error;
+	route_cb.any_count--;
+	RTSOCK_UNLOCK();
+	raw_usrreqs.pru_detach(so);
 }
 
 static int
--- netatalk/ddp_pcb.c	2005/01/07 02:37:15
+++ netatalk/ddp_pcb.c	2006/02/12 17:21:38
@@ -304,10 +304,7 @@
     DDP_LOCK_ASSERT(ddp);
 
     soisdisconnected(so);
-    ACCEPT_LOCK();
-    SOCK_LOCK(so);
     so->so_pcb = NULL;
-    sotryfree(so);
 
     /* remove ddp from ddp_ports list */
     if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
--- netatalk/ddp_usrreq.c	2005/02/18 10:57:04
+++ netatalk/ddp_usrreq.c	2006/02/15 20:26:05
@@ -56,8 +56,7 @@
 	int		error = 0;
 	
 	ddp = sotoddpcb(so);
-	if (ddp != NULL)
-		return (EINVAL);
+	KASSERT(ddp == NULL, ("ddp_attach: ddp != NULL"));
 
 	/*
 	 * Allocate socket buffer space first so that it's present
@@ -73,20 +72,18 @@
 	return (error);
 }
 
-static int
+static void
 ddp_detach(struct socket *so)
 {
 	struct ddpcb	*ddp;
 	
 	ddp = sotoddpcb(so);
-	if (ddp == NULL)
-	    return (EINVAL);
+	KASSERT(ddp != NULL, ("ddp_detach: ddp == NULL"));
 
 	DDP_LIST_XLOCK();
 	DDP_LOCK(ddp);
 	at_pcbdetach(so, ddp);
 	DDP_LIST_XUNLOCK();
-	return (0);
 }
 
 static int      
@@ -96,9 +93,8 @@
 	int		error = 0;
 	
 	ddp = sotoddpcb(so);
-	if (ddp == NULL) {
-	    return (EINVAL);
-	}
+	KASSERT(ddp != NULL, ("ddp_bind: ddp == NULL"));
+
 	DDP_LIST_XLOCK();
 	DDP_LOCK(ddp);
 	error = at_pcbsetaddr(ddp, nam, td);
@@ -114,9 +110,7 @@
 	int		error = 0;
 	
 	ddp = sotoddpcb(so);
-	if (ddp == NULL) {
-	    return (EINVAL);
-	}
+	KASSERT(ddp != NULL, ("ddp_connect: ddp == NULL"));
 
 	DDP_LIST_XLOCK();
 	DDP_LOCK(ddp);
@@ -141,9 +135,7 @@
 	struct ddpcb	*ddp;
 	
 	ddp = sotoddpcb(so);
-	if (ddp == NULL) {
-	    return (EINVAL);
-	}
+	KASSERT(ddp != NULL, ("ddp_disconnect: ddp == NULL"));
 	DDP_LOCK(ddp);
 	if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) {
 	    DDP_UNLOCK(ddp);
@@ -163,9 +155,7 @@
 	struct ddpcb	*ddp;
 
 	ddp = sotoddpcb(so);
-	if (ddp == NULL) {
-		return (EINVAL);
-	}
+	KASSERT(ddp != NULL, ("ddp_shutdown: ddp == NULL"));
 	socantsendmore(so);
 	return (0);
 }
@@ -178,9 +168,7 @@
 	int		error = 0;
 	
 	ddp = sotoddpcb(so);
-	if (ddp == NULL) {
-		return (EINVAL);
-	}
+	KASSERT(ddp != NULL, ("ddp_send: ddp == NULL"));
 
     	if (control && control->m_len) {
 		return (EINVAL);
@@ -213,20 +201,17 @@
 	return (error);
 }
 
-static int
+static void
 ddp_abort(struct socket *so)
 {
 	struct ddpcb	*ddp;
 	
 	ddp = sotoddpcb(so);
-	if (ddp == NULL) {
-		return (EINVAL);
-	}
+	KASSERT(ddp != NULL, ("ddp_abort: ddp == NULL"));
 	DDP_LIST_XLOCK();
 	DDP_LOCK(ddp);
 	at_pcbdetach(so, ddp);
 	DDP_LIST_XUNLOCK();
-	return (0);
 }
 
 void 
@@ -269,9 +254,7 @@
 	struct ddpcb	*ddp;
 
 	ddp = sotoddpcb(so);
-	if (ddp == NULL) {
-	    return (EINVAL);
-	}
+	KASSERT(ddp != NULL, ("at_setsockaddr: ddp == NULL"));
 	DDP_LOCK(ddp);
 	at_sockaddr(ddp, nam);
 	DDP_UNLOCK(ddp);
--- netatm/atm_aal5.c	2005/10/30 19:45:29
+++ netatm/atm_aal5.c	2006/02/15 20:28:21
@@ -66,7 +66,7 @@
  * Local functions
  */
 static int	atm_aal5_attach(struct socket *, int, struct thread *td);
-static int	atm_aal5_detach(struct socket *);
+static void	atm_aal5_detach(struct socket *);
 static int	atm_aal5_bind(struct socket *, struct sockaddr *, 
 			struct thread *td);
 static int	atm_aal5_listen(struct socket *, int backlog,
@@ -78,7 +78,7 @@
 static int	atm_aal5_shutdown(struct socket *);
 static int	atm_aal5_send(struct socket *, int, KBuffer *,
 			struct sockaddr *, KBuffer *, struct thread *td);
-static int	atm_aal5_abort(struct socket *);
+static void	atm_aal5_abort(struct socket *);
 static int	atm_aal5_control(struct socket *, u_long, caddr_t, 
 			struct ifnet *, struct thread *td);
 static int	atm_aal5_sense(struct socket *, struct stat *);
@@ -204,6 +204,11 @@
 	;
 #endif /* DIAGNOSTIC */
 
+#define	ATM_INTRO_NOERR(f)					\
+	int		s;					\
+	s = splnet();						\
+	;
+
 #define	ATM_OUTRO()						\
 	/*							\
 	 * Drain any deferred calls				\
@@ -213,6 +218,14 @@
 	return (err);						\
 	;
 
+#define	ATM_OUTRO_NOERR()					\
+	/*							\
+	 * Drain any deferred calls				\
+	 */							\
+	STACK_DRAIN();						\
+	(void) splx(s);						\
+	;
+
 #define	ATM_RETERR(errno) {					\
 	err = errno;						\
 	goto out;						\
@@ -277,15 +290,15 @@
  *	errno	error processing request - reason indicated
  *
  */
-static int
+static void
 atm_aal5_detach(so)
 	struct socket	*so;
 {
-	ATM_INTRO("detach");
+	ATM_INTRO_NOERR("detach");
 
-	err = atm_sock_detach(so);
+	atm_sock_detach(so);
 
-	ATM_OUTRO();
+	ATM_OUTRO_NOERR();
 }
 
 
@@ -546,16 +559,16 @@
  *	errno	error processing request - reason indicated
  *
  */
-static int
+static void
 atm_aal5_abort(so)
 	struct socket	*so;
 {
-	ATM_INTRO("abort");
+	ATM_INTRO_NOERR("abort");
 
 	so->so_error = ECONNABORTED;
-	err = atm_sock_detach(so);
+	atm_sock_detach(so);
 
-	ATM_OUTRO();
+	ATM_OUTRO_NOERR();
 }
 
 
--- netatm/atm_proto.c	2005/11/09 13:31:29
+++ netatm/atm_proto.c	2006/02/12 18:36:34
@@ -184,3 +184,17 @@
 {
 	return (EOPNOTSUPP);
 }
+
+/*
+ * Protocol request not supported
+ *
+ * Arguments:
+ *	so	pointer to socket
+ *
+ */
+void
+atm_proto_notsupp5(so)
+	struct socket	*so;
+{
+
+}
--- netatm/atm_socket.c	2005/10/30 19:45:29
+++ netatm/atm_socket.c	2006/02/12 18:36:34
@@ -146,12 +146,8 @@
  * Arguments:
  *	so	pointer to socket
  *
- * Returns:
- *	0	detach successful
- *	errno	detach failed - reason indicated
- *
  */
-int
+void
 atm_sock_detach(so)
 	struct socket	*so;
 {
@@ -160,8 +156,7 @@
 	/*
 	 * Make sure we're still attached
 	 */
-	if (atp == NULL)
-		return (ENOTCONN);
+	KASSERT(atp != NULL, ("atm_sock_detach: atp == NULL"));
 
 	/*
 	 * Terminate any (possibly pending) connection
@@ -170,17 +165,9 @@
 		(void) atm_sock_disconnect(so);
 	}
 
-	/*
-	 * Break links and free control blocks
-	 */
-	ACCEPT_LOCK();
-	SOCK_LOCK(so);
 	so->so_pcb = NULL;
-	sotryfree(so);
 
 	uma_zfree(atm_pcb_zone, atp);
-
-	return (0);
 }
 
 
--- netatm/atm_usrreq.c	2005/06/10 16:51:34
+++ netatm/atm_usrreq.c	2006/02/15 20:28:21
@@ -66,11 +66,11 @@
  * New-style socket request routines
  */
 struct pr_usrreqs	atm_dgram_usrreqs = {
-	.pru_abort =		atm_proto_notsupp1,
+	.pru_abort =		atm_proto_notsupp5,
 	.pru_attach =		atm_dgram_attach,
 	.pru_bind =		atm_proto_notsupp2,
 	.pru_control =		atm_dgram_control,
-	.pru_detach =		atm_proto_notsupp1,
+	.pru_detach =		atm_proto_notsupp5,
 	.pru_disconnect =	atm_proto_notsupp1,
 	.pru_peeraddr =		atm_proto_notsupp3,
 	.pru_send =		atm_proto_notsupp4,
--- netatm/atm_var.h	2005/10/30 19:45:29
+++ netatm/atm_var.h	2006/02/12 18:36:34
@@ -136,6 +136,7 @@
 int		atm_proto_notsupp3(struct socket *, struct sockaddr **);
 int		atm_proto_notsupp4(struct socket *, int, KBuffer *, 
 			struct sockaddr *, KBuffer *, struct thread *);
+void		atm_proto_notsupp5(struct socket *);
 
 	/* atm_signal.c */
 int		atm_sigmgr_register(struct sigmgr *);
@@ -150,7 +151,7 @@
 	/* atm_socket.c */
 void		atm_sock_init(void);
 int		atm_sock_attach(struct socket *, u_long, u_long);
-int		atm_sock_detach(struct socket *);
+void		atm_sock_detach(struct socket *);
 int		atm_sock_bind(struct socket *, struct sockaddr *);
 int		atm_sock_listen(struct socket *, Atm_endpoint *, int);
 int		atm_sock_connect(struct socket *, struct sockaddr *,
--- netgraph/bluetooth/include/ng_btsocket_hci_raw.h	2005/01/07 01:52:23
+++ netgraph/bluetooth/include/ng_btsocket_hci_raw.h	2006/02/14 02:16:05
@@ -66,7 +66,7 @@
 #ifdef _KERNEL
 
 void ng_btsocket_hci_raw_init       (void);
-int  ng_btsocket_hci_raw_abort      (struct socket *);
+void ng_btsocket_hci_raw_abort      (struct socket *);
 int  ng_btsocket_hci_raw_attach     (struct socket *, int, struct thread *);
 int  ng_btsocket_hci_raw_bind       (struct socket *, struct sockaddr *, 
                                      struct thread *);
@@ -75,7 +75,7 @@
 int  ng_btsocket_hci_raw_control    (struct socket *, u_long, caddr_t,
                                      struct ifnet *, struct thread *);
 int  ng_btsocket_hci_raw_ctloutput  (struct socket *, struct sockopt *);
-int  ng_btsocket_hci_raw_detach     (struct socket *);
+void ng_btsocket_hci_raw_detach     (struct socket *);
 int  ng_btsocket_hci_raw_disconnect (struct socket *);
 int  ng_btsocket_hci_raw_peeraddr   (struct socket *, struct sockaddr **);
 int  ng_btsocket_hci_raw_send       (struct socket *, int, struct mbuf *,
--- netgraph/bluetooth/include/ng_btsocket_l2cap.h	2005/10/30 19:45:29
+++ netgraph/bluetooth/include/ng_btsocket_l2cap.h	2006/02/14 02:16:05
@@ -92,7 +92,7 @@
 #ifdef _KERNEL
 
 void ng_btsocket_l2cap_raw_init       (void);
-int  ng_btsocket_l2cap_raw_abort      (struct socket *);
+void ng_btsocket_l2cap_raw_abort      (struct socket *);
 int  ng_btsocket_l2cap_raw_attach     (struct socket *, int, struct thread *);
 int  ng_btsocket_l2cap_raw_bind       (struct socket *, struct sockaddr *,
                                        struct thread *);
@@ -100,7 +100,7 @@
                                        struct thread *);
 int  ng_btsocket_l2cap_raw_control    (struct socket *, u_long, caddr_t,
                                        struct ifnet *, struct thread *);
-int  ng_btsocket_l2cap_raw_detach     (struct socket *);
+void ng_btsocket_l2cap_raw_detach     (struct socket *);
 int  ng_btsocket_l2cap_raw_disconnect (struct socket *);
 int  ng_btsocket_l2cap_raw_peeraddr   (struct socket *, struct sockaddr **);
 int  ng_btsocket_l2cap_raw_send       (struct socket *, int, struct mbuf *,
@@ -183,7 +183,7 @@
 #ifdef _KERNEL
 
 void ng_btsocket_l2cap_init       (void);
-int  ng_btsocket_l2cap_abort      (struct socket *);
+void ng_btsocket_l2cap_abort      (struct socket *);
 int  ng_btsocket_l2cap_accept     (struct socket *, struct sockaddr **);
 int  ng_btsocket_l2cap_attach     (struct socket *, int, struct thread *);
 int  ng_btsocket_l2cap_bind       (struct socket *, struct sockaddr *,
@@ -193,7 +193,7 @@
 int  ng_btsocket_l2cap_control    (struct socket *, u_long, caddr_t,
                                    struct ifnet *, struct thread *);
 int  ng_btsocket_l2cap_ctloutput  (struct socket *, struct sockopt *);
-int  ng_btsocket_l2cap_detach     (struct socket *);
+void ng_btsocket_l2cap_detach     (struct socket *);
 int  ng_btsocket_l2cap_disconnect (struct socket *);
 int  ng_btsocket_l2cap_listen     (struct socket *, int, struct thread *);
 int  ng_btsocket_l2cap_peeraddr   (struct socket *, struct sockaddr **);
--- netgraph/bluetooth/include/ng_btsocket_rfcomm.h	2005/10/30 19:45:29
+++ netgraph/bluetooth/include/ng_btsocket_rfcomm.h	2006/02/14 02:16:05
@@ -314,7 +314,7 @@
 #ifdef _KERNEL
 
 void ng_btsocket_rfcomm_init       (void);
-int  ng_btsocket_rfcomm_abort      (struct socket *);
+void ng_btsocket_rfcomm_abort      (struct socket *);
 int  ng_btsocket_rfcomm_accept     (struct socket *, struct sockaddr **);
 int  ng_btsocket_rfcomm_attach     (struct socket *, int, struct thread *);
 int  ng_btsocket_rfcomm_bind       (struct socket *, struct sockaddr *,
@@ -324,7 +324,7 @@
 int  ng_btsocket_rfcomm_control    (struct socket *, u_long, caddr_t,
                                     struct ifnet *, struct thread *);
 int  ng_btsocket_rfcomm_ctloutput  (struct socket *, struct sockopt *);
-int  ng_btsocket_rfcomm_detach     (struct socket *);
+void ng_btsocket_rfcomm_detach     (struct socket *);
 int  ng_btsocket_rfcomm_disconnect (struct socket *);
 int  ng_btsocket_rfcomm_listen     (struct socket *, int, struct thread *);
 int  ng_btsocket_rfcomm_peeraddr   (struct socket *, struct sockaddr **);
--- netgraph/bluetooth/socket/ng_btsocket_hci_raw.c	2005/07/28 17:45:20
+++ netgraph/bluetooth/socket/ng_btsocket_hci_raw.c	2006/02/14 02:16:05
@@ -872,10 +872,10 @@
  * Abort connection on socket
  */
 
-int
+void
 ng_btsocket_hci_raw_abort(struct socket *so)
 {
-	return (ng_btsocket_hci_raw_detach(so));
+	ng_btsocket_hci_raw_detach(so);
 } /* ng_btsocket_hci_raw_abort */
 
 /*
@@ -1399,15 +1399,15 @@
  * Detach raw HCI socket
  */
 
-int
+void
 ng_btsocket_hci_raw_detach(struct socket *so)
 {
 	ng_btsocket_hci_raw_pcb_p	pcb = so2hci_raw_pcb(so);
 
-	if (pcb == NULL)
-		return (EINVAL);
+	KASSERT(pcb != NULL, ("ng_btsocket_hci_raw_detach: pcb == NULL"));
+
 	if (ng_btsocket_hci_raw_node == NULL)
-		return (EINVAL);
+		return;
 
 	mtx_lock(&ng_btsocket_hci_raw_sockets_mtx);
 	mtx_lock(&pcb->pcb_mtx);
@@ -1422,12 +1422,7 @@
 	bzero(pcb, sizeof(*pcb));
 	FREE(pcb, M_NETGRAPH_BTSOCKET_HCI_RAW);
 
-	ACCEPT_LOCK();
-	SOCK_LOCK(so);
 	so->so_pcb = NULL;
-	sotryfree(so);
-
-	return (0);
 } /* ng_btsocket_hci_raw_detach */
 
 /*
--- netgraph/bluetooth/socket/ng_btsocket_l2cap.c	2005/10/30 19:45:29
+++ netgraph/bluetooth/socket/ng_btsocket_l2cap.c	2006/02/14 02:16:05
@@ -1912,12 +1912,12 @@
  * Abort connection on socket
  */
 
-int
+void
 ng_btsocket_l2cap_abort(struct socket *so)
 {
 	so->so_error = ECONNABORTED;
 
-	return (ng_btsocket_l2cap_detach(so));
+	ng_btsocket_l2cap_detach(so);
 } /* ng_btsocket_l2cap_abort */
 
 /*
@@ -2316,15 +2316,15 @@
  * Detach and destroy socket
  */
 
-int
+void
 ng_btsocket_l2cap_detach(struct socket *so)
 {
 	ng_btsocket_l2cap_pcb_p	pcb = so2l2cap_pcb(so);
 
-	if (pcb == NULL)
-		return (EINVAL);
+	KASSERT(pcb != NULL, ("ng_btsocket_l2cap_detach: pcb == NULL"));
+
 	if (ng_btsocket_l2cap_node == NULL) 
-		return (EINVAL);
+		return;
 
 	mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
 	mtx_lock(&pcb->pcb_mtx);
@@ -2350,12 +2350,7 @@
 	FREE(pcb, M_NETGRAPH_BTSOCKET_L2CAP);
 
 	soisdisconnected(so);
-	ACCEPT_LOCK();
-	SOCK_LOCK(so);
 	so->so_pcb = NULL;
-	sotryfree(so);
-
-	return (0);
 } /* ng_btsocket_l2cap_detach */
 
 /*
--- netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c	2005/08/23 00:55:32
+++ netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c	2006/02/14 02:16:05
@@ -572,10 +572,10 @@
  * Abort connection on socket
  */
 
-int
+void
 ng_btsocket_l2cap_raw_abort(struct socket *so)
 {
-	return (ng_btsocket_l2cap_raw_detach(so));
+	ng_btsocket_l2cap_raw_detach(so);
 } /* ng_btsocket_l2cap_raw_abort */
 
 /*
@@ -1094,15 +1094,14 @@
  * Detach and destroy socket
  */
 
-int
+void
 ng_btsocket_l2cap_raw_detach(struct socket *so)
 {
 	ng_btsocket_l2cap_raw_pcb_p	pcb = so2l2cap_raw_pcb(so);
 
-	if (pcb == NULL)
-		return (EINVAL);
+	KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL"));
 	if (ng_btsocket_l2cap_raw_node == NULL) 
-		return (EINVAL);
+		return;
 
 	mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
 	mtx_lock(&pcb->pcb_mtx);
@@ -1117,12 +1116,7 @@
 	bzero(pcb, sizeof(*pcb));
 	FREE(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
 
-	ACCEPT_LOCK();
-	SOCK_LOCK(so);
 	so->so_pcb = NULL;
-	sotryfree(so);
-
-	return (0);
 } /* ng_btsocket_l2cap_raw_detach */
 
 /*
--- netgraph/bluetooth/socket/ng_btsocket_rfcomm.c	2005/10/30 19:45:29
+++ netgraph/bluetooth/socket/ng_btsocket_rfcomm.c	2006/02/14 02:16:05
@@ -343,12 +343,12 @@
  * Abort connection on socket
  */
 
-int
+void
 ng_btsocket_rfcomm_abort(struct socket *so)
 {
 	so->so_error = ECONNABORTED;
 
-	return (ng_btsocket_rfcomm_detach(so));
+	ng_btsocket_rfcomm_detach(so);
 } /* ng_btsocket_rfcomm_abort */
 
 /*
@@ -674,13 +674,12 @@
  * Detach and destroy socket
  */
 
-int
+void
 ng_btsocket_rfcomm_detach(struct socket *so)
 {
 	ng_btsocket_rfcomm_pcb_p	pcb = so2rfcomm_pcb(so);
 
-	if (pcb == NULL)
-		return (EINVAL);
+	KASSERT(pcb != NULL, ("ng_btsocket_rfcomm_detach: pcb == NULL"));
 
 	mtx_lock(&pcb->pcb_mtx);
 
@@ -726,12 +725,7 @@
 	FREE(pcb, M_NETGRAPH_BTSOCKET_RFCOMM);
 
 	soisdisconnected(so);
-	ACCEPT_LOCK();
-	SOCK_LOCK(so);
 	so->so_pcb = NULL;
-	sotryfree(so);
-
-	return (0);
 } /* ng_btsocket_rfcomm_detach */
 
 /*
--- netgraph/ng_socket.c	2005/11/09 13:31:29
+++ netgraph/ng_socket.c	2006/02/15 20:26:51
@@ -185,15 +185,13 @@
 	return (ng_attach_cntl(so));
 }
 
-static int
+static void
 ngc_detach(struct socket *so)
 {
 	struct ngpcb *const pcbp = sotongpcb(so);
 
-	if (pcbp == NULL)
-		return (EINVAL);
+	KASSERT(pcbp != NULL, ("ngc_detach: pcbp == NULL"));
 	ng_detach_common(pcbp, NG_CONTROL);
-	return (0);
 }
 
 static int
@@ -395,15 +393,13 @@
 	return (ng_attach_data(so));
 }
 
-static int
+static void
 ngd_detach(struct socket *so)
 {
 	struct ngpcb *const pcbp = sotongpcb(so);
 
-	if (pcbp == NULL)
-		return (EINVAL);
+	KASSERT(pcbp == NULL, ("ngd_detach: pcbp == NULL"));
 	ng_detach_common(pcbp, NG_DATA);
-	return (0);
 }
 
 static int
--- netinet/in_pcb.c	2006/02/16 15:50:16
+++ netinet/in_pcb.c	2006/02/18 20:36:51
@@ -676,16 +676,30 @@
 #ifdef IPSEC
 	ipsec_pcbdisconn(inp->inp_sp);
 #endif
-	if (inp->inp_socket->so_state & SS_NOFDREF)
-		in_pcbdetach(inp);
 }
 
+/*
+ * In the old world order, in_pcbdetach() served two functions: to detach the
+ * pcb from the socket/potentially free the socket, and to free the pcb
+ * itself.  In the new world order, the protocol code is responsible for
+ * managing the relationship with the socket, and this code simply frees the
+ * pcb.
+ */
 void
 in_pcbdetach(struct inpcb *inp)
 {
-	struct socket *so = inp->inp_socket;
+
+	KASSERT(inp->inp_socket != NULL, ("in_pcbdetach: inp_socket == NULL"));
+	inp->inp_socket->so_pcb = NULL;
+	inp->inp_socket = NULL;
+}
+
+void
+in_pcbfree(struct inpcb *inp)
+{
 	struct inpcbinfo *ipi = inp->inp_pcbinfo;
 
+	KASSERT(inp->inp_socket == NULL, ("in_pcbfree: inp_socket != NULL"));
 	INP_INFO_WLOCK_ASSERT(ipi);
 	INP_LOCK_ASSERT(inp);
 
@@ -694,12 +708,6 @@
 #endif /*IPSEC*/
 	inp->inp_gencnt = ++ipi->ipi_gencnt;
 	in_pcbremlists(inp);
-	if (so) {
-		ACCEPT_LOCK();
-		SOCK_LOCK(so);
-		so->so_pcb = NULL;
-		sotryfree(so);
-	}
 	if (inp->inp_options)
 		(void)m_free(inp->inp_options);
 	ip_freemoptions(inp->inp_moptions);
@@ -744,10 +752,7 @@
 
 	INP_INFO_RLOCK(pcbinfo);
 	inp = sotoinpcb(so);
-	if (!inp) {
-		INP_INFO_RUNLOCK(pcbinfo);
-		return ECONNRESET;
-	}
+	KASSERT(inp != NULL, ("in_setsockaddr: so_pcb == NULL"));
 	INP_LOCK(inp);
 	port = inp->inp_lport;
 	addr = inp->inp_laddr;
@@ -771,10 +776,7 @@
 
 	INP_INFO_RLOCK(pcbinfo);
 	inp = sotoinpcb(so);
-	if (!inp) {
-		INP_INFO_RUNLOCK(pcbinfo);
-		return ECONNRESET;
-	}
+	KASSERT(inp != NULL, ("in_setpeeraddr: so_pcb == NULL"));
 	INP_LOCK(inp);
 	port = inp->inp_fport;
 	addr = inp->inp_faddr;
@@ -1169,7 +1171,8 @@
 #ifdef MAC
 	struct inpcb *inp;
 
-	inp = (struct inpcb *)so->so_pcb;
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("in_pcbsosetlabel: so->so_pcb == NULL"));
 	INP_LOCK(inp);
 	SOCK_LOCK(so);
 	mac_inpcb_sosetlabel(so, inp);
--- netinet/in_pcb.h	2005/09/26 20:25:23
+++ netinet/in_pcb.h	2006/02/19 16:42:18
@@ -131,6 +131,8 @@
 #define INP_IPV6PROTO	0x4		/* opened under IPv6 protocol */
 #define INP_TIMEWAIT	0x8		/* .. probably doesn't go here */
 #define	INP_ONESBCAST	0x10		/* send all-ones broadcast */
+#define	INP_DROPPED	0x20		/* protocol drop flag */
+#define	INP_SOCKREF	0x40		/* strong socket reference */
 	u_char	inp_ip_ttl;		/* time to live proto */
 	u_char	inp_ip_p;		/* protocol proto */
 	u_char	inp_ip_minttl;		/* minimum TTL or drop */
@@ -348,6 +350,7 @@
 	    struct ucred *);
 void	in_pcbdetach(struct inpcb *);
 void	in_pcbdisconnect(struct inpcb *);
+void	in_pcbfree(struct inpcb *);
 int	in_pcbinshash(struct inpcb *);
 struct inpcb *
 	in_pcblookup_local(struct inpcbinfo *,
--- netinet/ip_divert.c	2005/11/09 13:31:29
+++ netinet/ip_divert.c	2006/02/17 23:33:04
@@ -394,21 +394,14 @@
 	struct inpcb *inp;
 	int error;
 
-	INP_INFO_WLOCK(&divcbinfo);
 	inp  = sotoinpcb(so);
-	if (inp != 0) {
-		INP_INFO_WUNLOCK(&divcbinfo);
-		return EINVAL;
-	}
-	if (td && (error = suser(td)) != 0) {
-		INP_INFO_WUNLOCK(&divcbinfo);
+	KASSERT(inp == NULL, ("div_attach: inp != NULL"));
+	if (td && (error = suser(td)) != 0)
 		return error;
-	}
 	error = soreserve(so, div_sendspace, div_recvspace);
-	if (error) {
-		INP_INFO_WUNLOCK(&divcbinfo);
+	if (error)
 		return error;
-	}
+	INP_INFO_WLOCK(&divcbinfo);
 	error = in_pcballoc(so, &divcbinfo, "divinp");
 	if (error) {
 		INP_INFO_WUNLOCK(&divcbinfo);
@@ -424,21 +417,18 @@
 	return 0;
 }
 
-static int
+static void
 div_detach(struct socket *so)
 {
 	struct inpcb *inp;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("div_detach: inp == NULL"));
 	INP_INFO_WLOCK(&divcbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&divcbinfo);
-		return EINVAL;
-	}
 	INP_LOCK(inp);
 	in_pcbdetach(inp);
+	in_pcbfree(inp);
 	INP_INFO_WUNLOCK(&divcbinfo);
-	return 0;
 }
 
 static int
@@ -447,12 +437,8 @@
 	struct inpcb *inp;
 	int error;
 
-	INP_INFO_WLOCK(&divcbinfo);
 	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&divcbinfo);
-		return EINVAL;
-	}
+	KASSERT(inp == NULL, ("div_bind: inp == NULL"));
 	/* in_pcbbind assumes that nam is a sockaddr_in
 	 * and in_pcbbind requires a valid address. Since divert
 	 * sockets don't we need to make sure the address is
@@ -461,13 +447,12 @@
 	 * and should probably have its own family.
 	 */
 	if (nam->sa_family != AF_INET)
-		error = EAFNOSUPPORT;
-	else {
-		((struct sockaddr_in *)nam)->sin_addr.s_addr = INADDR_ANY;
-		INP_LOCK(inp);
-		error = in_pcbbind(inp, nam, td->td_ucred);
-		INP_UNLOCK(inp);
-	}
+		return EAFNOSUPPORT;
+	((struct sockaddr_in *)nam)->sin_addr.s_addr = INADDR_ANY;
+	INP_INFO_WLOCK(&divcbinfo);
+	INP_LOCK(inp);
+	error = in_pcbbind(inp, nam, td->td_ucred);
+	INP_UNLOCK(inp);
 	INP_INFO_WUNLOCK(&divcbinfo);
 	return error;
 }
@@ -477,14 +462,9 @@
 {
 	struct inpcb *inp;
 
-	INP_INFO_RLOCK(&divcbinfo);
 	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_RUNLOCK(&divcbinfo);
-		return EINVAL;
-	}
+	KASSERT(inp != NULL, ("div_shutdown: inp == NULL"));
 	INP_LOCK(inp);
-	INP_INFO_RUNLOCK(&divcbinfo);
 	socantsendmore(so);
 	INP_UNLOCK(inp);
 	return 0;
--- netinet/raw_ip.c	2005/12/14 22:30:18
+++ netinet/raw_ip.c	2006/02/21 15:36:28
@@ -578,32 +578,18 @@
 	struct inpcb *inp;
 	int error;
 
-	/* XXX why not lower? */
-	INP_INFO_WLOCK(&ripcbinfo);
 	inp = sotoinpcb(so);
-	if (inp) {
-		/* XXX counter, printf */
-		INP_INFO_WUNLOCK(&ripcbinfo);
-		return EINVAL;
-	}
-	if (jailed(td->td_ucred) && !jail_allow_raw_sockets) {
-		INP_INFO_WUNLOCK(&ripcbinfo);
+	KASSERT(inp == NULL, ("rip_attach: inp != NULL"));
+	if (jailed(td->td_ucred) && !jail_allow_raw_sockets)
 		return (EPERM);
-	}
-	if ((error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL)) != 0) {
-		INP_INFO_WUNLOCK(&ripcbinfo);
+	if ((error = suser_cred(td->td_ucred, SUSER_ALLOWJAIL)) != 0)
 		return error;
-	}
-	if (proto >= IPPROTO_MAX || proto < 0) {
-		INP_INFO_WUNLOCK(&ripcbinfo);
+	if (proto >= IPPROTO_MAX || proto < 0)
 		return EPROTONOSUPPORT;
-	}
-
 	error = soreserve(so, rip_sendspace, rip_recvspace);
-	if (error) {
-		INP_INFO_WUNLOCK(&ripcbinfo);
+	if (error)
 		return error;
-	}
+	INP_INFO_WLOCK(&ripcbinfo);
 	error = in_pcballoc(so, &ripcbinfo, "rawinp");
 	if (error) {
 		INP_INFO_WUNLOCK(&ripcbinfo);
@@ -633,45 +619,34 @@
 	if (so == ip_rsvpd)
 		ip_rsvp_done();
 	in_pcbdetach(inp);
+	in_pcbfree(inp);
 }
 
-static int
+static void
 rip_detach(struct socket *so)
 {
 	struct inpcb *inp;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("rip_detach: inp == NULL"));
 	INP_INFO_WLOCK(&ripcbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		/* XXX counter, printf */
-		INP_INFO_WUNLOCK(&ripcbinfo);
-		return EINVAL;
-	}
 	INP_LOCK(inp);
 	rip_pcbdetach(so, inp);
 	INP_INFO_WUNLOCK(&ripcbinfo);
-	return 0;
 }
 
-static int
+static void
 rip_abort(struct socket *so)
 {
 	struct inpcb *inp;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("rip_abort: inp == NULL"));
 	INP_INFO_WLOCK(&ripcbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&ripcbinfo);
-		return EINVAL;	/* ??? possible? panic instead? */
-	}
 	INP_LOCK(inp);
 	soisdisconnected(so);
-	if (so->so_state & SS_NOFDREF)
-		rip_pcbdetach(so, inp);
-	else
-		INP_UNLOCK(inp);
+	rip_pcbdetach(so, inp);
 	INP_INFO_WUNLOCK(&ripcbinfo);
-	return 0;
 }
 
 static int
@@ -679,7 +654,8 @@
 {
 	if ((so->so_state & SS_ISCONNECTED) == 0)
 		return ENOTCONN;
-	return rip_abort(so);
+	rip_abort(so);
+	return (0);
 }
 
 static int
@@ -705,12 +681,9 @@
 	     ifa_ifwithaddr((struct sockaddr *)addr) == 0))
 		return EADDRNOTAVAIL;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("rip_bind: inp == NULL"));
 	INP_INFO_WLOCK(&ripcbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&ripcbinfo);
-		return EINVAL;
-	}
 	INP_LOCK(inp);
 	inp->inp_laddr = addr->sin_addr;
 	INP_UNLOCK(inp);
@@ -731,12 +704,9 @@
 	if (addr->sin_family != AF_INET && addr->sin_family != AF_IMPLINK)
 		return EAFNOSUPPORT;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("rip_connect: inp == NULL"));
 	INP_INFO_WLOCK(&ripcbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&ripcbinfo);
-		return EINVAL;
-	}
 	INP_LOCK(inp);
 	inp->inp_faddr = addr->sin_addr;
 	soisconnected(so);
@@ -750,14 +720,9 @@
 {
 	struct inpcb *inp;
 
-	INP_INFO_RLOCK(&ripcbinfo);
 	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_RUNLOCK(&ripcbinfo);
-		return EINVAL;
-	}
+	KASSERT(inp != NULL, ("rip_shutdown: inp == NULL"));
 	INP_LOCK(inp);
-	INP_INFO_RUNLOCK(&ripcbinfo);
 	socantsendmore(so);
 	INP_UNLOCK(inp);
 	return 0;
@@ -769,28 +734,26 @@
 {
 	struct inpcb *inp;
 	u_long dst;
-	int ret;
 
-	INP_INFO_WLOCK(&ripcbinfo);
 	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("rip_send: inp == NULL"));
+	/*
+	 * Note: 'dst' reads below are unlocked.
+	 */
 	if (so->so_state & SS_ISCONNECTED) {
 		if (nam) {
-			INP_INFO_WUNLOCK(&ripcbinfo);
 			m_freem(m);
 			return EISCONN;
 		}
-		dst = inp->inp_faddr.s_addr;
+		dst = inp->inp_faddr.s_addr;	/* Unlocked read. */
 	} else {
 		if (nam == NULL) {
-			INP_INFO_WUNLOCK(&ripcbinfo);
 			m_freem(m);
 			return ENOTCONN;
 		}
 		dst = ((struct sockaddr_in *)nam)->sin_addr.s_addr;
 	}
-	ret = rip_output(m, so, dst);
-	INP_INFO_WUNLOCK(&ripcbinfo);
-	return ret;
+	return rip_output(m, so, dst);
 }
 
 static int
--- netinet/tcp_input.c	2006/02/18 17:05:16
+++ netinet/tcp_input.c	2006/02/19 18:34:22
@@ -790,6 +790,7 @@
 		goto drop;
 #endif
 	so = inp->inp_socket;
+	KASSERT(so != NULL, ("tcp_input: so == NULL"));
 #ifdef TCPDEBUG
 	if (so->so_options & SO_DEBUG) {
 		ostate = tp->t_state;
@@ -2551,7 +2552,7 @@
 			    (tcp_seq)0, TH_RST|TH_ACK);
 	}
 
-	if (tp)
+	if (tp != NULL)
 		INP_UNLOCK(inp);
 	if (headlocked)
 		INP_INFO_WUNLOCK(&tcbinfo);
@@ -2566,7 +2567,7 @@
 		tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen,
 			  &tcp_savetcp, 0);
 #endif
-	if (tp)
+	if (tp != NULL)
 		INP_UNLOCK(inp);
 	if (headlocked)
 		INP_INFO_WUNLOCK(&tcbinfo);
@@ -3198,7 +3199,7 @@
 	 * are above the previous ones.
 	 */
 	if ((thflags & TH_SYN) && SEQ_GT(th->th_seq, tw->rcv_nxt)) {
-		(void) tcp_twclose(tw, 0);
+		tcp_twclose(tw, 0);
 		return (1);
 	}
 
--- netinet/tcp_subr.c	2006/02/16 19:40:18
+++ netinet/tcp_subr.c	2006/02/21 15:36:28
@@ -213,7 +213,6 @@
 uma_zone_t sack_hole_zone;
 
 static struct inpcb *tcp_notify(struct inpcb *, int);
-static void	tcp_discardcb(struct tcpcb *);
 static void	tcp_isn_tick(void *);
 
 /*
@@ -665,7 +664,7 @@
 	return (tcp_close(tp));
 }
 
-static void
+void
 tcp_discardcb(tp)
 	struct tcpcb *tp;
 {
@@ -676,6 +675,12 @@
 	int isipv6 = (inp->inp_vflag & INP_IPV6) != 0;
 #endif /* INET6 */
 
+	/*
+	 * XXXRW: This is all very well and good, but actually, we might be
+	 * discarding the tcpcb after the socket is gone, so we can't do
+	 * this:
+	KASSERT(so != NULL, ("tcp_discardcb: so == NULL"));
+	 */
 	INP_LOCK_ASSERT(inp);
 
 	/*
@@ -755,7 +760,12 @@
 	inp->inp_ppcb = NULL;
 	tp->t_inpcb = NULL;
 	uma_zfree(tcpcb_zone, tp);
-	soisdisconnected(so);
+
+	/*
+	 * XXXRW: This seems a bit unclean.
+	 */
+	if (so != NULL)
+		soisdisconnected(so);
 }
 
 /*
@@ -769,22 +779,40 @@
 	struct tcpcb *tp;
 {
 	struct inpcb *inp = tp->t_inpcb;
-#ifdef INET6
-	struct socket *so = inp->inp_socket;
-#endif
+	struct socket *so;
 
 	INP_INFO_WLOCK_ASSERT(&tcbinfo);
 	INP_LOCK_ASSERT(inp);
 
-	tcp_discardcb(tp);
+	inp->inp_vflag |= INP_DROPPED;
+
+	tcpstat.tcps_closed++;
+	KASSERT(inp->inp_socket != NULL, ("tcp_close: inp_socket NULL"));
+	so = inp->inp_socket;
+	soisdisconnected(so);
+	if (inp->inp_vflag & INP_SOCKREF) {
+		KASSERT(so->so_state & SS_PROTOREF,
+		    ("tcp_close: !SS_PROTOREF"));
+		inp->inp_vflag &= ~INP_SOCKREF;
+		tcp_discardcb(tp);
+#ifdef INET6
+		if (inp->inp_vflag & INP_IPV6PROTO) {
+			in6_pcbdetach(inp);
+			in6_pcbfree(inp);
+		} else {
+#endif
+			in_pcbdetach(inp);
+			in_pcbfree(inp);
 #ifdef INET6
-	if (INP_CHECK_SOCKAF(so, AF_INET6))
-		in6_pcbdetach(inp);
-	else
+		}
 #endif
-		in_pcbdetach(inp);
-	tcpstat.tcps_closed++;
-	return (NULL);
+		ACCEPT_LOCK();
+		SOCK_LOCK(so);
+		so->so_state &= ~SS_PROTOREF;
+		sofree(so);
+		return (NULL);
+	}
+	return (tp);
 }
 
 void
@@ -857,8 +885,11 @@
 		return (inp);
 	} else if (tp->t_state < TCPS_ESTABLISHED && tp->t_rxtshift > 3 &&
 	    tp->t_softerror) {
-		tcp_drop(tp, error);
-		return (struct inpcb *)0;
+		tp = tcp_drop(tp, error);
+		if (tp != NULL)
+			return (inp);
+		else
+			return (NULL);
 	} else {
 		tp->t_softerror = error;
 		return (inp);
@@ -1433,8 +1464,11 @@
 	INP_LOCK_ASSERT(inp);
 
 	if (tp != NULL && tp->t_state == TCPS_SYN_SENT) {
-		tcp_drop(tp, errno);
-		return (NULL);
+		tp = tcp_drop(tp, errno);
+		if (tp != NULL)
+			return (inp);
+		else
+			return (NULL);
 	}
 	return (inp);
 }
@@ -1670,7 +1704,9 @@
 	if (tw == NULL) {
 		tw = tcp_timer_2msl_tw(1);
 		if (tw == NULL) {
-			tcp_close(tp);
+			tp = tcp_close(tp);
+			if (tp != NULL)
+				INP_UNLOCK(tp->t_inpcb);
 			return;
 		}
 	}
@@ -1705,21 +1741,45 @@
  */
 	tw_time = 2 * tcp_msl;
 	acknow = tp->t_flags & TF_ACKNOW;
+
+	/*
+	 * First, discard tcpcb state, which includes stopping its timers and
+	 * freeing it.  tcp_discardcb() used to also release the inpcb, but
+	 * that work is now done in the caller.
+	 */
 	tcp_discardcb(tp);
 	so = inp->inp_socket;
-	ACCEPT_LOCK();
 	SOCK_LOCK(so);
-	so->so_pcb = NULL;
 	tw->tw_cred = crhold(so->so_cred);
 	tw->tw_so_options = so->so_options;
-	sotryfree(so);
-	inp->inp_socket = NULL;
+	SOCK_UNLOCK(so);
 	if (acknow)
 		tcp_twrespond(tw, TH_ACK);
 	inp->inp_ppcb = (caddr_t)tw;
 	inp->inp_vflag |= INP_TIMEWAIT;
 	tcp_timer_2msl_reset(tw, tw_time);
-	INP_UNLOCK(inp);
+
+	/*
+	 * If the inpcb owns the sole reference to the socket, then we can
+	 * detach and free the socket as it is not needed in time wait.
+	 */
+	if (inp->inp_vflag & INP_SOCKREF) {
+		KASSERT(so->so_state & SS_PROTOREF,
+		    ("tcp_twstart: !SS_PROTOREF"));
+		inp->inp_vflag &= ~INP_SOCKREF;
+#ifdef INET6
+		if (inp->inp_vflag & INP_IPV6PROTO)
+			in6_pcbdetach(inp);
+		else
+#endif
+			in_pcbdetach(inp);
+		INP_UNLOCK(inp);
+		ACCEPT_LOCK();
+		SOCK_LOCK(so);
+		so->so_state &= ~SS_PROTOREF;
+		sofree(so);
+	} else
+		INP_UNLOCK(inp);
 }
 
 /*
@@ -1756,31 +1816,62 @@
 		return (0);
 }
 
-struct tcptw *
+void
 tcp_twclose(struct tcptw *tw, int reuse)
 {
+	struct socket *so;
 	struct inpcb *inp;
 
+	/*
+	 * At this point, we should have an inpcb<->twtcp pair, with no
+	 * associated socket.  Validate that this is the case.
+	 *
+	 * XXXRW: This comment stale -- could still have socket ...?
+	 */
 	inp = tw->tw_inpcb;
+	KASSERT((inp->inp_vflag & INP_TIMEWAIT), ("tcp_twclose: !timewait"));
+	KASSERT(inp->inp_ppcb == (void *)tw, ("tcp_twclose: inp_ppcb != tw"));
 	INP_INFO_WLOCK_ASSERT(&tcbinfo);	/* tcp_timer_2msl_stop(). */
 	INP_LOCK_ASSERT(inp);
 
 	tw->tw_inpcb = NULL;
 	tcp_timer_2msl_stop(tw);
 	inp->inp_ppcb = NULL;
+	inp->inp_vflag |= INP_DROPPED;
+
+	so = inp->inp_socket;
+	if (so != NULL && inp->inp_vflag & INP_SOCKREF) {
+		KASSERT(so->so_state & SS_PROTOREF,
+		    ("tcp_twclose: !SS_PROTOREF"));
+		inp->inp_vflag &= ~INP_SOCKREF;
 #ifdef INET6
-	if (inp->inp_vflag & INP_IPV6PROTO)
-		in6_pcbdetach(inp);
-	else
+		if (inp->inp_vflag & INP_IPV6PROTO) {
+			in6_pcbdetach(inp);
+			in6_pcbfree(inp);
+		} else {
+			in_pcbdetach(inp);
+			in_pcbfree(inp);
+		}
+#endif
+		ACCEPT_LOCK();
+		SOCK_LOCK(so);
+		so->so_state &= ~SS_PROTOREF;
+		sofree(so);
+	} else if (so == NULL) {
+#ifdef INET6
+		if (inp->inp_vflag & INP_IPV6PROTO)
+			in6_pcbfree(inp);
+		else
 #endif
-		in_pcbdetach(inp);
+			in_pcbfree(inp);
+	} else
+		printf("tcp_twclose: so != NULL but !INP_SOCKREF");
 	tcpstat.tcps_closed++;
 	crfree(tw->tw_cred);
 	tw->tw_cred = NULL;
 	if (reuse)
-		return (tw);
+		return;
 	uma_zfree(tcptw_zone, tw);
-	return (NULL);
 }
 
 int
@@ -2233,11 +2324,10 @@
 		INP_LOCK(inp);
 		if ((tw = intotw(inp)) &&
 		    (inp->inp_vflag & INP_TIMEWAIT) != 0) {
-			(void) tcp_twclose(tw, 0);
+			tcp_twclose(tw, 0);
 		} else if ((tp = intotcpcb(inp)) &&
 		    ((inp->inp_socket->so_options & SO_ACCEPTCONN) == 0)) {
-			tp = tcp_drop(tp, ECONNABORTED);
-			if (tp != NULL)
+			if (tcp_drop(tp, ECONNABORTED) != NULL)
 				INP_UNLOCK(inp);
 		} else
 			INP_UNLOCK(inp);
--- netinet/tcp_timer.c	2006/02/16 15:45:16
+++ netinet/tcp_timer.c	2006/02/21 23:33:49
@@ -125,6 +125,10 @@
 
 static int tcp_totbackoff = 2559;	/* sum of tcp_backoff[] */
 
+static int tcp_timer_race;
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, timer_race, CTLFLAG_RD, &tcp_timer_race,
+    0, "Count of t_inpcb races on tcp_discardcb");
+
 /*
  * TCP timer processing.
  */
@@ -138,7 +142,15 @@
 
 	INP_INFO_RLOCK(&tcbinfo);
 	inp = tp->t_inpcb;
+	/*
+	 * XXXRW: While this assert is in fact correct, bugs in the tcpcb
+	 * tear-down mean we need it as a work-around for races between
+	 * timers and tcp_discardcb().
+	 *
+	 * KASSERT(inp != NULL, ("tcp_timer_delack: inp == NULL"));
+	 */
 	if (inp == NULL) {
+		tcp_timer_race++;
 		INP_INFO_RUNLOCK(&tcbinfo);
 		return;
 	}
@@ -167,10 +179,21 @@
 
 	ostate = tp->t_state;
 #endif
+	/*
+	 * XXXRW: Does this actually happen?
+	 */
 	INP_INFO_WLOCK(&tcbinfo);
 	inp = tp->t_inpcb;
+	/*
+	 * XXXRW: While this assert is in fact correct, bugs in the tcpcb
+	 * tear-down mean we need it as a work-around for races between
+	 * timers and tcp_discardcb().
+	 *
+	 * KASSERT(inp != NULL, ("tcp_timer_2msl: inp == NULL"));
+	 */
 	if (inp == NULL) {
-		INP_INFO_WUNLOCK(&tcbinfo);
+		tcp_timer_race++;
+		INP_INFO_RUNLOCK(&tcbinfo);
 		return;
 	}
 	INP_LOCK(inp);
@@ -195,11 +218,11 @@
 		tp = tcp_close(tp);
 
 #ifdef TCPDEBUG
-	if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
+	if (tp != NULL && tp->t_inpcb->inp_socket->so_options & SO_DEBUG)
 		tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0,
 			  PRU_SLOWTIMO);
 #endif
-	if (tp)
+	if (tp != NULL)
 		INP_UNLOCK(inp);
 	INP_INFO_WUNLOCK(&tcbinfo);
 }
@@ -267,14 +290,12 @@
 	for (i = 0; i < 2; i++) {
 		twl = tw_2msl_list[i];
 		tw_tail = &twl->tw_tail;
-		for (;;) {
-			tw = LIST_FIRST(&twl->tw_list);
-			if (tw == tw_tail || (!reuse && tw->tw_time > ticks))
-				break;
-			INP_LOCK(tw->tw_inpcb);
-			if (tcp_twclose(tw, reuse) != NULL)
-				return (tw);
-		}
+		tw = LIST_FIRST(&twl->tw_list);
+		if (tw == tw_tail || (!reuse && tw->tw_time > ticks))
+			continue;
+		INP_LOCK(tw->tw_inpcb);
+		tcp_twclose(tw, reuse);
+		return (tw);
 	}
 	return (NULL);
 }
@@ -293,8 +314,16 @@
 #endif
 	INP_INFO_WLOCK(&tcbinfo);
 	inp = tp->t_inpcb;
-	if (!inp) {
-		INP_INFO_WUNLOCK(&tcbinfo);
+	/*
+	 * XXXRW: While this assert is in fact correct, bugs in the tcpcb
+	 * tear-down mean we need it as a work-around for races between
+	 * timers and tcp_discardcb().
+	 *
+	 * KASSERT(inp != NULL, ("tcp_timer_keep: inp == NULL"));
+	 */
+	if (inp == NULL) {
+		tcp_timer_race++;
+		INP_INFO_RUNLOCK(&tcbinfo);
 		return;
 	}
 	INP_LOCK(inp);
@@ -353,11 +382,11 @@
 	tp = tcp_drop(tp, ETIMEDOUT);
 
 #ifdef TCPDEBUG
-	if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
+	if (tp != NULL && tp->t_inpcb->inp_socket->so_options & SO_DEBUG)
 		tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0,
 			  PRU_SLOWTIMO);
 #endif
-	if (tp)
+	if (tp != NULL)
 		INP_UNLOCK(tp->t_inpcb);
 	INP_INFO_WUNLOCK(&tcbinfo);
 }
@@ -375,8 +404,16 @@
 #endif
 	INP_INFO_WLOCK(&tcbinfo);
 	inp = tp->t_inpcb;
-	if (!inp) {
-		INP_INFO_WUNLOCK(&tcbinfo);
+	/*
+	 * XXXRW: While this assert is in fact correct, bugs in the tcpcb
+	 * tear-down mean we need it as a work-around for races between
+	 * timers and tcp_discardcb().
+	 *
+	 * KASSERT(inp != NULL, ("tcp_timer_persist: inp == NULL"));
+	 */
+	if (inp == NULL) {
+		tcp_timer_race++;
+		INP_INFO_RUNLOCK(&tcbinfo);
 		return;
 	}
 	INP_LOCK(inp);
@@ -412,11 +449,11 @@
 
 out:
 #ifdef TCPDEBUG
-	if (tp && tp->t_inpcb->inp_socket->so_options & SO_DEBUG)
+	if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)
 		tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0,
 			  PRU_SLOWTIMO);
 #endif
-	if (tp)
+	if (tp != NULL)
 		INP_UNLOCK(inp);
 	INP_INFO_WUNLOCK(&tcbinfo);
 }
@@ -437,8 +474,16 @@
 	INP_INFO_WLOCK(&tcbinfo);
 	headlocked = 1;
 	inp = tp->t_inpcb;
-	if (!inp) {
-		INP_INFO_WUNLOCK(&tcbinfo);
+	/*
+	 * XXXRW: While this assert is in fact correct, bugs in the tcpcb
+	 * tear-down mean we need it as a work-around for races between
+	 * timers and tcp_discardcb().
+	 *
+	 * KASSERT(inp != NULL, ("tcp_timer_rexmt: inp == NULL"));
+	 */
+	if (inp == NULL) {
+		tcp_timer_race++;
+		INP_INFO_RUNLOCK(&tcbinfo);
 		return;
 	}
 	INP_LOCK(inp);
@@ -560,11 +605,11 @@
 
 out:
 #ifdef TCPDEBUG
-	if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
+	if (tp != NULL && tp->t_inpcb->inp_socket->so_options & SO_DEBUG)
 		tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0,
 			  PRU_SLOWTIMO);
 #endif
-	if (tp)
+	if (tp != NULL)
 		INP_UNLOCK(inp);
 	if (headlocked)
 		INP_INFO_WUNLOCK(&tcbinfo);
--- netinet/tcp_usrreq.c	2005/12/14 22:30:18
+++ netinet/tcp_usrreq.c	2006/02/22 16:11:12
@@ -89,10 +89,8 @@
 static int	tcp6_connect(struct tcpcb *, struct sockaddr *,
 		    struct thread *td);
 #endif /* INET6 */
-static struct tcpcb *
-		tcp_disconnect(struct tcpcb *);
-static struct tcpcb *
-		tcp_usrclosed(struct tcpcb *);
+static void	tcp_disconnect(struct tcpcb *);
+static void	tcp_usrclosed(struct tcpcb *);
 static void	tcp_fill_info(struct tcpcb *, struct tcp_info *);
 
 #ifdef TCPDEBUG
@@ -115,16 +113,12 @@
 {
 	int error;
 	struct inpcb *inp;
-	struct tcpcb *tp = 0;
 	TCPDEBUG0;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp == NULL, ("tcp_usr_attach: inp != NULL"));
 	INP_INFO_WLOCK(&tcbinfo);
 	TCPDEBUG1();
-	inp = sotoinpcb(so);
-	if (inp) {
-		error = EISCONN;
-		goto out;
-	}
 
 	error = tcp_attach(so);
 	if (error)
@@ -133,8 +127,6 @@
 	if ((so->so_options & SO_LINGER) && so->so_linger == 0)
 		so->so_linger = TCP_LINGERTIME;
 
-	inp = sotoinpcb(so);
-	tp = intotcpcb(inp);
 out:
 	TCPDEBUG2(PRU_ATTACH);
 	INP_INFO_WUNLOCK(&tcbinfo);
@@ -148,69 +140,94 @@
  * which may finish later; embryonic TCB's can just
  * be discarded here.
  */
-static int
+static void
 tcp_usr_detach(struct socket *so)
 {
-	int error = 0;
 	struct inpcb *inp;
 	struct tcpcb *tp;
+#ifdef INET6
+	int isipv6 = INP_CHECK_SOCKAF(so, AF_INET6) != 0;
+#endif
 	TCPDEBUG0;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("tcp_usr_detach: inp == NULL"));
 	INP_INFO_WLOCK(&tcbinfo);
-	inp = sotoinpcb(so);
-	if (inp == NULL) {
-		INP_INFO_WUNLOCK(&tcbinfo);
-		return error;
-	}
 	INP_LOCK(inp);
-	tp = intotcpcb(inp);
-	TCPDEBUG1();
-	tp = tcp_disconnect(tp);
+	KASSERT(inp->inp_socket != NULL,
+	    ("tcp_usr_detach: inp_socket == NULL"));
 
-	TCPDEBUG2(PRU_DETACH);
-	if (tp)
-		INP_UNLOCK(inp);
+	if (inp->inp_vflag & INP_TIMEWAIT) {
+		if (inp->inp_vflag & INP_DROPPED) {
+			/*
+			 * Connection was in time wait and has been dropped;
+			 * the calling path is via tcp_twclose(), which will
+			 * free the tcptw, so we can discard the remainder.
+			 *
+			 * XXXRW: Would it be cleaner to free the tcptw
+			 * here?
+			 */
+#ifdef INET6
+			if (isipv6) {
+				in6_pcbdetach(inp);
+				in6_pcbfree(inp);
+			} else {
+#endif
+				in_pcbdetach(inp);
+				in_pcbfree(inp);
+#ifdef INET6
+			}
+#endif
+		} else {
+			/*
+			 * Connection is in time wait and has not yet been
+			 * dropped; allow the socket to be discarded, but
+			 * need to keep inpcb until end of time wait.
+			 */
+#ifdef INET6
+			if (isipv6)
+				in6_pcbdetach(inp);
+			else
+#endif
+				in_pcbdetach(inp);
+			INP_UNLOCK(inp);
+		}
+	} else {
+		tp = intotcpcb(inp);
+		if (inp->inp_vflag & INP_DROPPED ||
+		    tp->t_state < TCPS_SYN_SENT) {
+			/*
+			 * Connection has been dropped or is a listen socket,
+			 * tear down all pcb state and allow socket to be
+			 * freed.
+			 */
+			tcp_discardcb(tp);
+#ifdef INET6
+			if (isipv6) {
+				in_pcbdetach(inp);
+				in_pcbfree(inp);
+			} else {
+#endif
+				in_pcbdetach(inp);
+				in_pcbfree(inp);
+#ifdef INET6
+			}
+#endif
+		} else {
+			/*
+			 * Connection state still required, as is socket, so
+			 * mark socket for TCP to free later.
+			 */
+			SOCK_LOCK(so);
+			so->so_state |= SS_PROTOREF;
+			SOCK_UNLOCK(so);
+			inp->inp_vflag |= INP_SOCKREF;
+			INP_UNLOCK(inp);
+		}
+	}
 	INP_INFO_WUNLOCK(&tcbinfo);
-	return error;
 }
 
-#define INI_NOLOCK	0
-#define INI_READ	1
-#define INI_WRITE	2
-
-#define	COMMON_START()						\
-	TCPDEBUG0;						\
-	do {							\
-		if (inirw == INI_READ)				\
-			INP_INFO_RLOCK(&tcbinfo);		\
-		else if (inirw == INI_WRITE)			\
-			INP_INFO_WLOCK(&tcbinfo);		\
-		inp = sotoinpcb(so);				\
-		if (inp == 0) {					\
-			if (inirw == INI_READ)			\
-				INP_INFO_RUNLOCK(&tcbinfo);	\
-			else if (inirw == INI_WRITE)		\
-				INP_INFO_WUNLOCK(&tcbinfo);	\
-			return EINVAL;				\
-		}						\
-		INP_LOCK(inp);					\
-		if (inirw == INI_READ)				\
-			INP_INFO_RUNLOCK(&tcbinfo);		\
-		tp = intotcpcb(inp);				\
-		TCPDEBUG1();					\
-} while(0)
-
-#define COMMON_END(req)						\
-out:	TCPDEBUG2(req);						\
-	do {							\
-		if (tp)						\
-			INP_UNLOCK(inp);			\
-		if (inirw == INI_WRITE)				\
-			INP_INFO_WUNLOCK(&tcbinfo);		\
-		return error;					\
-		goto out;					\
-} while(0)
-
 /*
  * Give the socket an address.
  */
@@ -221,7 +238,6 @@
 	struct inpcb *inp;
 	struct tcpcb *tp;
 	struct sockaddr_in *sinp;
-	const int inirw = INI_WRITE;
 
 	sinp = (struct sockaddr_in *)nam;
 	if (nam->sa_len != sizeof (*sinp))
@@ -234,11 +250,24 @@
 	    IN_MULTICAST(ntohl(sinp->sin_addr.s_addr)))
 		return (EAFNOSUPPORT);
 
-	COMMON_START();
+	TCPDEBUG0;
+	INP_INFO_WLOCK(&tcbinfo);
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("tcp_usr_bind: inp == NULL"));
+	INP_LOCK(inp);
+	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
+		error = EINVAL;
+		goto out;
+	}
+	tp = intotcpcb(inp);
+	TCPDEBUG1();
 	error = in_pcbbind(inp, nam, td->td_ucred);
-	if (error)
-		goto out;
-	COMMON_END(PRU_BIND);
+out:
+	TCPDEBUG2(PRU_BIND);
+	INP_UNLOCK(inp);
+	INP_INFO_WUNLOCK(&tcbinfo);
+
+	return (error);
 }
 
 #ifdef INET6
@@ -249,7 +278,6 @@
 	struct inpcb *inp;
 	struct tcpcb *tp;
 	struct sockaddr_in6 *sin6p;
-	const int inirw = INI_WRITE;
 
 	sin6p = (struct sockaddr_in6 *)nam;
 	if (nam->sa_len != sizeof (*sin6p))
@@ -262,7 +290,17 @@
 	    IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr))
 		return (EAFNOSUPPORT);
 
-	COMMON_START();
+	TCPDEBUG0;
+	INP_INFO_WLOCK(&tcbinfo);
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("tcp6_usr_bind: inp == NULL"));
+	INP_LOCK(inp);
+	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
+		error = EINVAL;
+		goto out;
+	}
+	tp = intotcpcb(inp);
+	TCPDEBUG1();
 	inp->inp_vflag &= ~INP_IPV4;
 	inp->inp_vflag |= INP_IPV6;
 	if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
@@ -280,9 +318,11 @@
 		}
 	}
 	error = in6_pcbbind(inp, nam, td->td_ucred);
-	if (error)
-		goto out;
-	COMMON_END(PRU_BIND);
+out:
+	TCPDEBUG2(PRU_BIND);
+	INP_UNLOCK(inp);
+	INP_INFO_WUNLOCK(&tcbinfo);
+	return (error);
 }
 #endif /* INET6 */
 
@@ -295,9 +335,18 @@
 	int error = 0;
 	struct inpcb *inp;
 	struct tcpcb *tp;
-	const int inirw = INI_WRITE;
 
-	COMMON_START();
+	TCPDEBUG0;
+	INP_INFO_WLOCK(&tcbinfo);
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("tcp_usr_listen: inp == NULL"));
+	INP_LOCK(inp);
+	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
+		error = EINVAL;
+		goto out;
+	}
+	tp = intotcpcb(inp);
+	TCPDEBUG1();
 	SOCK_LOCK(so);
 	error = solisten_proto_check(so);
 	if (error == 0 && inp->inp_lport == 0)
@@ -307,7 +356,12 @@
 		solisten_proto(so, backlog);
 	}
 	SOCK_UNLOCK(so);
-	COMMON_END(PRU_LISTEN);
+
+out:
+	TCPDEBUG2(PRU_LISTEN);
+	INP_UNLOCK(inp);
+	INP_INFO_WUNLOCK(&tcbinfo);
+	return (error);
 }
 
 #ifdef INET6
@@ -317,9 +371,18 @@
 	int error = 0;
 	struct inpcb *inp;
 	struct tcpcb *tp;
-	const int inirw = INI_WRITE;
 
-	COMMON_START();
+	TCPDEBUG0;
+	INP_INFO_WLOCK(&tcbinfo);
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("tcp6_usr_listen: inp == NULL"));
+	INP_LOCK(inp);
+	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
+		error = EINVAL;
+		goto out;
+	}
+	tp = intotcpcb(inp);
+	TCPDEBUG1();
 	SOCK_LOCK(so);
 	error = solisten_proto_check(so);
 	if (error == 0 && inp->inp_lport == 0) {
@@ -333,7 +396,12 @@
 		solisten_proto(so, backlog);
 	}
 	SOCK_UNLOCK(so);
-	COMMON_END(PRU_LISTEN);
+
+out:
+	TCPDEBUG2(PRU_LISTEN);
+	INP_UNLOCK(inp);
+	INP_INFO_WUNLOCK(&tcbinfo);
+	return (error);
 }
 #endif /* INET6 */
 
@@ -351,7 +419,6 @@
 	struct inpcb *inp;
 	struct tcpcb *tp;
 	struct sockaddr_in *sinp;
-	const int inirw = INI_WRITE;
 
 	sinp = (struct sockaddr_in *)nam;
 	if (nam->sa_len != sizeof (*sinp))
@@ -365,11 +432,25 @@
 	if (jailed(td->td_ucred))
 		prison_remote_ip(td->td_ucred, 0, &sinp->sin_addr.s_addr);
 
-	COMMON_START();
+	TCPDEBUG0;
+	INP_INFO_WLOCK(&tcbinfo);
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("tcp_usr_connect: inp == NULL"));
+	INP_LOCK(inp);
+	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
+		error = EINVAL;
+		goto out;
+	}
+	tp = intotcpcb(inp);
+	TCPDEBUG1();
 	if ((error = tcp_connect(tp, nam, td)) != 0)
 		goto out;
 	error = tcp_output(tp);
-	COMMON_END(PRU_CONNECT);
+out:
+	TCPDEBUG2(PRU_CONNECT);
+	INP_UNLOCK(inp);
+	INP_INFO_WUNLOCK(&tcbinfo);
+	return (error);
 }
 
 #ifdef INET6
@@ -380,7 +461,8 @@
 	struct inpcb *inp;
 	struct tcpcb *tp;
 	struct sockaddr_in6 *sin6p;
-	const int inirw = INI_WRITE;
+
+	TCPDEBUG0;
 
 	sin6p = (struct sockaddr_in6 *)nam;
 	if (nam->sa_len != sizeof (*sin6p))
@@ -392,7 +474,16 @@
 	    && IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr))
 		return (EAFNOSUPPORT);
 
-	COMMON_START();
+	INP_INFO_WLOCK(&tcbinfo);
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("tcp6_usr_connect: inp == NULL"));
+	INP_LOCK(inp);
+	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
+		error = EINVAL;
+		goto out;
+	}
+	tp = intotcpcb(inp);
+	TCPDEBUG1();
 	if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) {
 		struct sockaddr_in sin;
 
@@ -415,7 +506,12 @@
 	if ((error = tcp6_connect(tp, nam, td)) != 0)
 		goto out;
 	error = tcp_output(tp);
-	COMMON_END(PRU_CONNECT);
+
+out:
+	TCPDEBUG2(PRU_CONNECT);
+	INP_UNLOCK(inp);
+	INP_INFO_WUNLOCK(&tcbinfo);
+	return (error);
 }
 #endif /* INET6 */
 
@@ -433,14 +529,27 @@
 static int
 tcp_usr_disconnect(struct socket *so)
 {
-	int error = 0;
 	struct inpcb *inp;
 	struct tcpcb *tp;
-	const int inirw = INI_WRITE;
+	int error = 0;
 
-	COMMON_START();
-	tp = tcp_disconnect(tp);
-	COMMON_END(PRU_DISCONNECT);
+	TCPDEBUG0;
+	INP_INFO_WLOCK(&tcbinfo);
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("tcp_usr_disconnect: inp == NULL"));
+	INP_LOCK(inp);
+	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
+		error = EINVAL;
+		goto out;
+	}
+	tp = intotcpcb(inp);
+	TCPDEBUG1();
+	tcp_disconnect(tp);
+out:
+	TCPDEBUG2(PRU_DISCONNECT);
+	INP_UNLOCK(inp);
+	INP_INFO_WUNLOCK(&tcbinfo);
+	return (error);
 }
 
 /*
@@ -463,14 +572,13 @@
 		goto out;
 	}
 
-	INP_INFO_RLOCK(&tcbinfo);
 	inp = sotoinpcb(so);
-	if (!inp) {
-		INP_INFO_RUNLOCK(&tcbinfo);
-		return (EINVAL);
+	KASSERT(inp != NULL, ("tcp_usr_accept: inp == NULL"));
+	INP_LOCK(inp);
+	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
+		error = EINVAL;
+		goto out;
 	}
-	INP_LOCK(inp);
-	INP_INFO_RUNLOCK(&tcbinfo);
 	tp = intotcpcb(inp);
 	TCPDEBUG1();
 
@@ -482,9 +590,9 @@
 	port = inp->inp_fport;
 	addr = inp->inp_faddr;
 
-out:	TCPDEBUG2(PRU_ACCEPT);
-	if (tp)
-		INP_UNLOCK(inp);
+out:
+	TCPDEBUG2(PRU_ACCEPT);
+	INP_UNLOCK(inp);
 	if (error == 0)
 		*nam = in_sockaddr(port, &addr);
 	return error;
@@ -508,16 +616,16 @@
 		goto out;
 	}
 
-	INP_INFO_RLOCK(&tcbinfo);
 	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_RUNLOCK(&tcbinfo);
-		return (EINVAL);
+	KASSERT(inp != NULL, ("tcp6_usr_accept: inp == NULL"));
+	INP_LOCK(inp);
+	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
+		error = EINVAL;
+		goto out;
 	}
-	INP_LOCK(inp);
-	INP_INFO_RUNLOCK(&tcbinfo);
 	tp = intotcpcb(inp);
 	TCPDEBUG1();
+
 	/*
 	 * We inline in6_mapped_peeraddr and COMMON_END here, so that we can
 	 * copy the data of interest and defer the malloc until after we
@@ -532,9 +640,9 @@
 		addr6 = inp->in6p_faddr;
 	}
 
-out:	TCPDEBUG2(PRU_ACCEPT);
-	if (tp)
-		INP_UNLOCK(inp);
+out:
+	TCPDEBUG2(PRU_ACCEPT);
+	INP_UNLOCK(inp);
 	if (error == 0) {
 		if (v4)
 			*nam = in6_v4mapsin6_sockaddr(port, &addr);
@@ -575,14 +683,29 @@
 	int error = 0;
 	struct inpcb *inp;
 	struct tcpcb *tp;
-	const int inirw = INI_WRITE;
+
 
-	COMMON_START();
+	TCPDEBUG0;
+	INP_INFO_WLOCK(&tcbinfo);
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("inp == NULL"));
+	INP_LOCK(inp);
+	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
+		error = EINVAL;
+		goto out;
+	}
+	tp = intotcpcb(inp);
+	TCPDEBUG1();
 	socantsendmore(so);
-	tp = tcp_usrclosed(tp);
-	if (tp)
-		error = tcp_output(tp);
-	COMMON_END(PRU_SHUTDOWN);
+	tcp_usrclosed(tp);
+	error = tcp_output(tp);
+
+out:
+	TCPDEBUG2(PRU_SHUTDOWN);
+	INP_UNLOCK(inp);
+	INP_INFO_WUNLOCK(&tcbinfo);
+
+	return (error);
 }
 
 /*
@@ -591,14 +714,26 @@
 static int
 tcp_usr_rcvd(struct socket *so, int flags)
 {
-	int error = 0;
 	struct inpcb *inp;
 	struct tcpcb *tp;
-	const int inirw = INI_READ;
+	int error = 0;
 
-	COMMON_START();
+	TCPDEBUG0;
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("tcp_usr_rcvd: inp == NULL"));
+	INP_LOCK(inp);
+	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
+		error = EINVAL;
+		goto out;
+	}
+	tp = intotcpcb(inp);
+	TCPDEBUG1();
 	tcp_output(tp);
-	COMMON_END(PRU_RCVD);
+
+out:
+	TCPDEBUG2(PRU_RCVD);
+	INP_UNLOCK(inp);
+	return (error);
 }
 
 /*
@@ -615,36 +750,32 @@
 	int error = 0;
 	struct inpcb *inp;
 	struct tcpcb *tp;
-	int unlocked = 0;
+	int headlocked = 0;
 #ifdef INET6
 	int isipv6;
 #endif
 	TCPDEBUG0;
 
 	/*
-	 * Need write lock here because this function might call
-	 * tcp_connect or tcp_usrclosed.
-	 * We really want to have to this function upgrade from read lock
-	 * to write lock.  XXX
+	 * We require the pcbinfo lock in two cases:
+	 *
+	 * (1) An implied connect is taking place, which can result in
+	 *     binding IPs and ports and hence modification of the pcb hash
+	 *     chains.
+	 *
+	 * (2) PRUS_EOF is set, resulting in explicit close on the send.
 	 */
-	INP_INFO_WLOCK(&tcbinfo);
+	if ((nam != NULL) || (flags & PRUS_EOF)) {
+		INP_INFO_WLOCK(&tcbinfo);
+		headlocked = 1;
+	}
 	inp = sotoinpcb(so);
-	if (inp == NULL) {
-		/*
-		 * OOPS! we lost a race, the TCP session got reset after
-		 * we checked SBS_CANTSENDMORE, eg: while doing uiomove or a
-		 * network interrupt in the non-splnet() section of sosend().
-		 */
-		if (m)
-			m_freem(m);
-		if (control)
-			m_freem(control);
-		error = ECONNRESET;	/* XXX EPIPE? */
-		tp = NULL;
-		TCPDEBUG1();
+	KASSERT(inp != NULL, ("tcp_usr_send: inp == NULL"));
+	INP_LOCK(inp);
+	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
+		error = EINVAL;
 		goto out;
 	}
-	INP_LOCK(inp);
 #ifdef INET6
 	isipv6 = nam && nam->sa_family == AF_INET6;
 #endif /* INET6 */
@@ -670,6 +801,7 @@
 			 * initialize maxseg/maxopd using peer's cached
 			 * MSS.
 			 */
+			INP_INFO_WLOCK_ASSERT(&tcbinfo);
 #ifdef INET6
 			if (isipv6)
 				error = tcp6_connect(tp, nam, td);
@@ -681,17 +813,19 @@
 			tp->snd_wnd = TTCP_CLIENT_SND_WND;
 			tcp_mss(tp, -1);
 		}
-
 		if (flags & PRUS_EOF) {
 			/*
 			 * Close the send side of the connection after
 			 * the data is sent.
 			 */
+			INP_INFO_WLOCK_ASSERT(&tcbinfo);
 			socantsendmore(so);
-			tp = tcp_usrclosed(tp);
+			tcp_usrclosed(tp);
+		}
+		if (headlocked) {
+			INP_INFO_WUNLOCK(&tcbinfo);
+			headlocked = 0;
 		}
-		INP_INFO_WUNLOCK(&tcbinfo);
-		unlocked = 1;
 		if (tp != NULL) {
 			if (flags & PRUS_MORETOCOME)
 				tp->t_flags |= TF_MORETOCOME;
@@ -700,6 +834,9 @@
 				tp->t_flags &= ~TF_MORETOCOME;
 		}
 	} else {
+		/*
+		 * XXXRW: PRUS_EOF not implemented with PRUS_OOB?
+		 */
 		SOCKBUF_LOCK(&so->so_snd);
 		if (sbspace(&so->so_snd) < -512) {
 			SOCKBUF_UNLOCK(&so->so_snd);
@@ -724,6 +861,7 @@
 			 * initialize maxseg/maxopd using peer's cached
 			 * MSS.
 			 */
+			INP_INFO_WLOCK_ASSERT(&tcbinfo);
 #ifdef INET6
 			if (isipv6)
 				error = tcp6_connect(tp, nam, td);
@@ -734,9 +872,12 @@
 				goto out;
 			tp->snd_wnd = TTCP_CLIENT_SND_WND;
 			tcp_mss(tp, -1);
+			INP_INFO_WUNLOCK(&tcbinfo);
+			headlocked = 0;
+		} else if (nam) {
+			INP_INFO_WUNLOCK(&tcbinfo);
+			headlocked = 0;
 		}
-		INP_INFO_WUNLOCK(&tcbinfo);
-		unlocked = 1;
 		tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
 		tp->t_flags |= TF_FORCEDATA;
 		error = tcp_output(tp);
@@ -745,9 +886,8 @@
 out:
 	TCPDEBUG2((flags & PRUS_OOB) ? PRU_SENDOOB :
 		  ((flags & PRUS_EOF) ? PRU_SEND_EOF : PRU_SEND));
-	if (tp)
-		INP_UNLOCK(inp);
-	if (!unlocked)
+	INP_UNLOCK(inp);
+	if (headlocked)
 		INP_INFO_WUNLOCK(&tcbinfo);
 	return (error);
 }
@@ -755,17 +895,40 @@
 /*
  * Abort the TCP.
  */
-static int
+static void
 tcp_usr_abort(struct socket *so)
 {
-	int error = 0;
+#if 0
 	struct inpcb *inp;
 	struct tcpcb *tp;
-	const int inirw = INI_WRITE;
+#endif
+
+	/*
+	 * XXXRW: This is not really quite the same, as we want to tcp_drop()
+	 * rather than tcp_disconnect(), I think, but for now I'll avoid
+	 * replicating all the tear-down logic here.
+	 */
+	tcp_usr_detach(so);
 
-	COMMON_START();
+#if 0
+	TCPDEBUG0;
+	INP_INFO_WLOCK(&tcbinfo);
+	inp = sotoinpcb(so);
+	INP_LOCK(inp);
+	/*
+	 * Do we need to handle timewait here?  Aborted connections should
+	 * never generate a FIN?
+	 */
+	KASSERT((inp->inp_vflag & INP_TIMEWAIT) == 0,
+	    ("tcp_usr_abort: timewait"));
+	tp = intotcpcb(inp);
+	TCPDEBUG1();
 	tp = tcp_drop(tp, ECONNABORTED);
-	COMMON_END(PRU_ABORT);
+		TCPDEBUG2(PRU_ABORT);
+	if (tp != NULL)
+		INP_UNLOCK(inp);
+	INP_INFO_WUNLOCK(&tcbinfo);
+#endif
 }
 
 /*
@@ -777,9 +940,17 @@
 	int error = 0;
 	struct inpcb *inp;
 	struct tcpcb *tp;
-	const int inirw = INI_READ;
 
-	COMMON_START();
+	TCPDEBUG0;
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("tcp_usr_rcvoob: inp == NULL"));
+	INP_LOCK(inp);
+	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
+		error = EINVAL;
+		goto out;
+	}
+	tp = intotcpcb(inp);
+	TCPDEBUG1();
 	if ((so->so_oobmark == 0 &&
 	     (so->so_rcv.sb_state & SBS_RCVATMARK) == 0) ||
 	    so->so_options & SO_OOBINLINE ||
@@ -795,7 +966,11 @@
 	*mtod(m, caddr_t) = tp->t_iobc;
 	if ((flags & MSG_PEEK) == 0)
 		tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
-	COMMON_END(PRU_RCVOOB);
+
+out:
+	TCPDEBUG2(PRU_RCVOOB);
+	INP_UNLOCK(inp);
+	return (error);
 }
 
 struct pr_usrreqs tcp_usrreqs = {
@@ -860,6 +1035,9 @@
 	u_short lport;
 	int error;
 
+	INP_INFO_WLOCK_ASSERT(&tcbinfo);
+	INP_LOCK_ASSERT(inp);
+
 	if (inp->inp_lport == 0) {
 		error = in_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
 		if (error)
@@ -911,6 +1089,9 @@
 	struct in6_addr *addr6;
 	int error;
 
+	INP_INFO_WLOCK_ASSERT(&tcbinfo);
+	INP_LOCK_ASSERT(inp);
+
 	if (inp->inp_lport == 0) {
 		error = in6_pcbbind(inp, (struct sockaddr *)0, td->td_ucred);
 		if (error)
@@ -1020,14 +1201,9 @@
 	struct	tcp_info ti;
 
 	error = 0;
-	INP_INFO_RLOCK(&tcbinfo);
 	inp = sotoinpcb(so);
-	if (inp == NULL) {
-		INP_INFO_RUNLOCK(&tcbinfo);
-		return (ECONNRESET);
-	}
+	KASSERT(inp != NULL, ("tcp_ctloutput: inp == NULL"));
 	INP_LOCK(inp);
-	INP_INFO_RUNLOCK(&tcbinfo);
 	if (sopt->sopt_level != IPPROTO_TCP) {
 		INP_UNLOCK(inp);
 #ifdef INET6
@@ -1038,6 +1214,10 @@
 		error = ip_ctloutput(so, sopt);
 		return (error);
 	}
+	if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) {
+		error = ECONNRESET;
+		goto out;
+	}
 	tp = intotcpcb(inp);
 
 	switch (sopt->sopt_dir) {
@@ -1152,6 +1332,7 @@
 		}
 		break;
 	}
+out:
 	INP_UNLOCK(inp);
 	return (error);
 }
@@ -1204,19 +1385,19 @@
 #endif
 	inp->inp_vflag |= INP_IPV4;
 	tp = tcp_newtcpcb(inp);
-	if (tp == 0) {
-		int nofd = so->so_state & SS_NOFDREF;	/* XXX */
-
-		so->so_state &= ~SS_NOFDREF;	/* don't free the socket yet */
-
+	if (tp == NULL) {
 		INP_LOCK(inp);
 #ifdef INET6
-		if (isipv6)
+		if (isipv6) {
 			in6_pcbdetach(inp);
-		else
+			in6_pcbfree(inp);
+		} else {
+#endif
+			in_pcbdetach(inp);
+			in_pcbfree(inp);
+#ifdef INET6
+		}
 #endif
-		in_pcbdetach(inp);
-		so->so_state |= nofd;
 		return (ENOBUFS);
 	}
 	tp->t_state = TCPS_CLOSED;
@@ -1231,7 +1412,7 @@
  * current input data; switch states based on user close, and
  * send segment to peer (with FIN).
  */
-static struct tcpcb *
+static void
 tcp_disconnect(tp)
 	register struct tcpcb *tp;
 {
@@ -1241,18 +1422,24 @@
 	INP_INFO_WLOCK_ASSERT(&tcbinfo);
 	INP_LOCK_ASSERT(inp);
 
-	if (tp->t_state < TCPS_ESTABLISHED)
+	/*
+	 * Neither tcp_close() nor tcp_drop() should return NULL, as the
+	 * socket is still open.
+	 */
+	if (tp->t_state < TCPS_ESTABLISHED) {
 		tp = tcp_close(tp);
-	else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
+		KASSERT(tp != NULL,
+		    ("tcp_disconnect: tcp_close() returned NULL"));
+	} else if ((so->so_options & SO_LINGER) && so->so_linger == 0) {
 		tp = tcp_drop(tp, 0);
-	else {
+		KASSERT(tp != NULL,
+		    ("tcp_disconnect: tcp_drop() returned NULL"));
+	} else {
 		soisdisconnecting(so);
 		sbflush(&so->so_rcv);
-		tp = tcp_usrclosed(tp);
-		if (tp)
-			(void) tcp_output(tp);
+		tcp_usrclosed(tp);
+		tcp_output(tp);
 	}
-	return (tp);
 }
 
 /*
@@ -1265,7 +1452,7 @@
  * for peer to send FIN or not respond to keep-alives, etc.
  * We can let the user exit from the close as soon as the FIN is acked.
  */
-static struct tcpcb *
+static void
 tcp_usrclosed(tp)
 	register struct tcpcb *tp;
 {
@@ -1279,6 +1466,12 @@
 	case TCPS_LISTEN:
 		tp->t_state = TCPS_CLOSED;
 		tp = tcp_close(tp);
+		/*
+		 * tcp_close() should never return NULL here as the socket is
+		 * still open.
+		 */
+		KASSERT(tp != NULL,
+		    ("tcp_usrclosed: tcp_close() returned NULL"));
 		break;
 
 	case TCPS_SYN_SENT:
@@ -1301,5 +1494,4 @@
 			callout_reset(tp->tt_2msl, tcp_maxidle,
 				      tcp_timer_2msl, tp);
 	}
-	return (tp);
 }
--- netinet/tcp_var.h	2006/02/16 19:40:18
+++ netinet/tcp_var.h	2006/02/18 20:36:51
@@ -518,10 +518,10 @@
 
 struct tcpcb *
 	 tcp_close(struct tcpcb *);
+void	 tcp_discardcb(struct tcpcb *);
 void	 tcp_twstart(struct tcpcb *);
 int	 tcp_twrecycleable(struct tcptw *tw);
-struct tcptw *
-	 tcp_twclose(struct tcptw *_tw, int _reuse);
+void	 tcp_twclose(struct tcptw *_tw, int _reuse);
 void	 tcp_ctlinput(int, struct sockaddr *, void *);
 int	 tcp_ctloutput(struct socket *, struct sockopt *);
 struct tcpcb *
--- netinet/udp_usrreq.c	2006/01/24 09:11:50
+++ netinet/udp_usrreq.c	2006/02/17 23:33:04
@@ -125,7 +125,7 @@
 static void udp_append(struct inpcb *last, struct ip *ip, struct mbuf *n,
 		int off, struct sockaddr_in *udp_in);
 
-static int udp_detach(struct socket *so);
+static void udp_detach(struct socket *so);
 static	int udp_output(struct inpcb *, struct mbuf *, struct sockaddr *,
 		struct mbuf *, struct thread *);
 
@@ -929,22 +929,19 @@
 SYSCTL_ULONG(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW,
     &udp_recvspace, 0, "Maximum space for incoming UDP datagrams");
 
-static int
+static void
 udp_abort(struct socket *so)
 {
 	struct inpcb *inp;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("udp_abort: inp == NULL"));
 	INP_INFO_WLOCK(&udbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&udbinfo);
-		return EINVAL;	/* ??? possible? panic instead? */
-	}
 	INP_LOCK(inp);
 	soisdisconnected(so);
 	in_pcbdetach(inp);
+	in_pcbfree(inp);
 	INP_INFO_WUNLOCK(&udbinfo);
-	return 0;
 }
 
 static int
@@ -953,12 +950,9 @@
 	struct inpcb *inp;
 	int error;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp == NULL, ("udp_attach: inp != NULL"));
 	INP_INFO_WLOCK(&udbinfo);
-	inp = sotoinpcb(so);
-	if (inp != 0) {
-		INP_INFO_WUNLOCK(&udbinfo);
-		return EINVAL;
-	}
 	error = soreserve(so, udp_sendspace, udp_recvspace);
 	if (error) {
 		INP_INFO_WUNLOCK(&udbinfo);
@@ -985,12 +979,9 @@
 	struct inpcb *inp;
 	int error;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("udp_bind: inp == NULL"));
 	INP_INFO_WLOCK(&udbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&udbinfo);
-		return EINVAL;
-	}
 	INP_LOCK(inp);
 	error = in_pcbbind(inp, nam, td->td_ucred);
 	INP_UNLOCK(inp);
@@ -1005,12 +996,9 @@
 	int error;
 	struct sockaddr_in *sin;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("udp_connect: inp == NULL"));
 	INP_INFO_WLOCK(&udbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&udbinfo);
-		return EINVAL;
-	}
 	INP_LOCK(inp);
 	if (inp->inp_faddr.s_addr != INADDR_ANY) {
 		INP_UNLOCK(inp);
@@ -1028,21 +1016,18 @@
 	return error;
 }
 
-static int
+static void
 udp_detach(struct socket *so)
 {
 	struct inpcb *inp;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("udp_detach: inp == NULL"));
 	INP_INFO_WLOCK(&udbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&udbinfo);
-		return EINVAL;
-	}
 	INP_LOCK(inp);
 	in_pcbdetach(inp);
+	in_pcbfree(inp);
 	INP_INFO_WUNLOCK(&udbinfo);
-	return 0;
 }
 
 static int
@@ -1050,12 +1035,9 @@
 {
 	struct inpcb *inp;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("udp_disconnect: inp == NULL"));
 	INP_INFO_WLOCK(&udbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&udbinfo);
-		return EINVAL;
-	}
 	INP_LOCK(inp);
 	if (inp->inp_faddr.s_addr == INADDR_ANY) {
 		INP_INFO_WUNLOCK(&udbinfo);
@@ -1078,6 +1060,7 @@
 	struct inpcb *inp;
 
 	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("udp_send: inp == NULL"));
 	return udp_output(inp, m, addr, control, td);
 }
 
@@ -1086,14 +1069,9 @@
 {
 	struct inpcb *inp;
 
-	INP_INFO_RLOCK(&udbinfo);
 	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_RUNLOCK(&udbinfo);
-		return EINVAL;
-	}
+	KASSERT(inp != NULL, ("udp_shutdown: inp == NULL"));
 	INP_LOCK(inp);
-	INP_INFO_RUNLOCK(&udbinfo);
 	socantsendmore(so);
 	INP_UNLOCK(inp);
 	return 0;
--- netinet6/in6_pcb.c	2005/09/07 10:17:18
+++ netinet6/in6_pcb.c	2006/02/19 19:33:03
@@ -421,17 +421,23 @@
 #ifdef IPSEC
 	ipsec_pcbdisconn(inp->inp_sp);
 #endif
-	if (inp->inp_socket->so_state & SS_NOFDREF)
-		in6_pcbdetach(inp);
+}
+
+void
+in6_pcbdetach(struct inpcb *inp)
+{
+
+	KASSERT(inp->inp_socket != NULL, ("in6_pcbdetach: inp_socket == NULL"));
+	inp->inp_socket->so_pcb = NULL;
+	inp->inp_socket = NULL;
 }
 
 void
-in6_pcbdetach(inp)
-	struct inpcb *inp;
+in6_pcbfree(struct inpcb *inp)
 {
-	struct socket *so = inp->inp_socket;
 	struct inpcbinfo *ipi = inp->inp_pcbinfo;
 
+	KASSERT(inp->inp_socket == NULL, ("in6_pcbfree: inp_socket != NULL"));
 	INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
 	INP_LOCK_ASSERT(inp);
 
@@ -441,14 +447,6 @@
 #endif /* IPSEC */
 	inp->inp_gencnt = ++ipi->ipi_gencnt;
 	in_pcbremlists(inp);
-
-	if (so) {
-		ACCEPT_LOCK();
-		SOCK_LOCK(so);
-		so->so_pcb = NULL;
-		sotryfree(so);
-	}
-
  	ip6_freepcbopts(inp->in6p_outputopts);
  	ip6_freemoptions(inp->in6p_moptions);
 	/* Check and free IPv4 related resources in case of mapped addr */
--- netinet6/in6_pcb.h	2005/01/07 02:32:16
+++ netinet6/in6_pcb.h	2006/02/19 19:33:03
@@ -76,6 +76,7 @@
 int	in6_pcbconnect __P((struct inpcb *, struct sockaddr *, struct ucred *));
 void	in6_pcbdetach __P((struct inpcb *));
 void	in6_pcbdisconnect __P((struct inpcb *));
+void	in6_pcbfree __P((struct inpcb *));
 int	in6_pcbladdr __P((struct inpcb *, struct sockaddr *,
 			  struct in6_addr **));
 struct	inpcb *
--- netinet6/raw_ip6.c	2005/10/19 01:25:25
+++ netinet6/raw_ip6.c	2006/02/19 19:33:03
@@ -549,27 +549,18 @@
 	struct icmp6_filter *filter;
 	int error, s;
 
-	INP_INFO_WLOCK(&ripcbinfo);
 	inp = sotoinpcb(so);
-	if (inp) {
-		INP_INFO_WUNLOCK(&ripcbinfo);
-		panic("rip6_attach");
-	}
-	if (td && (error = suser(td)) != 0) {
-		INP_INFO_WUNLOCK(&ripcbinfo);
+	KASSERT(inp == NULL, ("rip6_attach: inp != NULL"));
+	if (td && (error = suser(td)) != 0)
 		return error;
-	}
 	error = soreserve(so, rip_sendspace, rip_recvspace);
-	if (error) {
-		INP_INFO_WUNLOCK(&ripcbinfo);
+	if (error)
 		return error;
-	}
 	MALLOC(filter, struct icmp6_filter *,
 	       sizeof(struct icmp6_filter), M_PCB, M_NOWAIT);
-	if (filter == NULL) {
-		INP_INFO_WUNLOCK(&ripcbinfo);
+	if (filter == NULL)
 		return ENOMEM;
-	}
+	INP_INFO_WLOCK(&ripcbinfo);
 	s = splnet();
 	error = in_pcballoc(so, &ripcbinfo, "raw6inp");
 	splx(s);
@@ -591,17 +582,13 @@
 	return 0;
 }
 
-static int
+static void
 rip6_detach(struct socket *so)
 {
 	struct inpcb *inp;
 
-	INP_INFO_WLOCK(&ripcbinfo);
 	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&ripcbinfo);
-		panic("rip6_detach");
-	}
+	KASSERT(inp != NULL, ("rip6_detach: inp == NULL"));
 	/* xxx: RSVP */
 	if (so == ip6_mrouter)
 		ip6_mrouter_done();
@@ -609,17 +596,18 @@
 		FREE(inp->in6p_icmp6filt, M_PCB);
 		inp->in6p_icmp6filt = NULL;
 	}
+	INP_INFO_WLOCK(&ripcbinfo);
 	INP_LOCK(inp);
 	in6_pcbdetach(inp);
+	in6_pcbfree(inp);
 	INP_INFO_WUNLOCK(&ripcbinfo);
-	return 0;
 }
 
-static int
+static void
 rip6_abort(struct socket *so)
 {
 	soisdisconnected(so);
-	return rip6_detach(so);
+	rip6_detach(so);
 }
 
 static int
@@ -630,7 +618,8 @@
 	if ((so->so_state & SS_ISCONNECTED) == 0)
 		return ENOTCONN;
 	inp->in6p_faddr = in6addr_any;
-	return rip6_abort(so);
+	rip6_abort(so);
+	return (0);
 }
 
 static int
@@ -641,6 +630,7 @@
 	struct ifaddr *ia = NULL;
 	int error = 0;
 
+	KASSERT(inp != NULL, ("rip6_bind: inp == NULL"));
 	if (nam->sa_len != sizeof(*addr))
 		return EINVAL;
 	if (TAILQ_EMPTY(&ifnet) || addr->sin6_family != AF_INET6)
@@ -674,6 +664,7 @@
 	struct ifnet *ifp = NULL;
 	int error = 0, scope_ambiguous = 0;
 
+	KASSERT(inp != NULL, ("rip6_connect: inp == NULL"));
 	if (nam->sa_len != sizeof(*addr))
 		return EINVAL;
 	if (TAILQ_EMPTY(&ifnet))
@@ -726,10 +717,9 @@
 {
 	struct inpcb *inp;
 
-	INP_INFO_RLOCK(&ripcbinfo);
 	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("rip6_shutdown: inp == NULL"));
 	INP_LOCK(inp);
-	INP_INFO_RUNLOCK(&ripcbinfo);
 	socantsendmore(so);
 	INP_UNLOCK(inp);
 	return 0;
@@ -744,6 +734,7 @@
 	struct sockaddr_in6 *dst;
 	int ret;
 
+	KASSERT(inp != NULL, ("rip6_send: inp == NULL"));
 	INP_INFO_WLOCK(&ripcbinfo);
 	/* always copy sockaddr to avoid overwrites */
 	/* Unlocked read. */
--- netinet6/udp6_usrreq.c	2006/02/04 05:50:26
+++ netinet6/udp6_usrreq.c	2006/02/19 19:33:03
@@ -117,7 +117,7 @@
  */
 
 extern	struct protosw inetsw[];
-static	int udp6_detach __P((struct socket *so));
+static	void udp6_detach __P((struct socket *so));
 
 int
 udp6_input(mp, offp, proto)
@@ -497,25 +497,19 @@
 	    0, 0,
 	    udp6_getcred, "S,xucred", "Get the xucred of a UDP6 connection");
 
-static int
+static void
 udp6_abort(struct socket *so)
 {
 	struct inpcb *inp;
-	int s;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("udp6_abort: inp == NULL"));
 	INP_INFO_WLOCK(&udbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&udbinfo);
-		return EINVAL;	/* ??? possible? panic instead? */
-	}
+	INP_LOCK(inp);
 	soisdisconnected(so);
-	s = splnet();
-	INP_LOCK(inp);
 	in6_pcbdetach(inp);
+	in6_pcbfree(inp);
 	INP_INFO_WUNLOCK(&udbinfo);
-	splx(s);
-	return 0;
 }
 
 static int
@@ -524,21 +518,15 @@
 	struct inpcb *inp;
 	int s, error;
 
-	INP_INFO_WLOCK(&udbinfo);
 	inp = sotoinpcb(so);
-	if (inp != 0) {
-		INP_INFO_WUNLOCK(&udbinfo);
-		return EINVAL;
-	}
-
+	KASSERT(inp == NULL, ("udp6_attach: inp == NULL"));
 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
 		error = soreserve(so, udp_sendspace, udp_recvspace);
-		if (error) {
-			INP_INFO_WUNLOCK(&udbinfo);
+		if (error)
 			return error;
-		}
 	}
 	s = splnet();
+	INP_INFO_WLOCK(&udbinfo);
 	error = in_pcballoc(so, &udbinfo, "udp6inp");
 	splx(s);
 	if (error) {
@@ -570,12 +558,9 @@
 	struct inpcb *inp;
 	int s, error;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("udp6_bind: inp == NULL"));
 	INP_INFO_WLOCK(&udbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&udbinfo);
-		return EINVAL;
-	}
 	INP_LOCK(inp);
 
 	inp->inp_vflag &= ~INP_IPV4;
@@ -615,14 +600,10 @@
 	struct inpcb *inp;
 	int s, error;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("udp6_connect: inp == NULL"));
 	INP_INFO_WLOCK(&udbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&udbinfo);
-		return EINVAL;
-	}
 	INP_LOCK(inp);
-
 	if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) {
 		struct sockaddr_in6 *sin6_p;
 
@@ -666,24 +647,18 @@
 	return error;
 }
 
-static int
+static void
 udp6_detach(struct socket *so)
 {
 	struct inpcb *inp;
-	int s;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("udp6_detach: inp == NULL"));
 	INP_INFO_WLOCK(&udbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&udbinfo);
-		return EINVAL;
-	}
 	INP_LOCK(inp);
-	s = splnet();
 	in6_pcbdetach(inp);
-	splx(s);
+	in6_pcbfree(inp);
 	INP_INFO_WUNLOCK(&udbinfo);
-	return 0;
 }
 
 static int
@@ -692,12 +667,9 @@
 	struct inpcb *inp;
 	int error, s;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("udp6_disconnect: inp == NULL"));
 	INP_INFO_WLOCK(&udbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&udbinfo);
-		return EINVAL;
-	}
 	INP_LOCK(inp);
 
 #ifdef INET
@@ -734,13 +706,9 @@
 	struct inpcb *inp;
 	int error = 0;
 
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("udp6_send: inp == NULL"));
 	INP_INFO_WLOCK(&udbinfo);
-	inp = sotoinpcb(so);
-	if (inp == 0) {
-		INP_INFO_WUNLOCK(&udbinfo);
-		m_freem(m);
-		return EINVAL;
-	}
 	INP_LOCK(inp);
 
 	if (addr) {
--- netipsec/keysock.c	2006/01/21 10:48:01
+++ netipsec/keysock.c	2006/02/15 20:29:56
@@ -369,14 +369,11 @@
  * key_abort()
  * derived from net/rtsock.c:rts_abort()
  */
-static int
+static void
 key_abort(struct socket *so)
 {
-	int s, error;
-	s = splnet();
-	error = raw_usrreqs.pru_abort(so);
-	splx(s);
-	return error;
+
+	raw_usrreqs.pru_abort(so);
 }
 
 /*
@@ -459,24 +456,20 @@
  * key_detach()
  * derived from net/rtsock.c:rts_detach()
  */
-static int
+static void
 key_detach(struct socket *so)
 {
 	struct keycb *kp = (struct keycb *)sotorawcb(so);
 	int s, error;
 
-	s = splnet();
-	if (kp != 0) {
-		if (kp->kp_raw.rcb_proto.sp_protocol
-		    == PF_KEY) /* XXX: AF_KEY */
-			key_cb.key_count--;
-		key_cb.any_count--;
+	KASSERT(kp != NULL, ("key_detach: kp == NULL"));
+	if (kp->kp_raw.rcb_proto.sp_protocol
+	    == PF_KEY) /* XXX: AF_KEY */
+		key_cb.key_count--;
+	key_cb.any_count--;
 
-		key_freereg(so);
-	}
-	error = raw_usrreqs.pru_detach(so);
-	splx(s);
-	return error;
+	key_freereg(so);
+	raw_usrreqs.pru_detach(so);
 }
 
 /*
--- netipx/ipx_pcb.c	2005/01/09 05:10:49
+++ netipx/ipx_pcb.c	2006/02/12 19:33:28
@@ -63,6 +63,7 @@
 {
 	register struct ipxpcb *ipxp;
 
+	KASSERT(so->so_pcb == NULL, ("ipx_pcballoc: so_pcb != NULL"));
 	IPX_LIST_LOCK_ASSERT();
 
 	MALLOC(ipxp, struct ipxpcb *, sizeof *ipxp, M_PCB, M_NOWAIT | M_ZERO);
@@ -285,10 +286,7 @@
 	IPX_LIST_LOCK_ASSERT();
 	IPX_LOCK_ASSERT(ipxp);
 
-	ACCEPT_LOCK();
-	SOCK_LOCK(so);
 	so->so_pcb = NULL;
-	sotryfree(so);
 	if (ipxp->ipxp_route.ro_rt != NULL)
 		RTFREE(ipxp->ipxp_route.ro_rt);
 	LIST_REMOVE(ipxp, ipxp_list);
--- netipx/ipx_usrreq.c	2005/01/09 05:20:42
+++ netipx/ipx_usrreq.c	2006/02/15 20:30:27
@@ -74,12 +74,12 @@
 SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW,
             &ipxrecvspace, 0, "");
 
-static	int ipx_usr_abort(struct socket *so);
+static	void ipx_usr_abort(struct socket *so);
 static	int ipx_attach(struct socket *so, int proto, struct thread *td);
 static	int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
 static	int ipx_connect(struct socket *so, struct sockaddr *nam,
 			struct thread *td);
-static	int ipx_detach(struct socket *so);
+static	void ipx_detach(struct socket *so);
 static	int ipx_disconnect(struct socket *so);
 static	int ipx_send(struct socket *so, int flags, struct mbuf *m,
 		     struct sockaddr *addr, struct mbuf *control,
@@ -428,7 +428,7 @@
 	return (error);
 }
 
-static int
+static void
 ipx_usr_abort(so)
 	struct socket *so;
 {
@@ -439,10 +439,6 @@
 	ipx_pcbdetach(ipxp);
 	IPX_LIST_UNLOCK();
 	soisdisconnected(so);
-	ACCEPT_LOCK();
-	SOCK_LOCK(so);
-	sotryfree(so);
-	return (0);
 }
 
 static int
@@ -454,13 +450,13 @@
 	struct ipxpcb *ipxp = sotoipxpcb(so);
 	int error;
 
-	if (ipxp != NULL)
-		return (EINVAL);
+	error = soreserve(so, ipxsendspace, ipxrecvspace);
+	if (error != 0)
+		return (error);
+	KASSERT(ipxp == NULL, ("ipx_attach: ipxp != NULL"));
 	IPX_LIST_LOCK();
 	error = ipx_pcballoc(so, &ipxpcb_list, td);
 	IPX_LIST_UNLOCK();
-	if (error == 0)
-		error = soreserve(so, ipxsendspace, ipxrecvspace);
 	return (error);
 }
 
@@ -473,6 +469,7 @@
 	struct ipxpcb *ipxp = sotoipxpcb(so);
 	int error;
 
+	KASSERT(ipxp != NULL, ("ipx_bind: ipxp == NULL"));
 	IPX_LIST_LOCK();
 	IPX_LOCK(ipxp);
 	error = ipx_pcbbind(ipxp, nam, td);
@@ -490,6 +487,7 @@
 	struct ipxpcb *ipxp = sotoipxpcb(so);
 	int error;
 
+	KASSERT(ipxp != NULL, ("ipx_connect: ipxp == NULL"));
 	IPX_LIST_LOCK();
 	IPX_LOCK(ipxp);
 	if (!ipx_nullhost(ipxp->ipxp_faddr)) {
@@ -505,19 +503,17 @@
 	return (error);
 }
 
-static int
+static void
 ipx_detach(so)
 	struct socket *so;
 {
 	struct ipxpcb *ipxp = sotoipxpcb(so);
 
-	if (ipxp == NULL)
-		return (ENOTCONN);
+	KASSERT(ipxp != NULL, ("ipx_detach: ipxp == NULL"));
 	IPX_LIST_LOCK();
 	IPX_LOCK(ipxp);
 	ipx_pcbdetach(ipxp);
 	IPX_LIST_UNLOCK();
-	return (0);
 }
 
 static int
@@ -527,6 +523,7 @@
 	struct ipxpcb *ipxp = sotoipxpcb(so);
 	int error;
 
+	KASSERT(ipxp != NULL, ("ipx_disconnect: ipxp == NULL"));
 	IPX_LIST_LOCK();
 	IPX_LOCK(ipxp);
 	error = 0;
@@ -549,6 +546,7 @@
 {
 	struct ipxpcb *ipxp = sotoipxpcb(so);
 
+	KASSERT(ipxp != NULL, ("ipx_peeraddr: ipxp == NULL"));
 	ipx_setpeeraddr(ipxp, nam);
 	return (0);
 }
@@ -566,6 +564,7 @@
 	struct ipxpcb *ipxp = sotoipxpcb(so);
 	struct ipx_addr laddr;
 
+	KASSERT(ipxp != NULL, ("ipxp_send: ipxp == NULL"));
 	/*
 	 * Attempt to only acquire the necessary locks: if the socket is
 	 * already connected, we don't need to hold the IPX list lock to be
@@ -619,6 +618,8 @@
 ipx_shutdown(so)
 	struct socket *so;
 {
+
+	KASSERT(so->so_pcb != NULL, ("ipx_shutdown: so_pcb == NULL"));
 	socantsendmore(so);
 	return (0);
 }
@@ -630,6 +631,7 @@
 {
 	struct ipxpcb *ipxp = sotoipxpcb(so);
 
+	KASSERT(ipxp != NULL, ("ipx_sockaddr: ipxp == NULL"));
 	ipx_setsockaddr(ipxp, nam);
 	return (0);
 }
@@ -643,6 +645,7 @@
 	int error = 0;
 	struct ipxpcb *ipxp = sotoipxpcb(so);
 
+	KASSERT(ipxp == NULL, ("ripx_attach: ipxp != NULL"));
 	if (td != NULL && (error = suser(td)) != 0)
 		return (error);
 	/*
--- netipx/spx_usrreq.c	2006/01/14 00:11:17
+++ netipx/spx_usrreq.c	2006/02/15 20:30:27
@@ -91,13 +91,13 @@
 static	struct spxpcb *spx_timers(struct spxpcb *cb, int timer);
 static	void spx_usrclosed(struct spxpcb *cb);
 
-static	int spx_usr_abort(struct socket *so);
+static	void spx_usr_abort(struct socket *so);
 static	int spx_accept(struct socket *so, struct sockaddr **nam);
 static	int spx_attach(struct socket *so, int proto, struct thread *td);
 static	int spx_bind(struct socket *so, struct sockaddr *nam, struct thread *td);
 static	int spx_connect(struct socket *so, struct sockaddr *nam,
 			struct thread *td);
-static	int spx_detach(struct socket *so);
+static	void spx_detach(struct socket *so);
 static	int spx_usr_disconnect(struct socket *so);
 static	int spx_listen(struct socket *so, int backlog, struct thread *td);
 static	int spx_rcvd(struct socket *so, int flags);
@@ -1169,6 +1169,8 @@
 	u_short usoptval;
 	int optval;
 
+	KASSERT(ipxp != NULL, ("spx_ctloutput: ipxp == NULL"));
+
 	error = 0;
 
 	if (sopt->sopt_level != IPXPROTO_SPX) {
@@ -1176,10 +1178,7 @@
 		   stacking of protocols */
 		return (ipx_ctloutput(so, sopt));
 	}
-	if (ipxp == NULL)
-		return (EINVAL);
-	else
-		cb = ipxtospxpcb(ipxp);
+	cb = ipxtospxpcb(ipxp);
 
 	switch (sopt->sopt_dir) {
 	case SOPT_GET:
@@ -1295,7 +1294,7 @@
 	return (error);
 }
 
-static int
+static void
 spx_usr_abort(so)
 	struct socket *so;
 {
@@ -1303,13 +1302,14 @@
 	struct spxpcb *cb;
 
 	ipxp = sotoipxpcb(so);
+	KASSERT(ipxp != NULL, ("spx_usr_abort: ipxp == NULL"));
+
 	cb = ipxtospxpcb(ipxp);
 
 	IPX_LIST_LOCK();
 	IPX_LOCK(ipxp);
 	spx_drop(cb, ECONNABORTED);
 	IPX_LIST_UNLOCK();
-	return (0);
 }
 
 /*
@@ -1326,6 +1326,7 @@
 	struct sockaddr_ipx *sipx, ssipx;
 
 	ipxp = sotoipxpcb(so);
+	KASSERT(ipxp != NULL, ("spx_accept: ipxp == NULL"));
 	sipx = &ssipx;
 	bzero(sipx, sizeof *sipx);
 	sipx->sipx_len = sizeof *sipx;
@@ -1350,7 +1351,7 @@
 	int error;
 
 	ipxp = sotoipxpcb(so);
-	cb = ipxtospxpcb(ipxp);
+	KASSERT(ipxp == NULL, ("spx_attach: ipxp != NULL"));
 
 	IPX_LIST_LOCK();
 	error = ipx_pcballoc(so, &ipxpcb_list, td);
@@ -1410,6 +1411,7 @@
 	int error;
 
 	ipxp = sotoipxpcb(so);
+	KASSERT(ipxp != NULL, ("spx_bind: ipxp == NULL"));
 
 	IPX_LIST_LOCK();
 	IPX_LOCK(ipxp);
@@ -1436,6 +1438,7 @@
 	int error;
 
 	ipxp = sotoipxpcb(so);
+	KASSERT(ipxp != NULL, ("spx_connect: ipxp == NULL"));
 	cb = ipxtospxpcb(ipxp);
 
 	IPX_LIST_LOCK();
@@ -1471,7 +1474,7 @@
 	return (error);
 }
 
-static int
+static void
 spx_detach(so)
 	struct socket *so;
 {
@@ -1479,6 +1482,7 @@
 	struct spxpcb *cb;
 
 	ipxp = sotoipxpcb(so);
+	KASSERT(ipxp != NULL, ("spx_detach: ipxp == NULL"));
 	cb = ipxtospxpcb(ipxp);
 
 	IPX_LIST_LOCK();
@@ -1488,7 +1492,6 @@
 	else
 		spx_close(cb);
 	IPX_LIST_UNLOCK();
-	return (0);
 }
 
 /*
@@ -1504,6 +1507,7 @@
 	struct spxpcb *cb;
 
 	ipxp = sotoipxpcb(so);
+	KASSERT(ipxp != NULL, ("spx_usr_disconnect: ipxp == NULL"));
 	cb = ipxtospxpcb(ipxp);
 
 	IPX_LIST_LOCK();
@@ -1576,6 +1580,7 @@
 	struct spxpcb *cb;
 
 	ipxp = sotoipxpcb(so);
+	KASSERT(ipxp != NULL, ("spx_rcvoob: ipxp == NULL"));
 	cb = ipxtospxpcb(ipxp);
 
 	SOCKBUF_LOCK(&so->so_rcv);
@@ -1606,6 +1611,7 @@
 
 	error = 0;
 	ipxp = sotoipxpcb(so);
+	KASSERT(ipxp != NULL, ("spx_send: ipxp == NULL"));
 	cb = ipxtospxpcb(ipxp);
 
 	IPX_LOCK(ipxp);
@@ -1645,6 +1651,7 @@
 	struct spxpcb *cb;
 
 	ipxp = sotoipxpcb(so);
+	KASSERT(ipxp != NULL, ("spx_shutdown: ipxp == NULL"));
 	cb = ipxtospxpcb(ipxp);
 
 	socantsendmore(so);
@@ -1664,6 +1671,8 @@
 	int error;
 	struct ipxpcb *ipxp;
 
+	KASSERT(so->so_pcb == NULL, ("spx_sp_attach: so_pcb != NULL"));
+
 	error = spx_attach(so, proto, td);
 	if (error == 0) {
 		ipxp = sotoipxpcb(so);
--- netkey/keysock.c	2006/01/21 10:48:01
+++ netkey/keysock.c	2006/02/15 20:30:53
@@ -278,14 +278,11 @@
  * key_abort()
  * derived from net/rtsock.c:rts_abort()
  */
-static int
+static void
 key_abort(struct socket *so)
 {
-	int s, error;
-	s = splnet();
-	error = raw_usrreqs.pru_abort(so);
-	splx(s);
-	return error;
+
+	raw_usrreqs.pru_abort(so);
 }
 
 /*
@@ -298,8 +295,7 @@
 	struct keycb *kp;
 	int s, error;
 
-	if (sotorawcb(so) != 0)
-		return EISCONN;	/* XXX panic? */
+	KASSERT(sotorawcb(so) == NULL, ("key_attach: so_pcb != NULL"));
 	kp = (struct keycb *)malloc(sizeof *kp, M_PCB, M_WAITOK); /* XXX */
 	if (kp == 0)
 		return ENOBUFS;
@@ -369,24 +365,17 @@
  * key_detach()
  * derived from net/rtsock.c:rts_detach()
  */
-static int
+static void
 key_detach(struct socket *so)
 {
 	struct keycb *kp = (struct keycb *)sotorawcb(so);
-	int s, error;
 
-	s = splnet();
-	if (kp != 0) {
-		if (kp->kp_raw.rcb_proto.sp_protocol
-		    == PF_KEY) /* XXX: AF_KEY */
-			key_cb.key_count--;
-		key_cb.any_count--;
-
-		key_freereg(so);
-	}
-	error = raw_usrreqs.pru_detach(so);
-	splx(s);
-	return error;
+	KASSERT(kp != NULL, ("key_detach: kp == NULL"));
+	if (kp->kp_raw.rcb_proto.sp_protocol == PF_KEY) /* XXX: AF_KEY */
+		key_cb.key_count--;
+	key_cb.any_count--;
+	key_freereg(so);
+	raw_usrreqs.pru_detach(so);
 }
 
 /*
--- netnatm/natm.c	2005/08/09 10:22:44
+++ netnatm/natm.c	2006/02/15 20:31:08
@@ -74,7 +74,7 @@
  * user requests
  */
 static int natm_usr_attach(struct socket *, int, d_thread_t *);
-static int natm_usr_detach(struct socket *);
+static void natm_usr_detach(struct socket *);
 static int natm_usr_connect(struct socket *, struct sockaddr *, d_thread_t *);
 static int natm_usr_disconnect(struct socket *);
 static int natm_usr_shutdown(struct socket *);
@@ -83,7 +83,7 @@
 static int natm_usr_peeraddr(struct socket *, struct sockaddr **);
 static int natm_usr_control(struct socket *, u_long, caddr_t,
     struct ifnet *, d_thread_t *);
-static int natm_usr_abort(struct socket *);
+static void natm_usr_abort(struct socket *);
 static int natm_usr_bind(struct socket *, struct sockaddr *, d_thread_t *);
 static int natm_usr_sockaddr(struct socket *, struct sockaddr **);
 
@@ -94,7 +94,6 @@
     int error = 0;
 
     npcb = (struct natmpcb *)so->so_pcb;
-
     KASSERT(npcb == NULL, ("natm_usr_attach: so_pcb != NULL"));
 
     if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
@@ -112,31 +111,17 @@
     return (error);
 }
 
-static int
+static void
 natm_usr_detach(struct socket *so)
 {
     struct natmpcb *npcb;
-    int error = 0;
 
     NATM_LOCK();
     npcb = (struct natmpcb *)so->so_pcb;
-    if (npcb == NULL) {
-	/* XXXRW: Does this case ever actually happen? */
-	error = EINVAL;
-	goto out;
-    }
-
-    /*
-     * we turn on 'drain' *before* we sofree.
-     */
+    KASSERT(npcb != NULL, ("natm_usr_detach: npcb == NULL"));
     npcb_free(npcb, NPCB_DESTROY);	/* drain */
-    ACCEPT_LOCK();
-    SOCK_LOCK(so);
     so->so_pcb = NULL;
-    sotryfree(so);
- out:
     NATM_UNLOCK();
-    return (error);
 }
 
 static int
@@ -151,11 +136,7 @@
 
     NATM_LOCK();
     npcb = (struct natmpcb *)so->so_pcb;
-    if (npcb == NULL) {
-	/* XXXRW: Does this case ever actually happen? */
-	error = EINVAL;
-	goto out;
-    }
+    KASSERT(npcb != NULL, ("natm_usr_connect: npcb == NULL"));
 
     /*
      * validate nam and npcb
@@ -212,18 +193,14 @@
     if (ifp->if_ioctl == NULL || 
 	ifp->if_ioctl(ifp, SIOCATMOPENVCC, (caddr_t)&op) != 0) {
 	IFF_UNLOCKGIANT(ifp);
-	NATM_LOCK();
-	npcb_free(npcb, NPCB_REMOVE);
         error = EIO;
 	goto out;
     }
     IFF_UNLOCKGIANT(ifp);
 
-    NATM_LOCK();
     soisconnected(so);
 
  out:
-    NATM_UNLOCK();
     return (error);
 }
 
@@ -237,11 +214,7 @@
 
     NATM_LOCK();
     npcb = (struct natmpcb *)so->so_pcb;
-    if (npcb == NULL) {
-	/* XXXRW: Does this case ever actually happen? */
-	error = EINVAL;
-	goto out;
-    }
+    KASSERT(npcb != NULL, ("natm_usr_disconnect: npcb == NULL"));
 
     if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
         printf("natm: disconnected check\n");
@@ -263,7 +236,6 @@
     }
     NATM_LOCK();
 
-    npcb_free(npcb, NPCB_REMOVE);
     soisdisconnected(so);
 
  out:
@@ -289,11 +261,7 @@
 
     NATM_LOCK();
     npcb = (struct natmpcb *)so->so_pcb;
-    if (npcb == NULL) {
-	/* XXXRW: Does this case ever actually happen? */
-	error = EINVAL;
-	goto out;
-    }
+    KASSERT(npcb != NULL, ("natm_usr_send: npcb == NULL"));
 
     if (control && control->m_len) {
 	m_freem(control);
@@ -330,11 +298,7 @@
 
     NATM_LOCK();
     npcb = (struct natmpcb *)so->so_pcb;
-    if (npcb == NULL) {
-	/* XXXRW: Does this case ever actually happen? */
-    	NATM_UNLOCK();
-	return (EINVAL);
-    }
+    KASSERT(npcb != NULL, ("natm_usr_peeraddr: npcb == NULL"));
 
     snatm = &ssnatm;
     bzero(snatm, sizeof(*snatm));
@@ -356,13 +320,8 @@
     struct natmpcb *npcb;
     int error;
 
-    /*
-     * XXXRW: Does this case ever actually happen?  And does it even matter
-     * given that npcb is unused?
-     */
     npcb = (struct natmpcb *)so->so_pcb;
-    if (npcb == NULL)
-	return (EINVAL);
+    KASSERT(npcb != NULL, ("natm_usr_control: npcb == NULL"));
 
     if (ifp == NULL || ifp->if_ioctl == NULL)
 	return (EOPNOTSUPP);
@@ -373,10 +332,10 @@
     return (error);
 }
 
-static int
+static void
 natm_usr_abort(struct socket *so)
 {
-    return (natm_usr_shutdown(so));
+    natm_usr_shutdown(so);
 }
 
 static int
--- sys/protosw.h	2005/10/30 19:45:29
+++ sys/protosw.h	2006/02/13 21:54:01
@@ -196,7 +196,7 @@
  */
 struct pr_usrreqs {
 	double	__Break_the_struct_layout_for_now;
-	int	(*pru_abort)(struct socket *so);
+	void	(*pru_abort)(struct socket *so);
 	int	(*pru_accept)(struct socket *so, struct sockaddr **nam);
 	int	(*pru_attach)(struct socket *so, int proto, struct thread *td);
 	int	(*pru_bind)(struct socket *so, struct sockaddr *nam,
@@ -206,7 +206,7 @@
 	int	(*pru_connect2)(struct socket *so1, struct socket *so2);
 	int	(*pru_control)(struct socket *so, u_long cmd, caddr_t data,
 		    struct ifnet *ifp, struct thread *td);
-	int	(*pru_detach)(struct socket *so);
+	void	(*pru_detach)(struct socket *so);
 	int	(*pru_disconnect)(struct socket *so);
 	int	(*pru_listen)(struct socket *so, int backlog,
 		    struct thread *td);
@@ -246,7 +246,7 @@
  * All nonvoid pru_*() functions below return EOPNOTSUPP.
  */
 
-int	pru_abort_notsupp(struct socket *so);
+void	pru_abort_notsupp(struct socket *so);
 int	pru_accept_notsupp(struct socket *so, struct sockaddr **nam);
 int	pru_attach_notsupp(struct socket *so, int proto, struct thread *td);
 int	pru_bind_notsupp(struct socket *so, struct sockaddr *nam,
@@ -256,7 +256,7 @@
 int	pru_connect2_notsupp(struct socket *so1, struct socket *so2);
 int	pru_control_notsupp(struct socket *so, u_long cmd, caddr_t data,
 	    struct ifnet *ifp, struct thread *td);
-int	pru_detach_notsupp(struct socket *so);
+void	pru_detach_notsupp(struct socket *so);
 int	pru_disconnect_notsupp(struct socket *so);
 int	pru_listen_notsupp(struct socket *so, int backlog, struct thread *td);
 int	pru_peeraddr_notsupp(struct socket *so, struct sockaddr **nam);
--- sys/socketvar.h	2006/01/13 11:03:11
+++ sys/socketvar.h	2006/02/19 15:46:04
@@ -208,6 +208,14 @@
 #define	SS_ASYNC		0x0200	/* async i/o notify */
 #define	SS_ISCONFIRMING		0x0400	/* deciding to accept connection req */
 #define	SS_ISDISCONNECTED	0x2000	/* socket disconnected from peer */
+/*
+ * Protocols can mark a socket as SS_PROTOREF to indicate that, following
+ * pru_detach, they still want the socket to persist, and will free it
+ * themselves when they are done.  Protocols should only ever call sofree()
+ * following setting this flag in pru_detach(), and never otherwise, as
+ * sofree() bypasses socket reference counting.
+ */
+#define	SS_PROTOREF		0x4000	/* strong protocol reference present */
 
 /*
  * Socket state bits now stored in the socket buffer state field.
@@ -486,7 +494,7 @@
 void	sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb);
 int	sbwait(struct sockbuf *sb);
 int	sb_lock(struct sockbuf *sb);
-int	soabort(struct socket *so);
+void	soabort(struct socket *so);
 int	soaccept(struct socket *so, struct sockaddr **nam);
 struct	socket *soalloc(int mflags);
 int	socheckuid(struct socket *so, uid_t uid);
