--- //depot/vendor/freebsd/src/sys/kern/uipc_socket.c 2006/02/12 15:00:33 +++ //depot/user/rwatson/sockref/src/sys/kern/uipc_socket.c 2006/02/21 23:55:13 @@ -1,6 +1,6 @@ /*- * Copyright (c) 2004 The FreeBSD Foundation - * Copyright (c) 2004-2005 Robert N. M. Watson + * Copyright (c) 2004-2006 Robert N. M. Watson * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * @@ -31,6 +31,40 @@ * @(#)uipc_socket.c 8.3 (Berkeley) 4/15/94 */ +/* + * Comments on the socket life cycle: + * + * soalloc() sets of socket layer state for a socket, called only by + * socreate(). Socket layer private. + * + * pru_attach() associates protocol layer state with an allocated socket; + * called only once, may fail, aborting socket allocation. This is called + * from socreate(). + * + * pru_detach() disassociates protocol layer state with an attached socket; + * this will be called only once, to notify the protocol that the socket + * layer is done with the socket. However, if the protocol has acquired a + * strong socket reference by setting SS_PROTOREF, the socket layer will not + * allow sofree() to release the socket. Once a pru_detach() has been + * received while holding a strong reference, the protocol is responsible for + * later calling sofree() to release the socket. This is useful for + * protocols in which need for socket buffer contents may continue after + * socket close, in which case the protocol can take ownership of the socket + * until it is ready to release it. + * + * sodealloc() tears down socket layer state for a socket, called only by + * sofree(). Socket layer private. + * + * socreate() creates a socket and attaches protocol state. + * sonewconn() creates a socket and attaches protocol state. + * sofree() destroys a socket and detaches protocol layer state. + * + * soclose() destroys a socket after waiting for it to disconnect. + * soabort() destroys a socket without waiting for it to disconnect (used + * only for incoming connections that are already connected). Calls + * pru_detach(). + */ + #include __FBSDID("$FreeBSD: src/sys/kern/uipc_socket.c,v 1.257 2006/02/12 15:00:27 rwatson Exp $"); @@ -250,6 +284,8 @@ { KASSERT(so->so_count == 0, ("sodealloc(): so_count %d", so->so_count)); + KASSERT(so->so_pcb == NULL, ("sodealloc(): so_pcb != NULL")); + mtx_lock(&so_global_mtx); so->so_gencnt = ++so_gencnt; mtx_unlock(&so_global_mtx); @@ -328,13 +364,18 @@ /* * Attempt to free a socket. This should really be sotryfree(). * - * We free the socket if the protocol is no longer interested in the socket, - * there's no file descriptor reference, and the refcount is 0. While the - * calling macro sotryfree() tests the refcount, sofree() has to test it - * again as it's possible to race with an accept()ing thread if the socket is - * in an listen queue of a listen socket, as being in the listen queue - * doesn't elevate the reference count. sofree() acquires the accept mutex - * early for this test in order to avoid that race. + * sofree() will succeed if: + * + * - There are no outstanding file descriptor references or related consumers + * (so_count == 0). + * + * - The socket has been closed by user space, if ever open (SS_NOFDREF). + * + * - The protocol does not have an outstanding strong reference on the socket + * (SS_PROTOREF). + * + * Otherwise, it will quietly abort so that a future call to sofree(), when + * conditions are right, can succeed. */ void sofree(so) @@ -345,8 +386,8 @@ ACCEPT_LOCK_ASSERT(); SOCK_LOCK_ASSERT(so); - if (so->so_pcb != NULL || (so->so_state & SS_NOFDREF) == 0 || - so->so_count != 0) { + if ((so->so_state & SS_NOFDREF) == 0 || so->so_count != 0 || + (so->so_state & SS_PROTOREF)) { SOCK_UNLOCK(so); ACCEPT_UNLOCK(); return; @@ -388,6 +429,7 @@ so->so_qstate & SQ_COMP, so->so_qstate & SQ_INCOMP)); SOCK_UNLOCK(so); ACCEPT_UNLOCK(); + SOCKBUF_LOCK(&so->so_snd); so->so_snd.sb_flags |= SB_NOINTR; (void)sblock(&so->so_snd, M_WAITOK); @@ -448,8 +490,6 @@ } ACCEPT_UNLOCK(); } - if (so->so_pcb == NULL) - goto discard; if (so->so_state & SS_ISCONNECTED) { if ((so->so_state & SS_ISDISCONNECTING) == 0) { error = sodisconnect(so); @@ -468,13 +508,9 @@ } } } + drop: - if (so->so_pcb != NULL) { - int error2 = (*so->so_proto->pr_usrreqs->pru_detach)(so); - if (error == 0) - error = error2; - } -discard: + (*so->so_proto->pr_usrreqs->pru_detach)(so); ACCEPT_LOCK(); SOCK_LOCK(so); KASSERT((so->so_state & SS_NOFDREF) == 0, ("soclose: NOFDREF")); @@ -488,21 +524,26 @@ * into the protocol, which will call back into the socket code causing * it to acquire additional socket locks that may cause recursion or lock * order reversals. + * + * soabort() is used to abort a received but unaccepted connection, as + * it doesn't have any valid references yet. + * + * XXXRW: Why do we maintain a distinction between pru_abort() and + * pru_detach()? + * + * XXXRW: Right now we don't attempt to handle SS_PROTOREF here. */ -int +void soabort(so) struct socket *so; { - int error; + + KASSERT(so->so_count == 0, ("soabort: so_count")); - error = (*so->so_proto->pr_usrreqs->pru_abort)(so); - if (error) { - ACCEPT_LOCK(); - SOCK_LOCK(so); - sotryfree(so); /* note: does not decrement the ref count */ - return (error); - } - return (0); + (*so->so_proto->pr_usrreqs->pru_abort)(so); + ACCEPT_LOCK(); + SOCK_LOCK(so); + sofree(so); } int @@ -1527,7 +1568,7 @@ * Notify the protocol that some data has been * drained before blocking. */ - if (pr->pr_flags & PR_WANTRCVD && so->so_pcb != NULL) { + if (pr->pr_flags & PR_WANTRCVD) { SOCKBUF_UNLOCK(&so->so_rcv); (*pr->pr_usrreqs->pru_rcvd)(so, flags); SOCKBUF_LOCK(&so->so_rcv); @@ -1571,7 +1612,7 @@ * ACK will be generated on return to TCP. */ if (!(flags & MSG_SOCALLBCK) && - (pr->pr_flags & PR_WANTRCVD) && so->so_pcb) { + (pr->pr_flags & PR_WANTRCVD)) { SOCKBUF_UNLOCK(&so->so_rcv); (*pr->pr_usrreqs->pru_rcvd)(so, flags); SOCKBUF_LOCK(&so->so_rcv); --- //depot/vendor/freebsd/src/sys/kern/uipc_socket2.c 2005/11/22 01:56:03 +++ //depot/user/rwatson/sockref/src/sys/kern/uipc_socket2.c 2006/02/13 21:54:01 @@ -1282,10 +1282,10 @@ * Some routines that return EOPNOTSUPP for entry points that are not * supported by a protocol. Fill in as needed. */ -int +void pru_abort_notsupp(struct socket *so) { - return EOPNOTSUPP; + } int @@ -1325,10 +1325,10 @@ return EOPNOTSUPP; } -int +void pru_detach_notsupp(struct socket *so) { - return EOPNOTSUPP; + } int --- //depot/vendor/freebsd/src/sys/kern/uipc_usrreq.c 2006/01/30 08:24:26 +++ //depot/user/rwatson/sockref/src/sys/kern/uipc_usrreq.c 2006/02/13 21:54:59 @@ -1,7 +1,7 @@ /*- * Copyright (c) 1982, 1986, 1989, 1991, 1993 * The Regents of the University of California. - * Copyright 2004-2005 Robert N. M. Watson + * Copyright 2004-2006 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -139,24 +139,17 @@ static int unp_listen(struct socket *, struct unpcb *, int, struct thread *); -static int +static void uipc_abort(struct socket *so) { struct unpcb *unp; + unp = sotounpcb(so); + KASSERT(unp != NULL, ("uipc_abort: unp == NULL")); UNP_LOCK(); - unp = sotounpcb(so); - if (unp == NULL) { - UNP_UNLOCK(); - return (EINVAL); - } unp_drop(unp, ECONNABORTED); unp_detach(unp); UNP_UNLOCK_ASSERT(); - ACCEPT_LOCK(); - SOCK_LOCK(so); - sotryfree(so); - return (0); } static int @@ -170,15 +163,10 @@ * if it was bound and we are still connected * (our peer may have closed already!). */ + unp = sotounpcb(so); + KASSERT(unp != NULL, ("uipc_accept: unp == NULL")); *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); UNP_LOCK(); - unp = sotounpcb(so); - if (unp == NULL) { - UNP_UNLOCK(); - free(*nam, M_SONAME); - *nam = NULL; - return (EINVAL); - } if (unp->unp_conn != NULL && unp->unp_conn->unp_addr != NULL) sa = (struct sockaddr *) unp->unp_conn->unp_addr; else @@ -191,10 +179,7 @@ static int uipc_attach(struct socket *so, int proto, struct thread *td) { - struct unpcb *unp = sotounpcb(so); - if (unp != NULL) - return (EISCONN); return (unp_attach(so)); } @@ -204,12 +189,9 @@ struct unpcb *unp; int error; + unp = sotounpcb(so); + KASSERT(unp != NULL, ("uipc_bind: unp == NULL")); UNP_LOCK(); - unp = sotounpcb(so); - if (unp == NULL) { - UNP_UNLOCK(); - return (EINVAL); - } error = unp_bind(unp, nam, td); UNP_UNLOCK(); return (error); @@ -223,12 +205,9 @@ KASSERT(td == curthread, ("uipc_connect: td != curthread")); + unp = sotounpcb(so); + KASSERT(unp != NULL, ("uipc_connect: unp == NULL")); UNP_LOCK(); - unp = sotounpcb(so); - if (unp == NULL) { - UNP_UNLOCK(); - return (EINVAL); - } error = unp_connect(so, nam, td); UNP_UNLOCK(); return (error); @@ -240,12 +219,9 @@ struct unpcb *unp; int error; + unp = sotounpcb(so1); + KASSERT(unp != NULL, ("uipc_connect2: unp == NULL")); UNP_LOCK(); - unp = sotounpcb(so1); - if (unp == NULL) { - UNP_UNLOCK(); - return (EINVAL); - } error = unp_connect2(so1, so2, PRU_CONNECT2); UNP_UNLOCK(); return (error); @@ -253,20 +229,16 @@ /* control is EOPNOTSUPP */ -static int +static void uipc_detach(struct socket *so) { struct unpcb *unp; + unp = sotounpcb(so); + KASSERT(unp != NULL, ("uipc_detach: unp == NULL")); UNP_LOCK(); - unp = sotounpcb(so); - if (unp == NULL) { - UNP_UNLOCK(); - return (EINVAL); - } unp_detach(unp); UNP_UNLOCK_ASSERT(); - return (0); } static int @@ -274,12 +246,9 @@ { struct unpcb *unp; + unp = sotounpcb(so); + KASSERT(unp != NULL, ("uipc_disconnect: unp == NULL")); UNP_LOCK(); - unp = sotounpcb(so); - if (unp == NULL) { - UNP_UNLOCK(); - return (EINVAL); - } unp_disconnect(unp); UNP_UNLOCK(); return (0); @@ -291,9 +260,10 @@ struct unpcb *unp; int error; + unp = sotounpcb(so); + KASSERT(unp != NULL, ("uipc_listen: unp == NULL")); UNP_LOCK(); - unp = sotounpcb(so); - if (unp == NULL || unp->unp_vnode == NULL) { + if (unp->unp_vnode == NULL) { UNP_UNLOCK(); return (EINVAL); } @@ -308,15 +278,10 @@ struct unpcb *unp; const struct sockaddr *sa; + unp = sotounpcb(so); + KASSERT(unp != NULL, ("uipc_peeraddr: unp == NULL")); *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); UNP_LOCK(); - unp = sotounpcb(so); - if (unp == NULL) { - UNP_UNLOCK(); - free(*nam, M_SONAME); - *nam = NULL; - return (EINVAL); - } if (unp->unp_conn != NULL && unp->unp_conn->unp_addr!= NULL) sa = (struct sockaddr *) unp->unp_conn->unp_addr; else { @@ -339,12 +304,9 @@ struct socket *so2; u_long newhiwat; + unp = sotounpcb(so); + KASSERT(unp != NULL, ("uipc_rcvd: unp == NULL")); UNP_LOCK(); - unp = sotounpcb(so); - if (unp == NULL) { - UNP_UNLOCK(); - return (EINVAL); - } switch (so->so_type) { case SOCK_DGRAM: panic("uipc_rcvd DGRAM?"); @@ -390,10 +352,7 @@ u_long newhiwat; unp = sotounpcb(so); - if (unp == NULL) { - error = EINVAL; - goto release; - } + KASSERT(unp != NULL, ("uipc_send: unp == NULL")); if (flags & PRUS_OOB) { error = EOPNOTSUPP; goto release; @@ -403,13 +362,6 @@ goto release; UNP_LOCK(); - unp = sotounpcb(so); - if (unp == NULL) { - UNP_UNLOCK(); - error = EINVAL; - goto dispose_release; - } - switch (so->so_type) { case SOCK_DGRAM: { @@ -523,7 +475,6 @@ } UNP_UNLOCK(); -dispose_release: if (control != NULL && error != 0) unp_dispose(control); @@ -541,12 +492,9 @@ struct unpcb *unp; struct socket *so2; + unp = sotounpcb(so); + KASSERT(unp != NULL, ("uipc_sense: unp == NULL")); UNP_LOCK(); - unp = sotounpcb(so); - if (unp == NULL) { - UNP_UNLOCK(); - return (EINVAL); - } sb->st_blksize = so->so_snd.sb_hiwat; if (so->so_type == SOCK_STREAM && unp->unp_conn != NULL) { so2 = unp->unp_conn->unp_socket; @@ -565,12 +513,9 @@ { struct unpcb *unp; + unp = sotounpcb(so); + KASSERT(unp != NULL, ("uipc_shutdown: unp == NULL")); UNP_LOCK(); - unp = sotounpcb(so); - if (unp == NULL) { - UNP_UNLOCK(); - return (EINVAL); - } socantsendmore(so); unp_shutdown(unp); UNP_UNLOCK(); @@ -583,15 +528,10 @@ struct unpcb *unp; const struct sockaddr *sa; + unp = sotounpcb(so); + KASSERT(unp != NULL, ("uipc_sockaddr: unp == NULL")); *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); UNP_LOCK(); - unp = sotounpcb(so); - if (unp == NULL) { - UNP_UNLOCK(); - free(*nam, M_SONAME); - *nam = NULL; - return (EINVAL); - } if (unp->unp_addr != NULL) sa = (struct sockaddr *) unp->unp_addr; else @@ -632,14 +572,10 @@ if (sopt->sopt_level != 0) return (EINVAL); + unp = sotounpcb(so); + KASSERT(unp != NULL, ("uipc_ctloutput: unp == NULL")); UNP_LOCK(); - unp = sotounpcb(so); - if (unp == NULL) { - UNP_UNLOCK(); - return (EINVAL); - } error = 0; - switch (sopt->sopt_dir) { case SOPT_GET: switch (sopt->sopt_name) { @@ -745,6 +681,8 @@ struct unpcb *unp; int error; + KASSERT(so->so_pcb == NULL, ("unp_attach: so_pcb != NULL")); + if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { switch (so->so_type) { @@ -926,7 +864,9 @@ struct sockaddr *sa; UNP_LOCK_ASSERT(); + unp = sotounpcb(so); + KASSERT(unp != NULL, ("unp_connect: unp == NULL")); len = nam->sa_len - offsetof(struct sockaddr_un, sun_path); if (len <= 0) @@ -956,10 +896,7 @@ mtx_unlock(&Giant); UNP_LOCK(); unp = sotounpcb(so); - if (unp == NULL) { - error = EINVAL; - goto bad2; - } + KASSERT(unp != NULL, ("unp_connect: unp == NULL")); so2 = vp->v_socket; if (so2 == NULL) { error = ECONNREFUSED; @@ -1049,6 +986,7 @@ if (so2->so_type != so->so_type) return (EPROTOTYPE); unp2 = sotounpcb(so2); + KASSERT(unp2 != NULL, ("unp_connect2: unp2 == NULL")); unp->unp_conn = unp2; switch (so->so_type) { --- //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 2005/11/11 16:05:46 +++ //depot/user/rwatson/sockref/src/sys/net/rtsock.c 2006/02/13 21:56:55 @@ -137,11 +137,11 @@ * It really doesn't make any sense at all for this code to share much * with raw_usrreq.c, since its functionality is so restricted. XXX */ -static int +static void rts_abort(struct socket *so) { - return (raw_usrreqs.pru_abort(so)); + raw_usrreqs.pru_abort(so); } /* pru_accept is EOPNOTSUPP */ @@ -152,8 +152,8 @@ struct rawcb *rp; int s, error; - if (sotorawcb(so) != NULL) - return EISCONN; /* XXX panic? */ + KASSERT(so->so_pcb == NULL, ("rts_attach: so_pcb != NULL")); + /* XXX */ MALLOC(rp, struct rawcb *, sizeof *rp, M_PCB, M_WAITOK | M_ZERO); if (rp == NULL) @@ -214,32 +214,28 @@ /* pru_connect2 is EOPNOTSUPP */ /* pru_control is EOPNOTSUPP */ -static int +static void rts_detach(struct socket *so) { struct rawcb *rp = sotorawcb(so); - int s, error; + + KASSERT(rp != NULL, ("rts_detach: rp == NULL")); - s = splnet(); - if (rp != NULL) { - RTSOCK_LOCK(); - switch(rp->rcb_proto.sp_protocol) { - case AF_INET: - route_cb.ip_count--; - break; - case AF_INET6: - route_cb.ip6_count--; - break; - case AF_IPX: - route_cb.ipx_count--; - break; - } - route_cb.any_count--; - RTSOCK_UNLOCK(); + RTSOCK_LOCK(); + switch(rp->rcb_proto.sp_protocol) { + case AF_INET: + route_cb.ip_count--; + break; + case AF_INET6: + route_cb.ip6_count--; + break; + case AF_IPX: + route_cb.ipx_count--; + break; } - error = raw_usrreqs.pru_detach(so); - splx(s); - return error; + route_cb.any_count--; + RTSOCK_UNLOCK(); + raw_usrreqs.pru_detach(so); } static int --- //depot/vendor/freebsd/src/sys/netatalk/ddp_pcb.c 2005/01/07 02:37:15 +++ //depot/user/rwatson/sockref/src/sys/netatalk/ddp_pcb.c 2006/02/12 17:21:38 @@ -304,10 +304,7 @@ DDP_LOCK_ASSERT(ddp); soisdisconnected(so); - ACCEPT_LOCK(); - SOCK_LOCK(so); so->so_pcb = NULL; - sotryfree(so); /* remove ddp from ddp_ports list */ if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && --- //depot/vendor/freebsd/src/sys/netatalk/ddp_usrreq.c 2005/02/18 10:57:04 +++ //depot/user/rwatson/sockref/src/sys/netatalk/ddp_usrreq.c 2006/02/15 20:26:05 @@ -56,8 +56,7 @@ int error = 0; ddp = sotoddpcb(so); - if (ddp != NULL) - return (EINVAL); + KASSERT(ddp == NULL, ("ddp_attach: ddp != NULL")); /* * Allocate socket buffer space first so that it's present @@ -73,20 +72,18 @@ return (error); } -static int +static void ddp_detach(struct socket *so) { struct ddpcb *ddp; ddp = sotoddpcb(so); - if (ddp == NULL) - return (EINVAL); + KASSERT(ddp != NULL, ("ddp_detach: ddp == NULL")); DDP_LIST_XLOCK(); DDP_LOCK(ddp); at_pcbdetach(so, ddp); DDP_LIST_XUNLOCK(); - return (0); } static int @@ -96,9 +93,8 @@ int error = 0; ddp = sotoddpcb(so); - if (ddp == NULL) { - return (EINVAL); - } + KASSERT(ddp != NULL, ("ddp_bind: ddp == NULL")); + DDP_LIST_XLOCK(); DDP_LOCK(ddp); error = at_pcbsetaddr(ddp, nam, td); @@ -114,9 +110,7 @@ int error = 0; ddp = sotoddpcb(so); - if (ddp == NULL) { - return (EINVAL); - } + KASSERT(ddp != NULL, ("ddp_connect: ddp == NULL")); DDP_LIST_XLOCK(); DDP_LOCK(ddp); @@ -141,9 +135,7 @@ struct ddpcb *ddp; ddp = sotoddpcb(so); - if (ddp == NULL) { - return (EINVAL); - } + KASSERT(ddp != NULL, ("ddp_disconnect: ddp == NULL")); DDP_LOCK(ddp); if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) { DDP_UNLOCK(ddp); @@ -163,9 +155,7 @@ struct ddpcb *ddp; ddp = sotoddpcb(so); - if (ddp == NULL) { - return (EINVAL); - } + KASSERT(ddp != NULL, ("ddp_shutdown: ddp == NULL")); socantsendmore(so); return (0); } @@ -178,9 +168,7 @@ int error = 0; ddp = sotoddpcb(so); - if (ddp == NULL) { - return (EINVAL); - } + KASSERT(ddp != NULL, ("ddp_send: ddp == NULL")); if (control && control->m_len) { return (EINVAL); @@ -213,20 +201,17 @@ return (error); } -static int +static void ddp_abort(struct socket *so) { struct ddpcb *ddp; ddp = sotoddpcb(so); - if (ddp == NULL) { - return (EINVAL); - } + KASSERT(ddp != NULL, ("ddp_abort: ddp == NULL")); DDP_LIST_XLOCK(); DDP_LOCK(ddp); at_pcbdetach(so, ddp); DDP_LIST_XUNLOCK(); - return (0); } void @@ -269,9 +254,7 @@ struct ddpcb *ddp; ddp = sotoddpcb(so); - if (ddp == NULL) { - return (EINVAL); - } + KASSERT(ddp != NULL, ("at_setsockaddr: ddp == NULL")); DDP_LOCK(ddp); at_sockaddr(ddp, nam); DDP_UNLOCK(ddp); --- //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 2005/09/26 20:25:23 +++ //depot/user/rwatson/sockref/src/sys/netinet/in_pcb.h 2006/02/19 16:42:18 @@ -131,6 +131,8 @@ #define INP_IPV6PROTO 0x4 /* opened under IPv6 protocol */ #define INP_TIMEWAIT 0x8 /* .. probably doesn't go here */ #define INP_ONESBCAST 0x10 /* send all-ones broadcast */ +#define INP_DROPPED 0x20 /* protocol drop flag */ +#define INP_SOCKREF 0x40 /* strong socket reference */ u_char inp_ip_ttl; /* time to live proto */ u_char inp_ip_p; /* protocol proto */ u_char inp_ip_minttl; /* minimum TTL or drop */ @@ -348,6 +350,7 @@ struct ucred *); void in_pcbdetach(struct inpcb *); void in_pcbdisconnect(struct inpcb *); +void in_pcbfree(struct inpcb *); int in_pcbinshash(struct inpcb *); struct inpcb * in_pcblookup_local(struct inpcbinfo *, --- //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/02/18 17:05:16 +++ //depot/user/rwatson/sockref/src/sys/netinet/tcp_input.c 2006/02/19 18:34:22 @@ -790,6 +790,7 @@ goto drop; #endif so = inp->inp_socket; + KASSERT(so != NULL, ("tcp_input: so == NULL")); #ifdef TCPDEBUG if (so->so_options & SO_DEBUG) { ostate = tp->t_state; @@ -2551,7 +2552,7 @@ (tcp_seq)0, TH_RST|TH_ACK); } - if (tp) + if (tp != NULL) INP_UNLOCK(inp); if (headlocked) INP_INFO_WUNLOCK(&tcbinfo); @@ -2566,7 +2567,7 @@ tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, &tcp_savetcp, 0); #endif - if (tp) + if (tp != NULL) INP_UNLOCK(inp); if (headlocked) INP_INFO_WUNLOCK(&tcbinfo); @@ -3198,7 +3199,7 @@ * are above the previous ones. */ if ((thflags & TH_SYN) && SEQ_GT(th->th_seq, tw->rcv_nxt)) { - (void) tcp_twclose(tw, 0); + tcp_twclose(tw, 0); return (1); } --- //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/02/16 15:45:16 +++ //depot/user/rwatson/sockref/src/sys/netinet/tcp_timer.c 2006/02/21 23:33:49 @@ -125,6 +125,10 @@ static int tcp_totbackoff = 2559; /* sum of tcp_backoff[] */ +static int tcp_timer_race; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, timer_race, CTLFLAG_RD, &tcp_timer_race, + 0, "Count of t_inpcb races on tcp_discardcb"); + /* * TCP timer processing. */ @@ -138,7 +142,15 @@ INP_INFO_RLOCK(&tcbinfo); inp = tp->t_inpcb; + /* + * XXXRW: While this assert is in fact correct, bugs in the tcpcb + * tear-down mean we need it as a work-around for races between + * timers and tcp_discardcb(). + * + * KASSERT(inp != NULL, ("tcp_timer_delack: inp == NULL")); + */ if (inp == NULL) { + tcp_timer_race++; INP_INFO_RUNLOCK(&tcbinfo); return; } @@ -167,10 +179,21 @@ ostate = tp->t_state; #endif + /* + * XXXRW: Does this actually happen? + */ INP_INFO_WLOCK(&tcbinfo); inp = tp->t_inpcb; + /* + * XXXRW: While this assert is in fact correct, bugs in the tcpcb + * tear-down mean we need it as a work-around for races between + * timers and tcp_discardcb(). + * + * KASSERT(inp != NULL, ("tcp_timer_2msl: inp == NULL")); + */ if (inp == NULL) { - INP_INFO_WUNLOCK(&tcbinfo); + tcp_timer_race++; + INP_INFO_RUNLOCK(&tcbinfo); return; } INP_LOCK(inp); @@ -195,11 +218,11 @@ tp = tcp_close(tp); #ifdef TCPDEBUG - if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp != NULL && tp->t_inpcb->inp_socket->so_options & SO_DEBUG) tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, PRU_SLOWTIMO); #endif - if (tp) + if (tp != NULL) INP_UNLOCK(inp); INP_INFO_WUNLOCK(&tcbinfo); } @@ -267,14 +290,12 @@ for (i = 0; i < 2; i++) { twl = tw_2msl_list[i]; tw_tail = &twl->tw_tail; - for (;;) { - tw = LIST_FIRST(&twl->tw_list); - if (tw == tw_tail || (!reuse && tw->tw_time > ticks)) - break; - INP_LOCK(tw->tw_inpcb); - if (tcp_twclose(tw, reuse) != NULL) - return (tw); - } + tw = LIST_FIRST(&twl->tw_list); + if (tw == tw_tail || (!reuse && tw->tw_time > ticks)) + continue; + INP_LOCK(tw->tw_inpcb); + tcp_twclose(tw, reuse); + return (tw); } return (NULL); } @@ -293,8 +314,16 @@ #endif INP_INFO_WLOCK(&tcbinfo); inp = tp->t_inpcb; - if (!inp) { - INP_INFO_WUNLOCK(&tcbinfo); + /* + * XXXRW: While this assert is in fact correct, bugs in the tcpcb + * tear-down mean we need it as a work-around for races between + * timers and tcp_discardcb(). + * + * KASSERT(inp != NULL, ("tcp_timer_keep: inp == NULL")); + */ + if (inp == NULL) { + tcp_timer_race++; + INP_INFO_RUNLOCK(&tcbinfo); return; } INP_LOCK(inp); @@ -353,11 +382,11 @@ tp = tcp_drop(tp, ETIMEDOUT); #ifdef TCPDEBUG - if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp != NULL && tp->t_inpcb->inp_socket->so_options & SO_DEBUG) tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, PRU_SLOWTIMO); #endif - if (tp) + if (tp != NULL) INP_UNLOCK(tp->t_inpcb); INP_INFO_WUNLOCK(&tcbinfo); } @@ -375,8 +404,16 @@ #endif INP_INFO_WLOCK(&tcbinfo); inp = tp->t_inpcb; - if (!inp) { - INP_INFO_WUNLOCK(&tcbinfo); + /* + * XXXRW: While this assert is in fact correct, bugs in the tcpcb + * tear-down mean we need it as a work-around for races between + * timers and tcp_discardcb(). + * + * KASSERT(inp != NULL, ("tcp_timer_persist: inp == NULL")); + */ + if (inp == NULL) { + tcp_timer_race++; + INP_INFO_RUNLOCK(&tcbinfo); return; } INP_LOCK(inp); @@ -412,11 +449,11 @@ out: #ifdef TCPDEBUG - if (tp && tp->t_inpcb->inp_socket->so_options & SO_DEBUG) + if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, PRU_SLOWTIMO); #endif - if (tp) + if (tp != NULL) INP_UNLOCK(inp); INP_INFO_WUNLOCK(&tcbinfo); } @@ -437,8 +474,16 @@ INP_INFO_WLOCK(&tcbinfo); headlocked = 1; inp = tp->t_inpcb; - if (!inp) { - INP_INFO_WUNLOCK(&tcbinfo); + /* + * XXXRW: While this assert is in fact correct, bugs in the tcpcb + * tear-down mean we need it as a work-around for races between + * timers and tcp_discardcb(). + * + * KASSERT(inp != NULL, ("tcp_timer_rexmt: inp == NULL")); + */ + if (inp == NULL) { + tcp_timer_race++; + INP_INFO_RUNLOCK(&tcbinfo); return; } INP_LOCK(inp); @@ -560,11 +605,11 @@ out: #ifdef TCPDEBUG - if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) + if (tp != NULL && tp->t_inpcb->inp_socket->so_options & SO_DEBUG) tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, PRU_SLOWTIMO); #endif - if (tp) + if (tp != NULL) INP_UNLOCK(inp); if (headlocked) INP_INFO_WUNLOCK(&tcbinfo); --- //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/02/22 14:19:11 @@ -89,10 +89,8 @@ static int tcp6_connect(struct tcpcb *, struct sockaddr *, struct thread *td); #endif /* INET6 */ -static struct tcpcb * - tcp_disconnect(struct tcpcb *); -static struct tcpcb * - tcp_usrclosed(struct tcpcb *); +static void tcp_disconnect(struct tcpcb *); +static void tcp_usrclosed(struct tcpcb *); static void tcp_fill_info(struct tcpcb *, struct tcp_info *); #ifdef TCPDEBUG @@ -115,16 +113,12 @@ { int error; struct inpcb *inp; - struct tcpcb *tp = 0; TCPDEBUG0; + inp = sotoinpcb(so); + KASSERT(inp == NULL, ("tcp_usr_attach: inp != NULL")); INP_INFO_WLOCK(&tcbinfo); TCPDEBUG1(); - inp = sotoinpcb(so); - if (inp) { - error = EISCONN; - goto out; - } error = tcp_attach(so); if (error) @@ -133,8 +127,6 @@ if ((so->so_options & SO_LINGER) && so->so_linger == 0) so->so_linger = TCP_LINGERTIME; - inp = sotoinpcb(so); - tp = intotcpcb(inp); out: TCPDEBUG2(PRU_ATTACH); INP_INFO_WUNLOCK(&tcbinfo); @@ -148,69 +140,94 @@ * which may finish later; embryonic TCB's can just * be discarded here. */ -static int +static void tcp_usr_detach(struct socket *so) { - int error = 0; struct inpcb *inp; struct tcpcb *tp; +#ifdef INET6 + int isipv6 = INP_CHECK_SOCKAF(so, AF_INET6) != 0; +#endif TCPDEBUG0; + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("tcp_usr_detach: inp == NULL")); INP_INFO_WLOCK(&tcbinfo); - inp = sotoinpcb(so); - if (inp == NULL) { - INP_INFO_WUNLOCK(&tcbinfo); - return error; - } INP_LOCK(inp); - tp = intotcpcb(inp); - TCPDEBUG1(); - tp = tcp_disconnect(tp); + KASSERT(inp->inp_socket != NULL, + ("tcp_usr_detach: inp_socket == NULL")); - TCPDEBUG2(PRU_DETACH); - if (tp) - INP_UNLOCK(inp); + if (inp->inp_vflag & INP_TIMEWAIT) { + if (inp->inp_vflag & INP_DROPPED) { + /* + * Connection was in time wait and has been dropped; + * the calling path is via tcp_twclose(), which will + * free the tcptw, so we can discard the remainder. + * + * XXXRW: Would it be cleaner to free the tcptw + * here? + */ +#ifdef INET6 + if (isipv6) { + in6_pcbdetach(inp); + in6_pcbfree(inp); + } else { +#endif + in_pcbdetach(inp); + in_pcbfree(inp); +#ifdef INET6 + } +#endif + } else { + /* + * Connection is in time wait and has not yet been + * dropped; allow the socket to be discarded, but + * need to keep inpcb until end of time wait. + */ +#ifdef INET6 + if (isipv6) + in6_pcbdetach(inp); + else +#endif + in_pcbdetach(inp); + INP_UNLOCK(inp); + } + } else { + tp = intotcpcb(inp); + if (inp->inp_vflag & INP_DROPPED || + tp->t_state < TCPS_SYN_SENT) { + /* + * Connection has been dropped or is a listen socket, + * tear down all pcb state and allow socket to be + * freed. + */ + tcp_discardcb(tp); +#ifdef INET6 + if (isipv6) { + in_pcbdetach(inp); + in_pcbfree(inp); + } else { +#endif + in_pcbdetach(inp); + in_pcbfree(inp); +#ifdef INET6 + } +#endif + } else { + /* + * Connection state still required, as is socket, so + * mark socket for TCP to free later. + */ + SOCK_LOCK(so); + so->so_state |= SS_PROTOREF; + SOCK_UNLOCK(so); + inp->inp_vflag |= INP_SOCKREF; + INP_UNLOCK(inp); + } + } INP_INFO_WUNLOCK(&tcbinfo); - return error; } -#define INI_NOLOCK 0 -#define INI_READ 1 -#define INI_WRITE 2 - -#define COMMON_START() \ - TCPDEBUG0; \ - do { \ - if (inirw == INI_READ) \ - INP_INFO_RLOCK(&tcbinfo); \ - else if (inirw == INI_WRITE) \ - INP_INFO_WLOCK(&tcbinfo); \ - inp = sotoinpcb(so); \ - if (inp == 0) { \ - if (inirw == INI_READ) \ - INP_INFO_RUNLOCK(&tcbinfo); \ - else if (inirw == INI_WRITE) \ - INP_INFO_WUNLOCK(&tcbinfo); \ - return EINVAL; \ - } \ - INP_LOCK(inp); \ - if (inirw == INI_READ) \ - INP_INFO_RUNLOCK(&tcbinfo); \ - tp = intotcpcb(inp); \ - TCPDEBUG1(); \ -} while(0) - -#define COMMON_END(req) \ -out: TCPDEBUG2(req); \ - do { \ - if (tp) \ - INP_UNLOCK(inp); \ - if (inirw == INI_WRITE) \ - INP_INFO_WUNLOCK(&tcbinfo); \ - return error; \ - goto out; \ -} while(0) - /* * Give the socket an address. */ @@ -221,7 +238,6 @@ struct inpcb *inp; struct tcpcb *tp; struct sockaddr_in *sinp; - const int inirw = INI_WRITE; sinp = (struct sockaddr_in *)nam; if (nam->sa_len != sizeof (*sinp)) @@ -234,11 +250,24 @@ IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) return (EAFNOSUPPORT); - COMMON_START(); + TCPDEBUG0; + INP_INFO_WLOCK(&tcbinfo); + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("tcp_usr_bind: inp == NULL")); + INP_LOCK(inp); + if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) { + error = EINVAL; + goto out; + } + tp = intotcpcb(inp); + TCPDEBUG1(); error = in_pcbbind(inp, nam, td->td_ucred); - if (error) - goto out; - COMMON_END(PRU_BIND); +out: + TCPDEBUG2(PRU_BIND); + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); + + return (error); } #ifdef INET6 @@ -249,7 +278,6 @@ struct inpcb *inp; struct tcpcb *tp; struct sockaddr_in6 *sin6p; - const int inirw = INI_WRITE; sin6p = (struct sockaddr_in6 *)nam; if (nam->sa_len != sizeof (*sin6p)) @@ -262,7 +290,17 @@ IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) return (EAFNOSUPPORT); - COMMON_START(); + TCPDEBUG0; + INP_INFO_WLOCK(&tcbinfo); + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("tcp6_usr_bind: inp == NULL")); + INP_LOCK(inp); + if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) { + error = EINVAL; + goto out; + } + tp = intotcpcb(inp); + TCPDEBUG1(); inp->inp_vflag &= ~INP_IPV4; inp->inp_vflag |= INP_IPV6; if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { @@ -280,9 +318,11 @@ } } error = in6_pcbbind(inp, nam, td->td_ucred); - if (error) - goto out; - COMMON_END(PRU_BIND); +out: + TCPDEBUG2(PRU_BIND); + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); + return (error); } #endif /* INET6 */ @@ -295,9 +335,18 @@ int error = 0; struct inpcb *inp; struct tcpcb *tp; - const int inirw = INI_WRITE; - COMMON_START(); + TCPDEBUG0; + INP_INFO_WLOCK(&tcbinfo); + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("tcp_usr_listen: inp == NULL")); + INP_LOCK(inp); + if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) { + error = EINVAL; + goto out; + } + tp = intotcpcb(inp); + TCPDEBUG1(); SOCK_LOCK(so); error = solisten_proto_check(so); if (error == 0 && inp->inp_lport == 0) @@ -307,7 +356,12 @@ solisten_proto(so, backlog); } SOCK_UNLOCK(so); - COMMON_END(PRU_LISTEN); + +out: + TCPDEBUG2(PRU_LISTEN); + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); + return (error); } #ifdef INET6 @@ -317,9 +371,18 @@ int error = 0; struct inpcb *inp; struct tcpcb *tp; - const int inirw = INI_WRITE; - COMMON_START(); + TCPDEBUG0; + INP_INFO_WLOCK(&tcbinfo); + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("tcp6_usr_listen: inp == NULL")); + INP_LOCK(inp); + if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) { + error = EINVAL; + goto out; + } + tp = intotcpcb(inp); + TCPDEBUG1(); SOCK_LOCK(so); error = solisten_proto_check(so); if (error == 0 && inp->inp_lport == 0) { @@ -333,7 +396,12 @@ solisten_proto(so, backlog); } SOCK_UNLOCK(so); - COMMON_END(PRU_LISTEN); + +out: + TCPDEBUG2(PRU_LISTEN); + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); + return (error); } #endif /* INET6 */ @@ -351,7 +419,6 @@ struct inpcb *inp; struct tcpcb *tp; struct sockaddr_in *sinp; - const int inirw = INI_WRITE; sinp = (struct sockaddr_in *)nam; if (nam->sa_len != sizeof (*sinp)) @@ -365,11 +432,25 @@ if (jailed(td->td_ucred)) prison_remote_ip(td->td_ucred, 0, &sinp->sin_addr.s_addr); - COMMON_START(); + TCPDEBUG0; + INP_INFO_WLOCK(&tcbinfo); + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("tcp_usr_connect: inp == NULL")); + INP_LOCK(inp); + if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) { + error = EINVAL; + goto out; + } + tp = intotcpcb(inp); + TCPDEBUG1(); if ((error = tcp_connect(tp, nam, td)) != 0) goto out; error = tcp_output(tp); - COMMON_END(PRU_CONNECT); +out: + TCPDEBUG2(PRU_CONNECT); + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); + return (error); } #ifdef INET6 @@ -380,7 +461,8 @@ struct inpcb *inp; struct tcpcb *tp; struct sockaddr_in6 *sin6p; - const int inirw = INI_WRITE; + + TCPDEBUG0; sin6p = (struct sockaddr_in6 *)nam; if (nam->sa_len != sizeof (*sin6p)) @@ -392,7 +474,16 @@ && IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) return (EAFNOSUPPORT); - COMMON_START(); + INP_INFO_WLOCK(&tcbinfo); + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("tcp6_usr_connect: inp == NULL")); + INP_LOCK(inp); + if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) { + error = EINVAL; + goto out; + } + tp = intotcpcb(inp); + TCPDEBUG1(); if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) { struct sockaddr_in sin; @@ -415,7 +506,12 @@ if ((error = tcp6_connect(tp, nam, td)) != 0) goto out; error = tcp_output(tp); - COMMON_END(PRU_CONNECT); + +out: + TCPDEBUG2(PRU_CONNECT); + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); + return (error); } #endif /* INET6 */ @@ -433,14 +529,27 @@ static int tcp_usr_disconnect(struct socket *so) { - int error = 0; struct inpcb *inp; struct tcpcb *tp; - const int inirw = INI_WRITE; + int error = 0; - COMMON_START(); - tp = tcp_disconnect(tp); - COMMON_END(PRU_DISCONNECT); + TCPDEBUG0; + INP_INFO_WLOCK(&tcbinfo); + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("tcp_usr_disconnect: inp == NULL")); + INP_LOCK(inp); + if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) { + error = EINVAL; + goto out; + } + tp = intotcpcb(inp); + TCPDEBUG1(); + tcp_disconnect(tp); +out: + TCPDEBUG2(PRU_DISCONNECT); + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); + return (error); } /* @@ -463,14 +572,13 @@ goto out; } - INP_INFO_RLOCK(&tcbinfo); inp = sotoinpcb(so); - if (!inp) { - INP_INFO_RUNLOCK(&tcbinfo); - return (EINVAL); + KASSERT(inp != NULL, ("tcp_usr_accept: inp == NULL")); + INP_LOCK(inp); + if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) { + error = EINVAL; + goto out; } - INP_LOCK(inp); - INP_INFO_RUNLOCK(&tcbinfo); tp = intotcpcb(inp); TCPDEBUG1(); @@ -482,9 +590,9 @@ port = inp->inp_fport; addr = inp->inp_faddr; -out: TCPDEBUG2(PRU_ACCEPT); - if (tp) - INP_UNLOCK(inp); +out: + TCPDEBUG2(PRU_ACCEPT); + INP_UNLOCK(inp); if (error == 0) *nam = in_sockaddr(port, &addr); return error; @@ -508,16 +616,16 @@ goto out; } - INP_INFO_RLOCK(&tcbinfo); inp = sotoinpcb(so); - if (inp == 0) { - INP_INFO_RUNLOCK(&tcbinfo); - return (EINVAL); + KASSERT(inp != NULL, ("tcp6_usr_accept: inp == NULL")); + INP_LOCK(inp); + if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) { + error = EINVAL; + goto out; } - INP_LOCK(inp); - INP_INFO_RUNLOCK(&tcbinfo); tp = intotcpcb(inp); TCPDEBUG1(); + /* * We inline in6_mapped_peeraddr and COMMON_END here, so that we can * copy the data of interest and defer the malloc until after we @@ -532,9 +640,9 @@ addr6 = inp->in6p_faddr; } -out: TCPDEBUG2(PRU_ACCEPT); - if (tp) - INP_UNLOCK(inp); +out: + TCPDEBUG2(PRU_ACCEPT); + INP_UNLOCK(inp); if (error == 0) { if (v4) *nam = in6_v4mapsin6_sockaddr(port, &addr); @@ -575,14 +683,29 @@ int error = 0; struct inpcb *inp; struct tcpcb *tp; - const int inirw = INI_WRITE; + - COMMON_START(); + TCPDEBUG0; + INP_INFO_WLOCK(&tcbinfo); + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("inp == NULL")); + INP_LOCK(inp); + if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) { + error = EINVAL; + goto out; + } + tp = intotcpcb(inp); + TCPDEBUG1(); socantsendmore(so); - tp = tcp_usrclosed(tp); - if (tp) - error = tcp_output(tp); - COMMON_END(PRU_SHUTDOWN); + tcp_usrclosed(tp); + error = tcp_output(tp); + +out: + TCPDEBUG2(PRU_SHUTDOWN); + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); + + return (error); } /* @@ -591,14 +714,26 @@ static int tcp_usr_rcvd(struct socket *so, int flags) { - int error = 0; struct inpcb *inp; struct tcpcb *tp; - const int inirw = INI_READ; + int error = 0; - COMMON_START(); + TCPDEBUG0; + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("tcp_usr_rcvd: inp == NULL")); + INP_LOCK(inp); + if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) { + error = EINVAL; + goto out; + } + tp = intotcpcb(inp); + TCPDEBUG1(); tcp_output(tp); - COMMON_END(PRU_RCVD); + +out: + TCPDEBUG2(PRU_RCVD); + INP_UNLOCK(inp); + return (error); } /* @@ -615,36 +750,32 @@ int error = 0; struct inpcb *inp; struct tcpcb *tp; - int unlocked = 0; + int headlocked = 0; #ifdef INET6 int isipv6; #endif TCPDEBUG0; /* - * Need write lock here because this function might call - * tcp_connect or tcp_usrclosed. - * We really want to have to this function upgrade from read lock - * to write lock. XXX + * We require the pcbinfo lock in two cases: + * + * (1) An implied connect is taking place, which can result in + * binding IPs and ports and hence modification of the pcb hash + * chains. + * + * (2) PRUS_EOF is set, resulting in explicit close on the send. */ - INP_INFO_WLOCK(&tcbinfo); + if ((nam != NULL) || (flags & PRUS_EOF)) { + INP_INFO_WLOCK(&tcbinfo); + headlocked = 1; + } inp = sotoinpcb(so); - if (inp == NULL) { - /* - * OOPS! we lost a race, the TCP session got reset after - * we checked SBS_CANTSENDMORE, eg: while doing uiomove or a - * network interrupt in the non-splnet() section of sosend(). - */ - if (m) - m_freem(m); - if (control) - m_freem(control); - error = ECONNRESET; /* XXX EPIPE? */ - tp = NULL; - TCPDEBUG1(); + KASSERT(inp != NULL, ("tcp_usr_send: inp == NULL")); + INP_LOCK(inp); + if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) { + error = EINVAL; goto out; } - INP_LOCK(inp); #ifdef INET6 isipv6 = nam && nam->sa_family == AF_INET6; #endif /* INET6 */ @@ -688,10 +819,10 @@ * the data is sent. */ socantsendmore(so); - tp = tcp_usrclosed(tp); + tcp_usrclosed(tp); } INP_INFO_WUNLOCK(&tcbinfo); - unlocked = 1; + headlocked = 0; if (tp != NULL) { if (flags & PRUS_MORETOCOME) tp->t_flags |= TF_MORETOCOME; @@ -736,7 +867,7 @@ tcp_mss(tp, -1); } INP_INFO_WUNLOCK(&tcbinfo); - unlocked = 1; + headlocked = 0; tp->snd_up = tp->snd_una + so->so_snd.sb_cc; tp->t_flags |= TF_FORCEDATA; error = tcp_output(tp); @@ -745,9 +876,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 +885,40 @@ /* * Abort the TCP. */ -static int +static void tcp_usr_abort(struct socket *so) { - int error = 0; +#if 0 struct inpcb *inp; struct tcpcb *tp; - const int inirw = INI_WRITE; +#endif + + /* + * XXXRW: This is not really quite the same, as we want to tcp_drop() + * rather than tcp_disconnect(), I think, but for now I'll avoid + * replicating all the tear-down logic here. + */ + tcp_usr_detach(so); - COMMON_START(); +#if 0 + TCPDEBUG0; + INP_INFO_WLOCK(&tcbinfo); + inp = sotoinpcb(so); + INP_LOCK(inp); + /* + * Do we need to handle timewait here? Aborted connections should + * never generate a FIN? + */ + KASSERT((inp->inp_vflag & INP_TIMEWAIT) == 0, + ("tcp_usr_abort: timewait")); + tp = intotcpcb(inp); + TCPDEBUG1(); tp = tcp_drop(tp, ECONNABORTED); - COMMON_END(PRU_ABORT); + TCPDEBUG2(PRU_ABORT); + if (tp != NULL) + INP_UNLOCK(inp); + INP_INFO_WUNLOCK(&tcbinfo); +#endif } /* @@ -777,9 +930,17 @@ int error = 0; struct inpcb *inp; struct tcpcb *tp; - const int inirw = INI_READ; - COMMON_START(); + TCPDEBUG0; + inp = sotoinpcb(so); + KASSERT(inp != NULL, ("tcp_usr_rcvoob: inp == NULL")); + INP_LOCK(inp); + if (inp->inp_vflag & (INP_TIMEWAIT | INP_DROPPED)) { + error = EINVAL; + goto out; + } + tp = intotcpcb(inp); + TCPDEBUG1(); if ((so->so_oobmark == 0 && (so->so_rcv.sb_state & SBS_RCVATMARK) == 0) || so->so_options & SO_OOBINLINE || @@ -795,7 +956,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 +1025,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 +1079,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 +1191,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 +1204,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 +1322,7 @@ } break; } +out: INP_UNLOCK(inp); return (error); } @@ -1204,19 +1375,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 +1402,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 +1412,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 +1442,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 +1456,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 +1484,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/16 19:40:18 +++ //depot/user/rwatson/sockref/src/sys/netinet/tcp_var.h 2006/02/18 20:36:51 @@ -518,10 +518,10 @@ struct tcpcb * tcp_close(struct tcpcb *); +void tcp_discardcb(struct tcpcb *); void tcp_twstart(struct tcpcb *); int tcp_twrecycleable(struct tcptw *tw); -struct tcptw * - tcp_twclose(struct tcptw *_tw, int _reuse); +void tcp_twclose(struct tcptw *_tw, int _reuse); void tcp_ctlinput(int, struct sockaddr *, void *); int tcp_ctloutput(struct socket *, struct sockopt *); struct tcpcb * --- //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 2005/09/07 10:17:18 +++ //depot/user/rwatson/sockref/src/sys/netinet6/in6_pcb.c 2006/02/19 19:33:03 @@ -421,17 +421,23 @@ #ifdef IPSEC ipsec_pcbdisconn(inp->inp_sp); #endif - if (inp->inp_socket->so_state & SS_NOFDREF) - in6_pcbdetach(inp); +} + +void +in6_pcbdetach(struct inpcb *inp) +{ + + KASSERT(inp->inp_socket != NULL, ("in6_pcbdetach: inp_socket == NULL")); + inp->inp_socket->so_pcb = NULL; + inp->inp_socket = NULL; } void -in6_pcbdetach(inp) - struct inpcb *inp; +in6_pcbfree(struct inpcb *inp) { - struct socket *so = inp->inp_socket; struct inpcbinfo *ipi = inp->inp_pcbinfo; + KASSERT(inp->inp_socket == NULL, ("in6_pcbfree: inp_socket != NULL")); INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo); INP_LOCK_ASSERT(inp); @@ -441,14 +447,6 @@ #endif /* IPSEC */ inp->inp_gencnt = ++ipi->ipi_gencnt; in_pcbremlists(inp); - - if (so) { - ACCEPT_LOCK(); - SOCK_LOCK(so); - so->so_pcb = NULL; - sotryfree(so); - } - ip6_freepcbopts(inp->in6p_outputopts); ip6_freemoptions(inp->in6p_moptions); /* Check and free IPv4 related resources in case of mapped addr */ --- //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_pcb.c 2005/01/09 05:10:49 +++ //depot/user/rwatson/sockref/src/sys/netipx/ipx_pcb.c 2006/02/12 19:33:28 @@ -63,6 +63,7 @@ { register struct ipxpcb *ipxp; + KASSERT(so->so_pcb == NULL, ("ipx_pcballoc: so_pcb != NULL")); IPX_LIST_LOCK_ASSERT(); MALLOC(ipxp, struct ipxpcb *, sizeof *ipxp, M_PCB, M_NOWAIT | M_ZERO); @@ -285,10 +286,7 @@ IPX_LIST_LOCK_ASSERT(); IPX_LOCK_ASSERT(ipxp); - ACCEPT_LOCK(); - SOCK_LOCK(so); so->so_pcb = NULL; - sotryfree(so); if (ipxp->ipxp_route.ro_rt != NULL) RTFREE(ipxp->ipxp_route.ro_rt); LIST_REMOVE(ipxp, ipxp_list); --- //depot/vendor/freebsd/src/sys/netipx/ipx_usrreq.c 2005/01/09 05:20:42 +++ //depot/user/rwatson/sockref/src/sys/netipx/ipx_usrreq.c 2006/02/15 20:30:27 @@ -74,12 +74,12 @@ SYSCTL_INT(_net_ipx_ipx, OID_AUTO, ipxrecvspace, CTLFLAG_RW, &ipxrecvspace, 0, ""); -static int ipx_usr_abort(struct socket *so); +static void ipx_usr_abort(struct socket *so); static int ipx_attach(struct socket *so, int proto, struct thread *td); static int ipx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); static int ipx_connect(struct socket *so, struct sockaddr *nam, struct thread *td); -static int ipx_detach(struct socket *so); +static void ipx_detach(struct socket *so); static int ipx_disconnect(struct socket *so); static int ipx_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, struct mbuf *control, @@ -428,7 +428,7 @@ return (error); } -static int +static void ipx_usr_abort(so) struct socket *so; { @@ -439,10 +439,6 @@ ipx_pcbdetach(ipxp); IPX_LIST_UNLOCK(); soisdisconnected(so); - ACCEPT_LOCK(); - SOCK_LOCK(so); - sotryfree(so); - return (0); } static int @@ -454,13 +450,13 @@ struct ipxpcb *ipxp = sotoipxpcb(so); int error; - if (ipxp != NULL) - return (EINVAL); + error = soreserve(so, ipxsendspace, ipxrecvspace); + if (error != 0) + return (error); + KASSERT(ipxp == NULL, ("ipx_attach: ipxp != NULL")); IPX_LIST_LOCK(); error = ipx_pcballoc(so, &ipxpcb_list, td); IPX_LIST_UNLOCK(); - if (error == 0) - error = soreserve(so, ipxsendspace, ipxrecvspace); return (error); } @@ -473,6 +469,7 @@ struct ipxpcb *ipxp = sotoipxpcb(so); int error; + KASSERT(ipxp != NULL, ("ipx_bind: ipxp == NULL")); IPX_LIST_LOCK(); IPX_LOCK(ipxp); error = ipx_pcbbind(ipxp, nam, td); @@ -490,6 +487,7 @@ struct ipxpcb *ipxp = sotoipxpcb(so); int error; + KASSERT(ipxp != NULL, ("ipx_connect: ipxp == NULL")); IPX_LIST_LOCK(); IPX_LOCK(ipxp); if (!ipx_nullhost(ipxp->ipxp_faddr)) { @@ -505,19 +503,17 @@ return (error); } -static int +static void ipx_detach(so) struct socket *so; { struct ipxpcb *ipxp = sotoipxpcb(so); - if (ipxp == NULL) - return (ENOTCONN); + KASSERT(ipxp != NULL, ("ipx_detach: ipxp == NULL")); IPX_LIST_LOCK(); IPX_LOCK(ipxp); ipx_pcbdetach(ipxp); IPX_LIST_UNLOCK(); - return (0); } static int @@ -527,6 +523,7 @@ struct ipxpcb *ipxp = sotoipxpcb(so); int error; + KASSERT(ipxp != NULL, ("ipx_disconnect: ipxp == NULL")); IPX_LIST_LOCK(); IPX_LOCK(ipxp); error = 0; @@ -549,6 +546,7 @@ { struct ipxpcb *ipxp = sotoipxpcb(so); + KASSERT(ipxp != NULL, ("ipx_peeraddr: ipxp == NULL")); ipx_setpeeraddr(ipxp, nam); return (0); } @@ -566,6 +564,7 @@ struct ipxpcb *ipxp = sotoipxpcb(so); struct ipx_addr laddr; + KASSERT(ipxp != NULL, ("ipxp_send: ipxp == NULL")); /* * Attempt to only acquire the necessary locks: if the socket is * already connected, we don't need to hold the IPX list lock to be @@ -619,6 +618,8 @@ ipx_shutdown(so) struct socket *so; { + + KASSERT(so->so_pcb != NULL, ("ipx_shutdown: so_pcb == NULL")); socantsendmore(so); return (0); } @@ -630,6 +631,7 @@ { struct ipxpcb *ipxp = sotoipxpcb(so); + KASSERT(ipxp != NULL, ("ipx_sockaddr: ipxp == NULL")); ipx_setsockaddr(ipxp, nam); return (0); } @@ -643,6 +645,7 @@ int error = 0; struct ipxpcb *ipxp = sotoipxpcb(so); + KASSERT(ipxp == NULL, ("ripx_attach: ipxp != NULL")); if (td != NULL && (error = suser(td)) != 0) return (error); /* --- //depot/vendor/freebsd/src/sys/netipx/spx_usrreq.c 2006/01/14 00:11:17 +++ //depot/user/rwatson/sockref/src/sys/netipx/spx_usrreq.c 2006/02/15 20:30:27 @@ -91,13 +91,13 @@ static struct spxpcb *spx_timers(struct spxpcb *cb, int timer); static void spx_usrclosed(struct spxpcb *cb); -static int spx_usr_abort(struct socket *so); +static void spx_usr_abort(struct socket *so); static int spx_accept(struct socket *so, struct sockaddr **nam); static int spx_attach(struct socket *so, int proto, struct thread *td); static int spx_bind(struct socket *so, struct sockaddr *nam, struct thread *td); static int spx_connect(struct socket *so, struct sockaddr *nam, struct thread *td); -static int spx_detach(struct socket *so); +static void spx_detach(struct socket *so); static int spx_usr_disconnect(struct socket *so); static int spx_listen(struct socket *so, int backlog, struct thread *td); static int spx_rcvd(struct socket *so, int flags); @@ -1169,6 +1169,8 @@ u_short usoptval; int optval; + KASSERT(ipxp != NULL, ("spx_ctloutput: ipxp == NULL")); + error = 0; if (sopt->sopt_level != IPXPROTO_SPX) { @@ -1176,10 +1178,7 @@ stacking of protocols */ return (ipx_ctloutput(so, sopt)); } - if (ipxp == NULL) - return (EINVAL); - else - cb = ipxtospxpcb(ipxp); + cb = ipxtospxpcb(ipxp); switch (sopt->sopt_dir) { case SOPT_GET: @@ -1295,7 +1294,7 @@ return (error); } -static int +static void spx_usr_abort(so) struct socket *so; { @@ -1303,13 +1302,14 @@ struct spxpcb *cb; ipxp = sotoipxpcb(so); + KASSERT(ipxp != NULL, ("spx_usr_abort: ipxp == NULL")); + cb = ipxtospxpcb(ipxp); IPX_LIST_LOCK(); IPX_LOCK(ipxp); spx_drop(cb, ECONNABORTED); IPX_LIST_UNLOCK(); - return (0); } /* @@ -1326,6 +1326,7 @@ struct sockaddr_ipx *sipx, ssipx; ipxp = sotoipxpcb(so); + KASSERT(ipxp != NULL, ("spx_accept: ipxp == NULL")); sipx = &ssipx; bzero(sipx, sizeof *sipx); sipx->sipx_len = sizeof *sipx; @@ -1350,7 +1351,7 @@ int error; ipxp = sotoipxpcb(so); - cb = ipxtospxpcb(ipxp); + KASSERT(ipxp == NULL, ("spx_attach: ipxp != NULL")); IPX_LIST_LOCK(); error = ipx_pcballoc(so, &ipxpcb_list, td); @@ -1410,6 +1411,7 @@ int error; ipxp = sotoipxpcb(so); + KASSERT(ipxp != NULL, ("spx_bind: ipxp == NULL")); IPX_LIST_LOCK(); IPX_LOCK(ipxp); @@ -1436,6 +1438,7 @@ int error; ipxp = sotoipxpcb(so); + KASSERT(ipxp != NULL, ("spx_connect: ipxp == NULL")); cb = ipxtospxpcb(ipxp); IPX_LIST_LOCK(); @@ -1471,7 +1474,7 @@ return (error); } -static int +static void spx_detach(so) struct socket *so; { @@ -1479,6 +1482,7 @@ struct spxpcb *cb; ipxp = sotoipxpcb(so); + KASSERT(ipxp != NULL, ("spx_detach: ipxp == NULL")); cb = ipxtospxpcb(ipxp); IPX_LIST_LOCK(); @@ -1488,7 +1492,6 @@ else spx_close(cb); IPX_LIST_UNLOCK(); - return (0); } /* @@ -1504,6 +1507,7 @@ struct spxpcb *cb; ipxp = sotoipxpcb(so); + KASSERT(ipxp != NULL, ("spx_usr_disconnect: ipxp == NULL")); cb = ipxtospxpcb(ipxp); IPX_LIST_LOCK(); @@ -1576,6 +1580,7 @@ struct spxpcb *cb; ipxp = sotoipxpcb(so); + KASSERT(ipxp != NULL, ("spx_rcvoob: ipxp == NULL")); cb = ipxtospxpcb(ipxp); SOCKBUF_LOCK(&so->so_rcv); @@ -1606,6 +1611,7 @@ error = 0; ipxp = sotoipxpcb(so); + KASSERT(ipxp != NULL, ("spx_send: ipxp == NULL")); cb = ipxtospxpcb(ipxp); IPX_LOCK(ipxp); @@ -1645,6 +1651,7 @@ struct spxpcb *cb; ipxp = sotoipxpcb(so); + KASSERT(ipxp != NULL, ("spx_shutdown: ipxp == NULL")); cb = ipxtospxpcb(ipxp); socantsendmore(so); @@ -1664,6 +1671,8 @@ int error; struct ipxpcb *ipxp; + KASSERT(so->so_pcb == NULL, ("spx_sp_attach: so_pcb != NULL")); + error = spx_attach(so, proto, td); if (error == 0) { ipxp = sotoipxpcb(so); --- //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 2005/08/09 10:22:44 +++ //depot/user/rwatson/sockref/src/sys/netnatm/natm.c 2006/02/15 20:31:08 @@ -74,7 +74,7 @@ * user requests */ static int natm_usr_attach(struct socket *, int, d_thread_t *); -static int natm_usr_detach(struct socket *); +static void natm_usr_detach(struct socket *); static int natm_usr_connect(struct socket *, struct sockaddr *, d_thread_t *); static int natm_usr_disconnect(struct socket *); static int natm_usr_shutdown(struct socket *); @@ -83,7 +83,7 @@ static int natm_usr_peeraddr(struct socket *, struct sockaddr **); static int natm_usr_control(struct socket *, u_long, caddr_t, struct ifnet *, d_thread_t *); -static int natm_usr_abort(struct socket *); +static void natm_usr_abort(struct socket *); static int natm_usr_bind(struct socket *, struct sockaddr *, d_thread_t *); static int natm_usr_sockaddr(struct socket *, struct sockaddr **); @@ -94,7 +94,6 @@ int error = 0; npcb = (struct natmpcb *)so->so_pcb; - KASSERT(npcb == NULL, ("natm_usr_attach: so_pcb != NULL")); if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { @@ -112,31 +111,17 @@ return (error); } -static int +static void natm_usr_detach(struct socket *so) { struct natmpcb *npcb; - int error = 0; NATM_LOCK(); npcb = (struct natmpcb *)so->so_pcb; - if (npcb == NULL) { - /* XXXRW: Does this case ever actually happen? */ - error = EINVAL; - goto out; - } - - /* - * we turn on 'drain' *before* we sofree. - */ + KASSERT(npcb != NULL, ("natm_usr_detach: npcb == NULL")); npcb_free(npcb, NPCB_DESTROY); /* drain */ - ACCEPT_LOCK(); - SOCK_LOCK(so); so->so_pcb = NULL; - sotryfree(so); - out: NATM_UNLOCK(); - return (error); } static int @@ -151,11 +136,7 @@ NATM_LOCK(); npcb = (struct natmpcb *)so->so_pcb; - if (npcb == NULL) { - /* XXXRW: Does this case ever actually happen? */ - error = EINVAL; - goto out; - } + KASSERT(npcb != NULL, ("natm_usr_connect: npcb == NULL")); /* * validate nam and npcb @@ -212,18 +193,14 @@ if (ifp->if_ioctl == NULL || ifp->if_ioctl(ifp, SIOCATMOPENVCC, (caddr_t)&op) != 0) { IFF_UNLOCKGIANT(ifp); - NATM_LOCK(); - npcb_free(npcb, NPCB_REMOVE); error = EIO; goto out; } IFF_UNLOCKGIANT(ifp); - NATM_LOCK(); soisconnected(so); out: - NATM_UNLOCK(); return (error); } @@ -237,11 +214,7 @@ NATM_LOCK(); npcb = (struct natmpcb *)so->so_pcb; - if (npcb == NULL) { - /* XXXRW: Does this case ever actually happen? */ - error = EINVAL; - goto out; - } + KASSERT(npcb != NULL, ("natm_usr_disconnect: npcb == NULL")); if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) { printf("natm: disconnected check\n"); @@ -263,7 +236,6 @@ } NATM_LOCK(); - npcb_free(npcb, NPCB_REMOVE); soisdisconnected(so); out: @@ -289,11 +261,7 @@ NATM_LOCK(); npcb = (struct natmpcb *)so->so_pcb; - if (npcb == NULL) { - /* XXXRW: Does this case ever actually happen? */ - error = EINVAL; - goto out; - } + KASSERT(npcb != NULL, ("natm_usr_send: npcb == NULL")); if (control && control->m_len) { m_freem(control); @@ -330,11 +298,7 @@ NATM_LOCK(); npcb = (struct natmpcb *)so->so_pcb; - if (npcb == NULL) { - /* XXXRW: Does this case ever actually happen? */ - NATM_UNLOCK(); - return (EINVAL); - } + KASSERT(npcb != NULL, ("natm_usr_peeraddr: npcb == NULL")); snatm = &ssnatm; bzero(snatm, sizeof(*snatm)); @@ -356,13 +320,8 @@ struct natmpcb *npcb; int error; - /* - * XXXRW: Does this case ever actually happen? And does it even matter - * given that npcb is unused? - */ npcb = (struct natmpcb *)so->so_pcb; - if (npcb == NULL) - return (EINVAL); + KASSERT(npcb != NULL, ("natm_usr_control: npcb == NULL")); if (ifp == NULL || ifp->if_ioctl == NULL) return (EOPNOTSUPP); @@ -373,10 +332,10 @@ return (error); } -static int +static void natm_usr_abort(struct socket *so) { - return (natm_usr_shutdown(so)); + natm_usr_shutdown(so); } static int --- //depot/vendor/freebsd/src/sys/sys/protosw.h 2005/10/30 19:45:29 +++ //depot/user/rwatson/sockref/src/sys/sys/protosw.h 2006/02/13 21:54:01 @@ -196,7 +196,7 @@ */ struct pr_usrreqs { double __Break_the_struct_layout_for_now; - int (*pru_abort)(struct socket *so); + void (*pru_abort)(struct socket *so); int (*pru_accept)(struct socket *so, struct sockaddr **nam); int (*pru_attach)(struct socket *so, int proto, struct thread *td); int (*pru_bind)(struct socket *so, struct sockaddr *nam, @@ -206,7 +206,7 @@ int (*pru_connect2)(struct socket *so1, struct socket *so2); int (*pru_control)(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td); - int (*pru_detach)(struct socket *so); + void (*pru_detach)(struct socket *so); int (*pru_disconnect)(struct socket *so); int (*pru_listen)(struct socket *so, int backlog, struct thread *td); @@ -246,7 +246,7 @@ * All nonvoid pru_*() functions below return EOPNOTSUPP. */ -int pru_abort_notsupp(struct socket *so); +void pru_abort_notsupp(struct socket *so); int pru_accept_notsupp(struct socket *so, struct sockaddr **nam); int pru_attach_notsupp(struct socket *so, int proto, struct thread *td); int pru_bind_notsupp(struct socket *so, struct sockaddr *nam, @@ -256,7 +256,7 @@ int pru_connect2_notsupp(struct socket *so1, struct socket *so2); int pru_control_notsupp(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td); -int pru_detach_notsupp(struct socket *so); +void pru_detach_notsupp(struct socket *so); int pru_disconnect_notsupp(struct socket *so); int pru_listen_notsupp(struct socket *so, int backlog, struct thread *td); int pru_peeraddr_notsupp(struct socket *so, struct sockaddr **nam); --- //depot/vendor/freebsd/src/sys/sys/socketvar.h 2006/01/13 11:03:11 +++ //depot/user/rwatson/sockref/src/sys/sys/socketvar.h 2006/02/19 15:46:04 @@ -208,6 +208,14 @@ #define SS_ASYNC 0x0200 /* async i/o notify */ #define SS_ISCONFIRMING 0x0400 /* deciding to accept connection req */ #define SS_ISDISCONNECTED 0x2000 /* socket disconnected from peer */ +/* + * Protocols can mark a socket as SS_PROTOREF to indicate that, following + * pru_detach, they still want the socket to persist, and will free it + * themselves when they are done. Protocols should only ever call sofree() + * following setting this flag in pru_detach(), and never otherwise, as + * sofree() bypasses socket reference counting. + */ +#define SS_PROTOREF 0x4000 /* strong protocol reference present */ /* * Socket state bits now stored in the socket buffer state field. @@ -486,7 +494,7 @@ void sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb); int sbwait(struct sockbuf *sb); int sb_lock(struct sockbuf *sb); -int soabort(struct socket *so); +void soabort(struct socket *so); int soaccept(struct socket *so, struct sockaddr **nam); struct socket *soalloc(int mflags); int socheckuid(struct socket *so, uid_t uid);