--- //depot/vendor/freebsd/src/sys/netinet/tcp_usrreq.c 2006/04/03 12:47:07 +++ //depot/user/rwatson/sockref/src/sys/netinet/tcp_usrreq.c 2006/04/23 17:51:27 @@ -139,46 +139,27 @@ } /* - * pru_detach() detaches the TCP protocol from the socket. - * If the protocol state is non-embryonic, then can't - * do this directly: have to initiate a pru_disconnect(), - * which may finish later; embryonic TCB's can just - * be discarded here. + * tcp_detach() releases any protocol state that can be reasonably released + * when a socket shutdown is requested, and is a shared code path for + * tcp_usr_detach() and tcp_usr_abort(), the two socket close entry points. + * + * Accepts pcbinfo, inpcb locked, will unlock the inpcb (if needed) on + * return. */ static void -tcp_usr_detach(struct socket *so) +tcp_detach(struct socket *so, struct inpcb *inp) { - 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_LOCK(inp); - KASSERT(inp->inp_socket != NULL, - ("tcp_usr_detach: inp_socket == NULL")); - TCPDEBUG1(); + INP_INFO_WLOCK_ASSERT(&tcbinfo); + INP_LOCK_ASSERT(inp); - /* - * First, if we still have full TCP state, and we're not dropped, - * initiate a disconnect. - */ - if (!(inp->inp_vflag & INP_TIMEWAIT) && - !(inp->inp_vflag & INP_DROPPED)) { - tp = intotcpcb(inp); - tcp_disconnect(tp); - } + KASSERT(so->so_pcb == inp, ("tcp_detach: so_pcb != inp")); + KASSERT(inp->inp_socket == so, ("tcp_detach: inp_socket != so")); - /* - * Second, release any protocol state that we can reasonably release. - * Note that the call to tcp_disconnect() may actually have changed - * the TCP state, so we have to re-evaluate INP_TIMEWAIT and - * INP_DROPPED. - */ if (inp->inp_vflag & INP_TIMEWAIT) { if (inp->inp_vflag & INP_DROPPED) { /* @@ -248,6 +229,40 @@ INP_UNLOCK(inp); } } +} + +/* + * pru_detach() detaches the TCP protocol from the socket. + * If the protocol state is non-embryonic, then can't + * do this directly: have to initiate a pru_disconnect(), + * which may finish later; embryonic TCB's can just + * be discarded here. + */ +static void +tcp_usr_detach(struct socket *so) +{ + struct inpcb *inp; + struct tcpcb *tp; + TCPDEBUG0; + + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("tcp_usr_detach: inp == NULL")); + INP_INFO_WLOCK(&tcbinfo); + INP_LOCK(inp); + KASSERT(inp->inp_socket != NULL, + ("tcp_usr_detach: inp_socket == NULL")); + TCPDEBUG1(); + + /* + * First, if we still have full TCP state, and we're not dropped, + * initiate a disconnect. + */ + if (!(inp->inp_vflag & INP_TIMEWAIT) && + !(inp->inp_vflag & INP_DROPPED)) { + tp = intotcpcb(inp); + tcp_disconnect(tp); + } + tcp_detach(so, inp); tp = NULL; TCPDEBUG2(PRU_DETACH); INP_INFO_WUNLOCK(&tcbinfo); @@ -916,41 +931,38 @@ /* * Abort the TCP. + * + * First, drop the connection. Then collect state if possible. */ static void tcp_usr_abort(struct socket *so) { -#if 0 struct inpcb *inp; struct tcpcb *tp; -#endif + TCPDEBUG0; - /* - * 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); + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("tcp_usr_abort: inp == NULL")); -#if 0 - TCPDEBUG0; INP_INFO_WLOCK(&tcbinfo); - inp = sotoinpcb(so); INP_LOCK(inp); + KASSERT(inp->inp_socket != NULL, + ("tcp_usr_abort: inp_socket == NULL")); + TCPDEBUG1(); + /* - * Do we need to handle timewait here? Aborted connections should - * never generate a FIN? + * First, if we still have full TCP state, and we're not dropped, + * drop. */ - KASSERT((inp->inp_vflag & INP_TIMEWAIT) == 0, - ("tcp_usr_abort: timewait")); - tp = intotcpcb(inp); - TCPDEBUG1(); - tp = tcp_drop(tp, ECONNABORTED); - TCPDEBUG2(PRU_ABORT); - if (tp != NULL) - INP_UNLOCK(inp); + if (!(inp->inp_vflag & INP_TIMEWAIT) && + !(inp->inp_vflag & INP_DROPPED)) { + tp = intotcpcb(inp); + tcp_drop(tp, ECONNABORTED); + } + tcp_detach(so, inp); + tp = NULL; + TCPDEBUG2(PRU_DETACH); INP_INFO_WUNLOCK(&tcbinfo); -#endif } /*