--- //depot/vendor/freebsd/src/sys/compat/linux/linux_socket.c 2006/03/21 22:00:18 +++ //depot/user/rwatson/sockref/src/sys/compat/linux/linux_socket.c 2006/03/29 11:47:32 @@ -662,6 +662,10 @@ * Linux doesn't return EISCONN the first time it occurs, * when on a non-blocking socket. Instead it returns the * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. + * + * XXXRW: Instead of using fgetsock(), check that it is a + * socket and use the file descriptor reference instead of + * creating a new one. */ NET_LOCK_GIANT(); error = fgetsock(td, linux_args.s, &so, &fflag); --- //depot/vendor/freebsd/src/sys/compat/svr4/svr4_stream.c 2005/09/28 07:07:24 +++ //depot/user/rwatson/sockref/src/sys/compat/svr4/svr4_stream.c 2006/03/29 11:47:32 @@ -167,6 +167,10 @@ struct uio *ktruio = NULL; #endif + /* + * XXXRW: Instead of using fgetsock(), just rely on the file + * descriptor reference. + */ if ((error = fgetsock(td, s, &so, NULL)) != 0) return (error); @@ -263,6 +267,10 @@ struct uio *ktruio = NULL; #endif + /* + * XXXRW: Instead of using fgetsock(), just rely on the file + * descriptor reference. + */ if ((error = fgetsock(td, s, &so, NULL)) != 0) return (error); --- //depot/vendor/freebsd/src/sys/kern/kern_descrip.c 2006/03/20 00:17:41 +++ //depot/user/rwatson/sockref/src/sys/kern/kern_descrip.c 2006/03/29 11:45:09 @@ -2090,6 +2090,10 @@ * * We bump the ref count on the returned socket. XXX Also obtain the SX * lock in the future. + * + * XXXRW: fgetsock() and fputsock() are deprecated, as consumers should rely + * on their file descriptor reference to prevent the socket from being + * freed during use. */ int fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp) @@ -2119,8 +2123,10 @@ } /* - * Drop the reference count on the socket and XXX release the SX lock in - * the future. The last reference closes the socket. + * Drop the reference count on the socket and XXX release the SX lock in the + * future. The last reference closes the socket. + * + * XXXRW: fputsock() is deprecated, see comment for fgetsock(). */ void fputsock(struct socket *so) --- //depot/vendor/freebsd/src/sys/kern/uipc_socket.c 2006/03/16 07:07:59 +++ //depot/user/rwatson/sockref/src/sys/kern/uipc_socket.c 2006/03/29 11:38:31 @@ -31,6 +31,63 @@ * @(#)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() and sonewconn(). Socket layer private. + * + * sdealloc() tears down socket layer state for a socket, called only by + * sofree() and sonewconn(). 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() and sonewconn(). Socket layer private. + * + * pru_detach() disassociates protocol layer state from an attached socket, + * and will be called exactly once for sockets in which pru_attach() has + * been successfully called. If pru_attach() returned an error, + * pru_detach() will not be called. Socket layer private. + * + * socreate() creates a socket and attaches protocol state. This is a public + * interface that may be used by socket layer consumers to create new + * sockets. + * + * sonewconn() creates a socket and attaches protocol state. This is a + * public interface that may be used by protocols to create new sockets when + * a new connection is received and will be available for accept() on a + * listen socket. + * + * soclose() destroys a socket after possibly waiting for it to disconnect. + * This is a public interface that socket consumers should use to close and + * release a socket when done with it. + * + * soabort() destroys a socket without waiting for it to disconnect (used + * only for incoming connections that are already partially or fully + * connected). This is used internally by the socket layer when clearing + * listen socket queues (due to overflow or close on the listen socket), but + * is also a public interface protocols may use to abort connections in + * their incomplete listen queues should they no longer be required. Sockets + * placed in completed connection listen queues should not be aborted. + * + * sofree() will free a socket and its protocol state if all references on + * the socket have been released, and is the public interface to attempt to + * free a socket when a reference is removed. This is a socket layer private + * interface. + * + * NOTE: In addition to socreate() and soclose(), which provide a single + * socket reference to the consumer to be managed as required, there are two + * calls to explicitly manage socket references, soref(), and sorele(). + * Currently, these are generally required only when transitioning a socket + * from a listen queue to a file descriptor, in order to prevent garbage + * collection of the socket at an untimely moment. For a number of reasons, + * these interfaces are not preferred, and should be avoided. + * + * XXXRW: The behavior of sockets after soclose() but before the last + * sorele() is poorly defined. We can probably entirely eliminate them with + * a little work, since consumers are managing references anyway. + */ + #include __FBSDID("$FreeBSD: src/sys/kern/uipc_socket.c,v 1.259 2006/03/16 07:03:14 rwatson Exp $"); @@ -250,6 +307,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 +387,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 +409,8 @@ ACCEPT_LOCK_ASSERT(); SOCK_LOCK_ASSERT(so); - if (so->so_pcb != NULL || (so->so_state & SS_NOFDREF) == 0 || - so->so_count != 0 || (so->so_state & SS_PROTOREF)) { + if ((so->so_state & SS_NOFDREF) == 0 || so->so_count != 0 || + (so->so_state & SS_PROTOREF)) { SOCK_UNLOCK(so); ACCEPT_UNLOCK(); return; @@ -388,6 +452,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 +513,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 +531,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")); @@ -484,23 +543,41 @@ } /* - * soabort() must not be called with any socket locks held, as it calls - * 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() allows the socket code or protocol code to detach a socket that + * has been in an incomplete or completed listen queue, but has not yet been + * accepted. + * + * This interface is tricky, because it is called on an unreferenced socket, + * and must be called only by a thread that has actually removed the socket + * from the listen queue it was on, or races with other threads are risked. + * + * This interface will call into the protocol code, so must not be called + * with any socket locks held. Protocols do call it while holding their own + * recursible protocol mutexes, but this is something that should be subject + * to review in the future. + * + * XXXRW: Why do we maintain a distinction between pru_abort() and + * pru_detach()? */ void soabort(so) struct socket *so; { - int error; + + /* + * In as much as is possible, assert that no references to this + * socket are held. This is not quite the same as asserting that the + * current thread is responsible for arranging for no references, but + * is as close as we can get for now. + */ + KASSERT(so->so_count == 0, ("soabort: so_count")); + KASSERT(!(so->so_state & SS_PROTOREF), ("soabort: SS_PROTOREF")); + KASSERT(so->so_state & SS_NOFDREF, ("soabort: !SS_NOFDREF")); - 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 */ - } + (*so->so_proto->pr_usrreqs->pru_abort)(so); + ACCEPT_LOCK(); + SOCK_LOCK(so); + sofree(so); } int @@ -1525,7 +1602,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); @@ -1569,7 +1646,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); --- //depot/vendor/freebsd/src/sys/kern/uipc_socket2.c 2006/03/26 22:46:11 +++ //depot/user/rwatson/sockref/src/sys/kern/uipc_socket2.c 2006/03/27 01:02:42 @@ -1292,10 +1292,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 @@ -1335,10 +1335,10 @@ return EOPNOTSUPP; } -int +void pru_detach_notsupp(struct socket *so) { - return EOPNOTSUPP; + } int --- //depot/vendor/freebsd/src/sys/kern/uipc_syscalls.c 2006/03/27 04:25:16 +++ //depot/user/rwatson/sockref/src/sys/kern/uipc_syscalls.c 2006/03/29 11:49:48 @@ -283,6 +283,9 @@ /* * accept1() * MPSAFE + * + * XXXRW: Use getsock() instead of fgetsock() here to avoid additional + * mutex operations due to soref()/sorele(). */ static int accept1(td, uap, compat) --- //depot/vendor/freebsd/src/sys/kern/uipc_usrreq.c 2006/03/17 13:58:13 +++ //depot/user/rwatson/sockref/src/sys/kern/uipc_usrreq.c 2006/03/17 18:28:51 @@ -139,7 +139,7 @@ static int unp_listen(struct socket *, struct unpcb *, int, struct thread *); -static int +static void uipc_abort(struct socket *so) { struct unpcb *unp; @@ -150,10 +150,6 @@ unp_drop(unp, ECONNABORTED); unp_detach(unp); UNP_UNLOCK_ASSERT(); - ACCEPT_LOCK(); - SOCK_LOCK(so); - sotryfree(so); - return (0); } static int @@ -232,7 +228,7 @@ /* control is EOPNOTSUPP */ -static int +static void uipc_detach(struct socket *so) { struct unpcb *unp; @@ -242,7 +238,6 @@ UNP_LOCK(); unp_detach(unp); UNP_UNLOCK_ASSERT(); - return (0); } static int --- //depot/vendor/freebsd/src/sys/net/raw_cb.c 2005/01/24 23:00:55 +++ //depot/user/rwatson/sockref/src/sys/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); --- //depot/vendor/freebsd/src/sys/net/raw_usrreq.c 2005/01/07 01:52:23 +++ //depot/user/rwatson/sockref/src/sys/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); --- //depot/vendor/freebsd/src/sys/net/rtsock.c 2006/03/15 19:41:44 +++ //depot/user/rwatson/sockref/src/sys/net/rtsock.c 2006/03/16 21:44:47 @@ -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 --- //depot/vendor/freebsd/src/sys/netatalk/ddp_usrreq.c 2006/03/25 18:55:33 +++ //depot/user/rwatson/sockref/src/sys/netatalk/ddp_usrreq.c 2006/03/26 01:39:59 @@ -72,7 +72,7 @@ return (error); } -static int +static void ddp_detach(struct socket *so) { struct ddpcb *ddp; @@ -84,7 +84,6 @@ DDP_LOCK(ddp); at_pcbdetach(so, ddp); DDP_LIST_XUNLOCK(); - return (0); } static int @@ -95,6 +94,7 @@ ddp = sotoddpcb(so); KASSERT(ddp != NULL, ("ddp_bind: ddp == NULL")); + DDP_LIST_XLOCK(); DDP_LOCK(ddp); error = at_pcbsetaddr(ddp, nam, td); @@ -200,7 +200,7 @@ return (error); } -static int +static void ddp_abort(struct socket *so) { struct ddpcb *ddp; @@ -211,8 +211,6 @@ DDP_LOCK(ddp); at_pcbdetach(so, ddp); DDP_LIST_XUNLOCK(); - /* XXXRW: Should be calling sotryfree() here? */ - return (0); } void --- //depot/vendor/freebsd/src/sys/netatm/atm_aal5.c 2005/10/30 19:45:29 +++ //depot/user/rwatson/sockref/src/sys/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(); } --- //depot/vendor/freebsd/src/sys/netatm/atm_proto.c 2005/11/09 13:31:29 +++ //depot/user/rwatson/sockref/src/sys/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; +{ + +} --- //depot/vendor/freebsd/src/sys/netatm/atm_socket.c 2005/10/30 19:45:29 +++ //depot/user/rwatson/sockref/src/sys/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); } --- //depot/vendor/freebsd/src/sys/netatm/atm_usrreq.c 2005/06/10 16:51:34 +++ //depot/user/rwatson/sockref/src/sys/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, --- //depot/vendor/freebsd/src/sys/netatm/atm_var.h 2005/10/30 19:45:29 +++ //depot/user/rwatson/sockref/src/sys/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 *, --- //depot/vendor/freebsd/src/sys/netgraph/bluetooth/include/ng_btsocket_hci_raw.h 2005/01/07 01:52:23 +++ //depot/user/rwatson/sockref/src/sys/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 *, --- //depot/vendor/freebsd/src/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h 2005/10/30 19:45:29 +++ //depot/user/rwatson/sockref/src/sys/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 **); --- //depot/vendor/freebsd/src/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h 2005/10/30 19:45:29 +++ //depot/user/rwatson/sockref/src/sys/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 **); --- //depot/vendor/freebsd/src/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c 2005/07/28 17:45:20 +++ //depot/user/rwatson/sockref/src/sys/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 */ /* --- //depot/vendor/freebsd/src/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c 2005/10/30 19:45:29 +++ //depot/user/rwatson/sockref/src/sys/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 */ /* --- //depot/vendor/freebsd/src/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c 2005/08/23 00:55:32 +++ //depot/user/rwatson/sockref/src/sys/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 */ /* --- //depot/vendor/freebsd/src/sys/netgraph/bluetooth/socket/ng_btsocket_rfcomm.c 2005/10/30 19:45:29 +++ //depot/user/rwatson/sockref/src/sys/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 */ /* --- //depot/vendor/freebsd/src/sys/netgraph/ng_socket.c 2005/11/09 13:31:29 +++ //depot/user/rwatson/sockref/src/sys/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 --- //depot/vendor/freebsd/src/sys/netinet/in_pcb.c 2006/02/16 15:50:16 +++ //depot/user/rwatson/sockref/src/sys/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); --- //depot/vendor/freebsd/src/sys/netinet/in_pcb.h 2006/03/26 11:33:20 +++ //depot/user/rwatson/sockref/src/sys/netinet/in_pcb.h 2006/03/26 11:48:04 @@ -352,6 +352,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 *, --- //depot/vendor/freebsd/src/sys/netinet/ip_divert.c 2005/11/09 13:31:29 +++ //depot/user/rwatson/sockref/src/sys/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; --- //depot/vendor/freebsd/src/sys/netinet/raw_ip.c 2005/12/14 22:30:18 +++ //depot/user/rwatson/sockref/src/sys/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 --- //depot/vendor/freebsd/src/sys/netinet/tcp_input.c 2006/03/26 01:35:16 +++ //depot/user/rwatson/sockref/src/sys/netinet/tcp_input.c 2006/03/26 01:39:59 @@ -3200,7 +3200,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); } --- //depot/vendor/freebsd/src/sys/netinet/tcp_subr.c 2006/02/16 19:40:18 +++ //depot/user/rwatson/sockref/src/sys/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); --- //depot/vendor/freebsd/src/sys/netinet/tcp_timer.c 2006/03/26 01:35:16 +++ //depot/user/rwatson/sockref/src/sys/netinet/tcp_timer.c 2006/03/26 01:39:59 @@ -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); @@ -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); @@ -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,7 +449,7 @@ out: #ifdef TCPDEBUG - if (tp != NULL && 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 @@ -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); --- //depot/vendor/freebsd/src/sys/netinet/tcp_usrreq.c 2005/12/14 22:30:18 +++ //depot/user/rwatson/sockref/src/sys/netinet/tcp_usrreq.c 2006/03/18 12:34:13 @@ -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 @@ -113,18 +111,15 @@ static int tcp_usr_attach(struct socket *so, int proto, struct thread *td) { + struct inpcb *inp; + struct tcpcb *tp = NULL; 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) @@ -148,69 +143,99 @@ * 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); + KASSERT(inp->inp_socket != NULL, + ("tcp_usr_detach: inp_socket == NULL")); + + TCPDEBUG1(); tp = intotcpcb(inp); - TCPDEBUG1(); - tp = tcp_disconnect(tp); + 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); + } + } + tp = NULL; TCPDEBUG2(PRU_DETACH); - if (tp) - 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. */ @@ -219,9 +244,8 @@ { int error = 0; struct inpcb *inp; - struct tcpcb *tp; + struct tcpcb *tp = NULL; struct sockaddr_in *sinp; - const int inirw = INI_WRITE; sinp = (struct sockaddr_in *)nam; if (nam->sa_len != sizeof (*sinp)) @@ -234,11 +258,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 @@ -247,9 +284,8 @@ { int error = 0; struct inpcb *inp; - struct tcpcb *tp; + struct tcpcb *tp = NULL; struct sockaddr_in6 *sin6p; - const int inirw = INI_WRITE; sin6p = (struct sockaddr_in6 *)nam; if (nam->sa_len != sizeof (*sin6p)) @@ -262,7 +298,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 +326,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 */ @@ -294,10 +342,19 @@ { int error = 0; struct inpcb *inp; - struct tcpcb *tp; - const int inirw = INI_WRITE; + struct tcpcb *tp = NULL; - 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 +364,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 @@ -316,10 +378,19 @@ { int error = 0; struct inpcb *inp; - struct tcpcb *tp; - const int inirw = INI_WRITE; + struct tcpcb *tp = NULL; - 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 +404,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 */ @@ -349,9 +425,8 @@ { int error = 0; struct inpcb *inp; - struct tcpcb *tp; + struct tcpcb *tp = NULL; struct sockaddr_in *sinp; - const int inirw = INI_WRITE; sinp = (struct sockaddr_in *)nam; if (nam->sa_len != sizeof (*sinp)) @@ -365,11 +440,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 @@ -378,9 +467,10 @@ { int error = 0; struct inpcb *inp; - struct tcpcb *tp; + struct tcpcb *tp = NULL; struct sockaddr_in6 *sin6p; - const int inirw = INI_WRITE; + + TCPDEBUG0; sin6p = (struct sockaddr_in6 *)nam; if (nam->sa_len != sizeof (*sin6p)) @@ -392,7 +482,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 +514,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 +537,27 @@ static int tcp_usr_disconnect(struct socket *so) { + struct inpcb *inp; + struct tcpcb *tp = NULL; int error = 0; - struct inpcb *inp; - struct tcpcb *tp; - const int inirw = INI_WRITE; - 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 +580,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 +598,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 +624,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 +648,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); @@ -574,15 +690,29 @@ { int error = 0; struct inpcb *inp; - struct tcpcb *tp; - const int inirw = INI_WRITE; + struct tcpcb *tp = NULL; - 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 +721,26 @@ static int tcp_usr_rcvd(struct socket *so, int flags) { + struct inpcb *inp; + struct tcpcb *tp = NULL; 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_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); } /* @@ -614,37 +756,33 @@ { int error = 0; struct inpcb *inp; - struct tcpcb *tp; - int unlocked = 0; + struct tcpcb *tp = NULL; + 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 +808,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 +820,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 +841,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 +868,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 +879,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 +893,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 +902,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 } /* @@ -776,10 +946,18 @@ { int error = 0; struct inpcb *inp; - struct tcpcb *tp; - const int inirw = INI_READ; + struct tcpcb *tp = NULL; - 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 +973,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 +1042,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 +1096,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 +1208,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 +1221,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 +1339,7 @@ } break; } +out: INP_UNLOCK(inp); return (error); } @@ -1204,19 +1392,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 +1419,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 +1429,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 +1459,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 +1473,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 +1501,4 @@ callout_reset(tp->tt_2msl, tcp_maxidle, tcp_timer_2msl, tp); } - return (tp); } --- //depot/vendor/freebsd/src/sys/netinet/tcp_var.h 2006/02/28 23:10:19 +++ //depot/user/rwatson/sockref/src/sys/netinet/tcp_var.h 2006/03/12 21:11:41 @@ -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 * --- //depot/vendor/freebsd/src/sys/netinet/udp_usrreq.c 2006/01/24 09:11:50 +++ //depot/user/rwatson/sockref/src/sys/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; --- //depot/vendor/freebsd/src/sys/netinet6/in6_pcb.c 2006/03/19 11:54:04 +++ //depot/user/rwatson/sockref/src/sys/netinet6/in6_pcb.c 2006/03/25 14:19:05 @@ -422,17 +422,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); @@ -442,14 +448,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 */ --- //depot/vendor/freebsd/src/sys/netinet6/in6_pcb.h 2005/01/07 02:32:16 +++ //depot/user/rwatson/sockref/src/sys/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 * --- //depot/vendor/freebsd/src/sys/netinet6/raw_ip6.c 2005/10/19 01:25:25 +++ //depot/user/rwatson/sockref/src/sys/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. */ --- //depot/vendor/freebsd/src/sys/netinet6/udp6_usrreq.c 2006/02/04 05:50:26 +++ //depot/user/rwatson/sockref/src/sys/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) { --- //depot/vendor/freebsd/src/sys/netipsec/keysock.c 2006/01/21 10:48:01 +++ //depot/user/rwatson/sockref/src/sys/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); } /* --- //depot/vendor/freebsd/src/sys/netipx/ipx_usrreq.c 2006/03/25 17:30:21 +++ //depot/user/rwatson/sockref/src/sys/netipx/ipx_usrreq.c 2006/03/25 18:49:02 @@ -75,12 +75,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; { @@ -441,10 +441,6 @@ ipx_pcbfree(ipxp); IPX_LIST_UNLOCK(); soisdisconnected(so); - ACCEPT_LOCK(); - SOCK_LOCK(so); - sotryfree(so); - return (0); } static int @@ -509,7 +505,7 @@ return (error); } -static int +static void ipx_detach(so) struct socket *so; { @@ -521,7 +517,6 @@ ipx_pcbdetach(ipxp); ipx_pcbfree(ipxp); IPX_LIST_UNLOCK(); - return (0); } static int --- //depot/vendor/freebsd/src/sys/netipx/spx_usrreq.c 2006/03/27 00:50:30 +++ //depot/user/rwatson/sockref/src/sys/netipx/spx_usrreq.c 2006/03/27 01:02:42 @@ -97,13 +97,13 @@ static void 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 void spx_pcbdetach(struct ipxpcb *ipxp); static int spx_usr_disconnect(struct socket *so); static int spx_listen(struct socket *so, int backlog, struct thread *td); @@ -366,6 +366,9 @@ dropwithreset: IPX_LOCK_ASSERT(ipxp); + /* + * XXXRW: This trace code was originally below the dropsocket block. + */ if (cb == NULL || (cb->s_ipxpcb->ipxp_socket->so_options & SO_DEBUG || traceallspxs)) spx_trace(SA_DROP, (u_char)ostate, cb, &spx_savesi, 0); @@ -1305,7 +1308,7 @@ return (error); } -static int +static void spx_usr_abort(struct socket *so) { struct ipxpcb *ipxp; @@ -1324,10 +1327,6 @@ ipx_pcbdetach(ipxp); ipx_pcbfree(ipxp); IPX_LIST_UNLOCK(); - ACCEPT_LOCK(); - SOCK_LOCK(so); - sotryfree(so); - return (0); } /* @@ -1516,7 +1515,7 @@ return (error); } -static int +static void spx_detach(struct socket *so) { struct ipxpcb *ipxp; @@ -1538,7 +1537,6 @@ ipx_pcbdetach(ipxp); ipx_pcbfree(ipxp); IPX_LIST_UNLOCK(); - return (0); } /* --- //depot/vendor/freebsd/src/sys/netkey/keysock.c 2006/01/21 10:48:01 +++ //depot/user/rwatson/sockref/src/sys/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); } /* --- //depot/vendor/freebsd/src/sys/netnatm/natm.c 2006/03/17 18:30:16 +++ //depot/user/rwatson/sockref/src/sys/netnatm/natm.c 2006/03/17 20:55:12 @@ -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 **); @@ -111,7 +111,7 @@ return (error); } -static int +static void natm_usr_detach(struct socket *so) { struct natmpcb *npcb; @@ -122,7 +122,6 @@ npcb_free(npcb, NPCB_DESTROY); /* drain */ so->so_pcb = NULL; NATM_UNLOCK(); - return (0); } static int @@ -333,14 +332,10 @@ return (error); } -static int +static void natm_usr_abort(struct socket *so) { natm_usr_shutdown(so); - ACCEPT_LOCK(); - SOCK_LOCK(so); - sotryfree(so); - return (0); } static int --- //depot/vendor/freebsd/src/sys/sys/protosw.h 2006/03/15 20:45:23 +++ //depot/user/rwatson/sockref/src/sys/sys/protosw.h 2006/03/16 21:44:47 @@ -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); --- //depot/vendor/freebsd/src/sys/sys/socketvar.h 2006/03/16 07:07:59 +++ //depot/user/rwatson/sockref/src/sys/sys/socketvar.h 2006/03/25 19:01:21 @@ -208,6 +208,13 @@ #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 */ /*