Change semantics of socket close and detach. Add a new protocol switch

function, pru_close, to notify protocols that the file descriptor or
other consumer of a socket is closing the socket.  pru_abort is now a
notification of close also, and no longer detaches.  pru_detach is no
longer used to notify of close, and will be called during socket
tear-down by sofree() when all references to a socket evaporate after
an earlier call to abort or close the socket.  This means detach is now
an unconditional teardown of a socket, whereas previously sockets could
persist after detach of the protocol retained a reference.

This faciliates sharing mutexes between layers of the network stack as
the mutex is required during the checking and removal of references at
the head of sofree().  With this change, pru_detach can now assume that
the mutex will no longer be required by the socket layer after
completion, whereas before this was not necessarily true.

Reviewed by:	gnn
This commit is contained in:
Robert Watson 2006-07-21 17:11:15 +00:00
parent 05a7329cba
commit a152f8a361
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=160549
28 changed files with 441 additions and 192 deletions

View File

@ -589,6 +589,8 @@ sofree(so)
sorflush(so);
knlist_destroy(&so->so_rcv.sb_sel.si_note);
knlist_destroy(&so->so_snd.sb_sel.si_note);
if (so->so_proto->pr_usrreqs->pru_detach != NULL)
(*so->so_proto->pr_usrreqs->pru_detach)(so);
sodealloc(so);
}
@ -653,8 +655,8 @@ soclose(so)
}
drop:
if (*so->so_proto->pr_usrreqs->pru_detach != NULL)
(*so->so_proto->pr_usrreqs->pru_detach)(so);
if (so->so_proto->pr_usrreqs->pru_close != NULL)
(*so->so_proto->pr_usrreqs->pru_close)(so);
ACCEPT_LOCK();
SOCK_LOCK(so);
KASSERT((so->so_state & SS_NOFDREF) == 0, ("soclose: NOFDREF"));
@ -676,9 +678,6 @@ soclose(so)
* with any socket locks held. Protocols do call it while holding their own
* recursible protocol mutexes, but this is something that should be subject
* to review in the future.
*
* XXXRW: Why do we maintain a distinction between pru_abort() and
* pru_detach()?
*/
void
soabort(so)
@ -697,7 +696,7 @@ soabort(so)
KASSERT((so->so_state & SQ_COMP) == 0, ("soabort: SQ_COMP"));
KASSERT((so->so_state & SQ_INCOMP) == 0, ("soabort: SQ_INCOMP"));
if (*so->so_proto->pr_usrreqs->pru_abort != NULL)
if (so->so_proto->pr_usrreqs->pru_abort != NULL)
(*so->so_proto->pr_usrreqs->pru_abort)(so);
ACCEPT_LOCK();
SOCK_LOCK(so);

View File

@ -149,8 +149,7 @@ uipc_abort(struct socket *so)
KASSERT(unp != NULL, ("uipc_abort: unp == NULL"));
UNP_LOCK();
unp_drop(unp, ECONNABORTED);
unp_detach(unp);
UNP_UNLOCK_ASSERT();
UNP_UNLOCK();
}
static int
@ -210,6 +209,21 @@ uipc_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
return (error);
}
/*
* XXXRW: Should also unbind?
*/
static void
uipc_close(struct socket *so)
{
struct unpcb *unp;
unp = sotounpcb(so);
KASSERT(unp != NULL, ("uipc_close: unp == NULL"));
UNP_LOCK();
unp_disconnect(unp);
UNP_UNLOCK();
}
int
uipc_connect2(struct socket *so1, struct socket *so2)
{
@ -565,6 +579,7 @@ struct pr_usrreqs uipc_usrreqs = {
.pru_sosend = sosend,
.pru_soreceive = soreceive,
.pru_sopoll = sopoll,
.pru_close = uipc_close,
};
int

View File

@ -146,7 +146,16 @@ raw_uabort(struct socket *so)
KASSERT(rp != NULL, ("raw_uabort: rp == NULL"));
raw_disconnect(rp);
soisdisconnected(so);
raw_detach(rp);
}
static void
raw_uclose(struct socket *so)
{
struct rawcb *rp = sotorawcb(so);
KASSERT(rp != NULL, ("raw_uabort: rp == NULL"));
raw_disconnect(rp);
soisdisconnected(so);
}
/* pru_accept is EOPNOTSUPP */
@ -295,4 +304,5 @@ struct pr_usrreqs raw_usrreqs = {
.pru_send = raw_usend,
.pru_shutdown = raw_ushutdown,
.pru_sockaddr = raw_usockaddr,
.pru_close = raw_uclose,
};

View File

@ -144,6 +144,13 @@ rts_abort(struct socket *so)
raw_usrreqs.pru_abort(so);
}
static void
rts_close(struct socket *so)
{
raw_usrreqs.pru_close(so);
}
/* pru_accept is EOPNOTSUPP */
static int
@ -292,6 +299,7 @@ static struct pr_usrreqs route_usrreqs = {
.pru_send = rts_send,
.pru_shutdown = rts_shutdown,
.pru_sockaddr = rts_sockaddr,
.pru_close = rts_close,
};
/*ARGSUSED*/

View File

@ -202,6 +202,10 @@ ddp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
return (error);
}
/*
* XXXRW: This is never called because we only invoke abort on stream
* protocols.
*/
static void
ddp_abort(struct socket *so)
{
@ -210,10 +214,22 @@ ddp_abort(struct socket *so)
ddp = sotoddpcb(so);
KASSERT(ddp != NULL, ("ddp_abort: ddp == NULL"));
DDP_LIST_XLOCK();
DDP_LOCK(ddp);
at_pcbdetach(so, ddp);
DDP_LIST_XUNLOCK();
at_pcbdisconnect(ddp);
DDP_UNLOCK(ddp);
}
static void
ddp_close(struct socket *so)
{
struct ddpcb *ddp;
ddp = sotoddpcb(so);
KASSERT(ddp != NULL, ("ddp_close: ddp == NULL"));
DDP_LOCK(ddp);
at_pcbdisconnect(ddp);
DDP_UNLOCK(ddp);
}
void
@ -276,4 +292,5 @@ struct pr_usrreqs ddp_usrreqs = {
.pru_send = ddp_send,
.pru_shutdown = ddp_shutdown,
.pru_sockaddr = at_setsockaddr,
.pru_close = ddp_close,
};

View File

@ -88,6 +88,7 @@ static int atm_aal5_incoming(void *, Atm_connection *,
Atm_attributes *, void **);
static void atm_aal5_cpcs_data(void *, KBuffer *);
static caddr_t atm_aal5_getname(void *);
static void atm_aal5_close(struct socket *);
/*
@ -108,6 +109,7 @@ struct pr_usrreqs atm_aal5_usrreqs = {
.pru_sense = atm_aal5_sense,
.pru_shutdown = atm_aal5_shutdown,
.pru_sockaddr = atm_aal5_sockaddr,
.pru_close = atm_aal5_close,
};
/*
@ -565,8 +567,19 @@ atm_aal5_abort(so)
{
ATM_INTRO_NOERR("abort");
(void)atm_sock_disconnect(so);
so->so_error = ECONNABORTED;
atm_sock_detach(so);
ATM_OUTRO_NOERR();
}
static void
atm_aal5_close(so)
struct socket *so;
{
ATM_INTRO_NOERR("close");
(void)atm_sock_disconnect(so);
ATM_OUTRO_NOERR();
}

View File

@ -79,6 +79,7 @@ struct pr_usrreqs atm_dgram_usrreqs = {
.pru_sosend = NULL,
.pru_soreceive = NULL,
.pru_sopoll = NULL,
.pru_close = atm_proto_notsupp5,
};

View File

@ -67,6 +67,7 @@ typedef struct ng_btsocket_hci_raw_pcb * ng_btsocket_hci_raw_pcb_p;
void ng_btsocket_hci_raw_init (void);
void ng_btsocket_hci_raw_abort (struct socket *);
void ng_btsocket_hci_raw_close (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 *);

View File

@ -93,6 +93,7 @@ typedef struct ng_btsocket_l2cap_raw_pcb * ng_btsocket_l2cap_raw_pcb_p;
void ng_btsocket_l2cap_raw_init (void);
void ng_btsocket_l2cap_raw_abort (struct socket *);
void ng_btsocket_l2cap_raw_close (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 *);
@ -184,6 +185,7 @@ typedef struct ng_btsocket_l2cap_pcb * ng_btsocket_l2cap_pcb_p;
void ng_btsocket_l2cap_init (void);
void ng_btsocket_l2cap_abort (struct socket *);
void ng_btsocket_l2cap_close (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 *,

View File

@ -315,6 +315,7 @@ typedef struct ng_btsocket_rfcomm_pcb * ng_btsocket_rfcomm_pcb_p;
void ng_btsocket_rfcomm_init (void);
void ng_btsocket_rfcomm_abort (struct socket *);
void ng_btsocket_rfcomm_close (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 *,

View File

@ -74,6 +74,7 @@ static struct pr_usrreqs ng_btsocket_hci_raw_usrreqs = {
.pru_send = ng_btsocket_hci_raw_send,
.pru_shutdown = NULL,
.pru_sockaddr = ng_btsocket_hci_raw_sockaddr,
.pru_close = ng_btsocket_hci_raw_close,
};
/*
@ -92,6 +93,7 @@ static struct pr_usrreqs ng_btsocket_l2cap_raw_usrreqs = {
.pru_send = ng_btsocket_l2cap_raw_send,
.pru_shutdown = NULL,
.pru_sockaddr = ng_btsocket_l2cap_raw_sockaddr,
.pru_close = ng_btsocket_l2cap_raw_close,
};
/*
@ -112,6 +114,7 @@ static struct pr_usrreqs ng_btsocket_l2cap_usrreqs = {
.pru_send = ng_btsocket_l2cap_send,
.pru_shutdown = NULL,
.pru_sockaddr = ng_btsocket_l2cap_sockaddr,
.pru_close = ng_btsocket_l2cap_close,
};
/*
@ -132,6 +135,7 @@ static struct pr_usrreqs ng_btsocket_rfcomm_usrreqs = {
.pru_send = ng_btsocket_rfcomm_send,
.pru_shutdown = NULL,
.pru_sockaddr = ng_btsocket_rfcomm_sockaddr,
.pru_close = ng_btsocket_rfcomm_close,
};
/*

View File

@ -876,9 +876,13 @@ ng_btsocket_hci_raw_init(void)
void
ng_btsocket_hci_raw_abort(struct socket *so)
{
ng_btsocket_hci_raw_detach(so);
} /* ng_btsocket_hci_raw_abort */
void
ng_btsocket_hci_raw_close(struct socket *so)
{
} /* ng_btsocket_hci_raw_close */
/*
* Create new raw HCI socket
*/

View File

@ -1917,9 +1917,16 @@ ng_btsocket_l2cap_abort(struct socket *so)
{
so->so_error = ECONNABORTED;
ng_btsocket_l2cap_detach(so);
(void)ng_btsocket_l2cap_disconnect(so);
} /* ng_btsocket_l2cap_abort */
void
ng_btsocket_l2cap_close(struct socket *so)
{
(void)ng_btsocket_l2cap_disconnect(so);
} /* ng_btsocket_l2cap_close */
/*
* Accept connection on socket. Nothing to do here, socket must be connected
* and ready, so just return peer address and be done with it.

View File

@ -575,9 +575,17 @@ ng_btsocket_l2cap_raw_init(void)
void
ng_btsocket_l2cap_raw_abort(struct socket *so)
{
ng_btsocket_l2cap_raw_detach(so);
(void)ng_btsocket_l2cap_raw_disconnect(so);
} /* ng_btsocket_l2cap_raw_abort */
void
ng_btsocket_l2cap_raw_close(struct socket *so)
{
(void)ng_btsocket_l2cap_raw_disconnect(so);
} /* ng_btsocket_l2cap_raw_close */
/*
* Create and attach new socket
*/

View File

@ -346,11 +346,18 @@ ng_btsocket_rfcomm_init(void)
void
ng_btsocket_rfcomm_abort(struct socket *so)
{
so->so_error = ECONNABORTED;
ng_btsocket_rfcomm_detach(so);
so->so_error = ECONNABORTED;
(void)ng_btsocket_rfcomm_disconnect(so);
} /* ng_btsocket_rfcomm_abort */
void
ng_btsocket_rfcomm_close(struct socket *so)
{
(void)ng_btsocket_rfcomm_disconnect(so);
} /* ng_btsocket_rfcomm_close */
/*
* Accept connection on socket. Nothing to do here, socket must be connected
* and ready, so just return peer address and be done with it.

View File

@ -1087,6 +1087,8 @@ dummy_disconnect(struct socket *so)
}
/*
* Control and data socket type descriptors
*
* XXXRW: Perhaps _close should do something?
*/
static struct pr_usrreqs ngc_usrreqs = {
@ -1100,6 +1102,7 @@ static struct pr_usrreqs ngc_usrreqs = {
.pru_send = ngc_send,
.pru_shutdown = NULL,
.pru_sockaddr = ng_setsockaddr,
.pru_close = NULL,
};
static struct pr_usrreqs ngd_usrreqs = {
@ -1113,6 +1116,7 @@ static struct pr_usrreqs ngd_usrreqs = {
.pru_send = ngd_send,
.pru_shutdown = NULL,
.pru_sockaddr = ng_setsockaddr,
.pru_close = NULL,
};
/*

View File

@ -622,12 +622,17 @@ rip_attach(struct socket *so, int proto, struct thread *td)
}
static void
rip_pcbdetach(struct socket *so, struct inpcb *inp)
rip_detach(struct socket *so)
{
struct inpcb *inp;
INP_INFO_WLOCK_ASSERT(&ripcbinfo);
INP_LOCK_ASSERT(inp);
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("rip_detach: inp == NULL"));
KASSERT(inp->inp_faddr.s_addr == INADDR_ANY,
("rip_detach: not closed"));
INP_INFO_WLOCK(&ripcbinfo);
INP_LOCK(inp);
if (so == ip_mrouter && ip_mrouter_done)
ip_mrouter_done();
if (ip_rsvp_force_done)
@ -636,19 +641,19 @@ rip_pcbdetach(struct socket *so, struct inpcb *inp)
ip_rsvp_done();
in_pcbdetach(inp);
in_pcbfree(inp);
INP_INFO_WUNLOCK(&ripcbinfo);
}
static void
rip_detach(struct socket *so)
rip_dodisconnect(struct socket *so, struct inpcb *inp)
{
struct inpcb *inp;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("rip_detach: inp == NULL"));
INP_INFO_WLOCK(&ripcbinfo);
INP_LOCK(inp);
rip_pcbdetach(so, inp);
INP_INFO_WUNLOCK(&ripcbinfo);
INP_LOCK_ASSERT(inp);
inp->inp_faddr.s_addr = INADDR_ANY;
SOCK_LOCK(so);
so->so_state &= ~SS_ISCONNECTED;
SOCK_UNLOCK(so);
}
static void
@ -658,10 +663,26 @@ rip_abort(struct socket *so)
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("rip_abort: inp == NULL"));
INP_INFO_WLOCK(&ripcbinfo);
INP_LOCK(inp);
soisdisconnected(so);
rip_pcbdetach(so, inp);
rip_dodisconnect(so, inp);
INP_UNLOCK(inp);
INP_INFO_WUNLOCK(&ripcbinfo);
}
static void
rip_close(struct socket *so)
{
struct inpcb *inp;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("rip_close: inp == NULL"));
INP_INFO_WLOCK(&ripcbinfo);
INP_LOCK(inp);
rip_dodisconnect(so, inp);
INP_UNLOCK(inp);
INP_INFO_WUNLOCK(&ripcbinfo);
}
@ -677,10 +698,7 @@ rip_disconnect(struct socket *so)
KASSERT(inp != NULL, ("rip_disconnect: inp == NULL"));
INP_INFO_WLOCK(&ripcbinfo);
INP_LOCK(inp);
inp->inp_faddr.s_addr = INADDR_ANY;
SOCK_LOCK(so);
so->so_state &= ~SS_ISCONNECTED;
SOCK_UNLOCK(so);
rip_dodisconnect(so, inp);
INP_UNLOCK(inp);
INP_INFO_WUNLOCK(&ripcbinfo);
return (0);
@ -912,5 +930,6 @@ struct pr_usrreqs rip_usrreqs = {
.pru_send = rip_send,
.pru_shutdown = rip_shutdown,
.pru_sockaddr = rip_sockaddr,
.pru_sosetlabel = in_pcbsosetlabel
.pru_sosetlabel = in_pcbsosetlabel,
.pru_close = rip_close,
};

View File

@ -808,18 +808,7 @@ tcp_close(struct tcpcb *tp)
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
}
#endif
INP_UNLOCK(inp);
ACCEPT_LOCK();
SOCK_LOCK(so);
so->so_state &= ~SS_PROTOREF;
@ -1789,12 +1778,6 @@ tcp_twstart(struct tcpcb *tp)
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);
@ -1847,12 +1830,11 @@ tcp_twclose(struct tcptw *tw, int reuse)
/*
* At this point, we are in one of two situations:
*
* (1) We have no socket, just an inpcb<->twtcp pair. Release it all
* after validating.
* (1) We have no socket, just an inpcb<->twtcp pair. We can free
* all state.
*
* (2) We have a socket, which we may or may now own the reference
* for. If we own the reference, release all the state after
* validating. If not, leave it for the socket close to clean up.
* (2) We have a socket -- if we own a reference, release it and
* notify the socket layer.
*/
inp = tw->tw_inpcb;
KASSERT((inp->inp_vflag & INP_TIMEWAIT), ("tcp_twclose: !timewait"));
@ -1867,22 +1849,15 @@ tcp_twclose(struct tcptw *tw, int reuse)
so = inp->inp_socket;
if (so != NULL) {
/*
* If there's a socket, handle two cases: first, we own a
* strong reference, which we will now release, or we don't
* in which case another reference exists (XXXRW: think
* about this more), and we don't need to take action.
*/
if (inp->inp_vflag & INP_SOCKREF) {
/*
* If a socket is present, and we own the only
* reference, we need to tear down the socket and the
* inpcb.
*/
inp->inp_vflag &= ~INP_SOCKREF;
#ifdef INET6
if (inp->inp_vflag & INP_IPV6PROTO) {
in6_pcbdetach(inp);
in6_pcbfree(inp);
} else {
in_pcbdetach(inp);
in_pcbfree(inp);
}
#endif
INP_UNLOCK(inp);
ACCEPT_LOCK();
SOCK_LOCK(so);
KASSERT(so->so_state & SS_PROTOREF,

View File

@ -808,18 +808,7 @@ tcp_close(struct tcpcb *tp)
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
}
#endif
INP_UNLOCK(inp);
ACCEPT_LOCK();
SOCK_LOCK(so);
so->so_state &= ~SS_PROTOREF;
@ -1789,12 +1778,6 @@ tcp_twstart(struct tcpcb *tp)
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);
@ -1847,12 +1830,11 @@ tcp_twclose(struct tcptw *tw, int reuse)
/*
* At this point, we are in one of two situations:
*
* (1) We have no socket, just an inpcb<->twtcp pair. Release it all
* after validating.
* (1) We have no socket, just an inpcb<->twtcp pair. We can free
* all state.
*
* (2) We have a socket, which we may or may now own the reference
* for. If we own the reference, release all the state after
* validating. If not, leave it for the socket close to clean up.
* (2) We have a socket -- if we own a reference, release it and
* notify the socket layer.
*/
inp = tw->tw_inpcb;
KASSERT((inp->inp_vflag & INP_TIMEWAIT), ("tcp_twclose: !timewait"));
@ -1867,22 +1849,15 @@ tcp_twclose(struct tcptw *tw, int reuse)
so = inp->inp_socket;
if (so != NULL) {
/*
* If there's a socket, handle two cases: first, we own a
* strong reference, which we will now release, or we don't
* in which case another reference exists (XXXRW: think
* about this more), and we don't need to take action.
*/
if (inp->inp_vflag & INP_SOCKREF) {
/*
* If a socket is present, and we own the only
* reference, we need to tear down the socket and the
* inpcb.
*/
inp->inp_vflag &= ~INP_SOCKREF;
#ifdef INET6
if (inp->inp_vflag & INP_IPV6PROTO) {
in6_pcbdetach(inp);
in6_pcbfree(inp);
} else {
in_pcbdetach(inp);
in_pcbfree(inp);
}
#endif
INP_UNLOCK(inp);
ACCEPT_LOCK();
SOCK_LOCK(so);
KASSERT(so->so_state & SS_PROTOREF,

View File

@ -137,12 +137,13 @@ tcp_usr_attach(struct socket *so, int proto, struct thread *td)
}
/*
* tcp_detach() releases any protocol state that can be reasonably released
* when a socket shutdown is requested, and is a shared code path for
* tcp_usr_detach() and tcp_usr_abort(), the two socket close entry points.
* tcp_detach is called when the socket layer loses its final reference
* to the socket, be it a file descriptor reference, a reference from TCP,
* etc. At this point, there is only one case in which we will keep around
* inpcb state: time wait.
*
* Accepts pcbinfo, inpcb locked, will unlock the inpcb (if needed) on
* return.
* This function can probably be re-absorbed back into tcp_usr_detach() now
* that there is a single detach path.
*/
static void
tcp_detach(struct socket *so, struct inpcb *inp)
@ -158,19 +159,24 @@ tcp_detach(struct socket *so, struct inpcb *inp)
KASSERT(so->so_pcb == inp, ("tcp_detach: so_pcb != inp"));
KASSERT(inp->inp_socket == so, ("tcp_detach: inp_socket != so"));
tp = intotcpcb(inp);
if (inp->inp_vflag & INP_TIMEWAIT) {
/*
* There are two cases to handle: one in which the time wait
* state is being discarded (INP_DROPPED), and one in which
* this connection will remain in timewait. In the former,
* it is time to discard all state (except tcptw, which has
* already been discarded by the timewait close code, which
* should be further up the call stack somewhere). In the
* latter case, we detach from the socket, but leave the pcb
* present until timewait ends.
*
* XXXRW: Would it be cleaner to free the tcptw here?
*/
if (inp->inp_vflag & INP_DROPPED) {
/*
* Connection was in time wait and has been dropped;
* the calling path is either via tcp_twclose(), or
* as a result of an eventual soclose() after
* tcp_twclose() has been called. In either case,
* tcp_twclose() has detached the tcptw from the
* inpcb, so we just detach and free the inpcb.
*
* XXXRW: Would it be cleaner to free the tcptw
* here?
*/
KASSERT(tp == NULL, ("tcp_detach: INP_TIMEWAIT && "
"INP_DROPPED && tp != NULL"));
#ifdef INET6
if (isipv6) {
in6_pcbdetach(inp);
@ -183,11 +189,6 @@ tcp_detach(struct socket *so, struct inpcb *inp)
}
#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);
@ -198,20 +199,21 @@ tcp_detach(struct socket *so, struct inpcb *inp)
}
} else {
/*
* If not in timewait, there are two possible paths. First,
* the TCP connection is either embryonic or done, in which
* case we tear down all state. Second, it may still be
* active, in which case we acquire a reference to the socket
* and will free it later when TCP is done.
* If the connection is not in timewait, we consider two
* two conditions: one in which no further processing is
* necessary (dropped || embryonic), and one in which TCP is
* not yet done, but no longer requires the socket, so the
* pcb will persist for the time being.
*
* XXXRW: Does the second case still occur?
*/
tp = intotcpcb(inp);
if (inp->inp_vflag & INP_DROPPED ||
tp->t_state < TCPS_SYN_SENT) {
tcp_discardcb(tp);
#ifdef INET6
if (isipv6) {
in_pcbdetach(inp);
in_pcbfree(inp);
in6_pcbdetach(inp);
in6_pcbfree(inp);
} else {
#endif
in_pcbdetach(inp);
@ -220,11 +222,12 @@ tcp_detach(struct socket *so, struct inpcb *inp)
}
#endif
} else {
SOCK_LOCK(so);
so->so_state |= SS_PROTOREF;
SOCK_UNLOCK(so);
inp->inp_vflag |= INP_SOCKREF;
INP_UNLOCK(inp);
#ifdef INET6
if (isipv6)
in6_pcbdetach(inp);
else
#endif
in_pcbdetach(inp);
}
}
}
@ -251,15 +254,6 @@ tcp_usr_detach(struct socket *so)
("tcp_usr_detach: inp_socket == NULL"));
TCPDEBUG1();
/*
* First, if we still have full TCP state, and we're not dropped,
* initiate a disconnect.
*/
if (!(inp->inp_vflag & INP_TIMEWAIT) &&
!(inp->inp_vflag & INP_DROPPED)) {
tp = intotcpcb(inp);
tcp_disconnect(tp);
}
tcp_detach(so, inp);
tp = NULL;
TCPDEBUG2(PRU_DETACH);
@ -926,15 +920,13 @@ tcp_usr_send(struct socket *so, int flags, struct mbuf *m,
}
/*
* Abort the TCP.
*
* First, drop the connection. Then collect state if possible.
* Abort the TCP. Drop the connection abruptly.
*/
static void
tcp_usr_abort(struct socket *so)
{
struct inpcb *inp;
struct tcpcb *tp;
struct tcpcb *tp = NULL;
TCPDEBUG0;
inp = sotoinpcb(so);
@ -944,20 +936,63 @@ tcp_usr_abort(struct socket *so)
INP_LOCK(inp);
KASSERT(inp->inp_socket != NULL,
("tcp_usr_abort: inp_socket == NULL"));
TCPDEBUG1();
/*
* First, if we still have full TCP state, and we're not dropped,
* drop.
* If we still have full TCP state, and we're not dropped, drop.
*/
if (!(inp->inp_vflag & INP_TIMEWAIT) &&
!(inp->inp_vflag & INP_DROPPED)) {
tp = intotcpcb(inp);
TCPDEBUG1();
tcp_drop(tp, ECONNABORTED);
TCPDEBUG2(PRU_ABORT);
}
tcp_detach(so, inp);
tp = NULL;
TCPDEBUG2(PRU_DETACH);
if (!(inp->inp_vflag & INP_DROPPED)) {
SOCK_LOCK(so);
so->so_state |= SS_PROTOREF;
SOCK_UNLOCK(so);
inp->inp_vflag |= INP_SOCKREF;
}
INP_UNLOCK(inp);
INP_INFO_WUNLOCK(&tcbinfo);
}
/*
* TCP socket is closed. Start friendly disconnect.
*/
static void
tcp_usr_close(struct socket *so)
{
struct inpcb *inp;
struct tcpcb *tp = NULL;
TCPDEBUG0;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("tcp_usr_close: inp == NULL"));
INP_INFO_WLOCK(&tcbinfo);
INP_LOCK(inp);
KASSERT(inp->inp_socket != NULL,
("tcp_usr_close: inp_socket == NULL"));
/*
* If we still have full TCP state, and we're not dropped, initiate
* a disconnect.
*/
if (!(inp->inp_vflag & INP_TIMEWAIT) &&
!(inp->inp_vflag & INP_DROPPED)) {
tp = intotcpcb(inp);
TCPDEBUG1();
tcp_disconnect(tp);
TCPDEBUG2(PRU_CLOSE);
}
if (!(inp->inp_vflag & INP_DROPPED)) {
SOCK_LOCK(so);
so->so_state |= SS_PROTOREF;
SOCK_UNLOCK(so);
inp->inp_vflag |= INP_SOCKREF;
}
INP_UNLOCK(inp);
INP_INFO_WUNLOCK(&tcbinfo);
}
@ -1019,7 +1054,8 @@ struct pr_usrreqs tcp_usrreqs = {
.pru_send = tcp_usr_send,
.pru_shutdown = tcp_usr_shutdown,
.pru_sockaddr = tcp_sockaddr,
.pru_sosetlabel = in_pcbsosetlabel
.pru_sosetlabel = in_pcbsosetlabel,
.pru_close = tcp_usr_close,
};
#ifdef INET6
@ -1039,7 +1075,8 @@ struct pr_usrreqs tcp6_usrreqs = {
.pru_send = tcp_usr_send,
.pru_shutdown = tcp_usr_shutdown,
.pru_sockaddr = in6_mapped_sockaddr,
.pru_sosetlabel = in_pcbsosetlabel
.pru_sosetlabel = in_pcbsosetlabel,
.pru_close = tcp_usr_close,
};
#endif /* INET6 */

View File

@ -959,9 +959,12 @@ udp_abort(struct socket *so)
KASSERT(inp != NULL, ("udp_abort: inp == NULL"));
INP_INFO_WLOCK(&udbinfo);
INP_LOCK(inp);
soisdisconnected(so);
in_pcbdetach(inp);
in_pcbfree(inp);
if (inp->inp_faddr.s_addr != INADDR_ANY) {
in_pcbdisconnect(inp);
inp->inp_laddr.s_addr = INADDR_ANY;
soisdisconnected(so);
}
INP_UNLOCK(inp);
INP_INFO_WUNLOCK(&udbinfo);
}
@ -1007,6 +1010,24 @@ udp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
return error;
}
static void
udp_close(struct socket *so)
{
struct inpcb *inp;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp_close: inp == NULL"));
INP_INFO_WLOCK(&udbinfo);
INP_LOCK(inp);
if (inp->inp_faddr.s_addr != INADDR_ANY) {
in_pcbdisconnect(inp);
inp->inp_laddr.s_addr = INADDR_ANY;
soisdisconnected(so);
}
INP_UNLOCK(inp);
INP_INFO_WUNLOCK(&udbinfo);
}
static int
udp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
{
@ -1041,6 +1062,8 @@ udp_detach(struct socket *so)
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp_detach: inp == NULL"));
KASSERT(inp->inp_faddr.s_addr == INADDR_ANY,
("udp_detach: not disconnected"));
INP_INFO_WLOCK(&udbinfo);
INP_LOCK(inp);
in_pcbdetach(inp);
@ -1131,5 +1154,6 @@ struct pr_usrreqs udp_usrreqs = {
.pru_sosend = sosend_dgram,
.pru_shutdown = udp_shutdown,
.pru_sockaddr = udp_sockaddr,
.pru_sosetlabel = in_pcbsosetlabel
.pru_sosetlabel = in_pcbsosetlabel,
.pru_close = udp_close,
};

View File

@ -586,25 +586,42 @@ rip6_detach(struct socket *so)
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("rip6_detach: inp == NULL"));
/* xxx: RSVP */
if (so == ip6_mrouter)
ip6_mrouter_done();
INP_INFO_WLOCK(&ripcbinfo);
INP_LOCK(inp);
if (inp->in6p_icmp6filt) {
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);
}
/* XXXRW: This can't ever be called. */
static void
rip6_abort(struct socket *so)
{
struct inpcb *inp;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("rip6_abort: inp == NULL"));
soisdisconnected(so);
}
static void
rip6_close(struct socket *so)
{
struct inpcb *inp;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("rip6_close: inp == NULL"));
soisdisconnected(so);
rip6_detach(so);
}
static int
@ -794,4 +811,5 @@ struct pr_usrreqs rip6_usrreqs = {
.pru_send = rip6_send,
.pru_shutdown = rip6_shutdown,
.pru_sockaddr = in6_setsockaddr,
.pru_close = rip6_close,
};

View File

@ -480,11 +480,24 @@ udp6_abort(struct socket *so)
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp6_abort: inp == NULL"));
#ifdef INET
if (inp->inp_vflag & INP_IPV4) {
struct pr_usrreqs *pru;
pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
(*pru->pru_abort)(so);
return;
}
#endif
INP_INFO_WLOCK(&udbinfo);
INP_LOCK(inp);
soisdisconnected(so);
in6_pcbdetach(inp);
in6_pcbfree(inp);
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
in6_pcbdisconnect(inp);
inp->in6p_laddr = in6addr_any;
soisdisconnected(so);
}
INP_UNLOCK(inp);
INP_INFO_WUNLOCK(&udbinfo);
}
@ -565,6 +578,34 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
return error;
}
static void
udp6_close(struct socket *so)
{
struct inpcb *inp;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("udp6_close: inp == NULL"));
#ifdef INET
if (inp->inp_vflag & INP_IPV4) {
struct pr_usrreqs *pru;
pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs;
(*pru->pru_disconnect)(so);
return;
}
#endif
INP_INFO_WLOCK(&udbinfo);
INP_LOCK(inp);
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) {
in6_pcbdisconnect(inp);
inp->in6p_laddr = in6addr_any;
soisdisconnected(so);
}
INP_UNLOCK(inp);
INP_INFO_WUNLOCK(&udbinfo);
}
static int
udp6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
{
@ -755,5 +796,6 @@ struct pr_usrreqs udp6_usrreqs = {
.pru_send = udp6_send,
.pru_shutdown = udp_shutdown,
.pru_sockaddr = in6_mapped_sockaddr,
.pru_sosetlabel = in_pcbsosetlabel
.pru_sosetlabel = in_pcbsosetlabel,
.pru_close = udp6_close
};

View File

@ -438,6 +438,17 @@ key_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
return error;
}
/*
* key_close()
* derived from net/rtsock.c:rts_close().
*/
static void
key_abort(struct socket *so)
{
raw_usrreqs.pru_close(so);
}
/*
* key_connect()
* derived from net/rtsock.c:rts_connect()
@ -553,6 +564,7 @@ struct pr_usrreqs key_usrreqs = {
.pru_send = key_send,
.pru_shutdown = key_shutdown,
.pru_sockaddr = key_sockaddr,
.pru_close = key_close,
};
/* sysctl */

View File

@ -88,6 +88,7 @@ static int ipx_send(struct socket *so, int flags, struct mbuf *m,
static int ipx_shutdown(struct socket *so);
static int ripx_attach(struct socket *so, int proto, struct thread *td);
static int ipx_output(struct ipxpcb *ipxp, struct mbuf *m0);
static void ipx_usr_close(struct socket *so);
struct pr_usrreqs ipx_usrreqs = {
.pru_abort = ipx_usr_abort,
@ -101,6 +102,7 @@ struct pr_usrreqs ipx_usrreqs = {
.pru_send = ipx_send,
.pru_shutdown = ipx_shutdown,
.pru_sockaddr = ipx_sockaddr,
.pru_close = ipx_usr_close,
};
struct pr_usrreqs ripx_usrreqs = {
@ -115,6 +117,7 @@ struct pr_usrreqs ripx_usrreqs = {
.pru_send = ipx_send,
.pru_shutdown = ipx_shutdown,
.pru_sockaddr = ipx_sockaddr,
.pru_close = ipx_usr_close,
};
/*
@ -432,14 +435,8 @@ static void
ipx_usr_abort(so)
struct socket *so;
{
struct ipxpcb *ipxp = sotoipxpcb(so);
KASSERT(ipxp != NULL, ("ipx_usr_abort: ipxp == NULL"));
IPX_LIST_LOCK();
IPX_LOCK(ipxp);
ipx_pcbdetach(ipxp);
ipx_pcbfree(ipxp);
IPX_LIST_UNLOCK();
/* XXXRW: Possibly ipx_disconnect() here? */
soisdisconnected(so);
}
@ -482,6 +479,15 @@ ipx_bind(so, nam, td)
return (error);
}
static void
ipx_usr_close(so)
struct socket *so;
{
/* XXXRW: Possibly ipx_disconnect() here? */
soisdisconnected(so);
}
static int
ipx_connect(so, nam, td)
struct socket *so;
@ -513,6 +519,7 @@ ipx_detach(so)
{
struct ipxpcb *ipxp = sotoipxpcb(so);
/* XXXRW: Should assert detached. */
KASSERT(ipxp != NULL, ("ipx_detach: ipxp == NULL"));
IPX_LIST_LOCK();
IPX_LOCK(ipxp);

View File

@ -101,6 +101,7 @@ 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 void spx_usr_close(struct socket *so);
static int spx_connect(struct socket *so, struct sockaddr *nam,
struct thread *td);
static void spx_detach(struct socket *so);
@ -131,6 +132,7 @@ struct pr_usrreqs spx_usrreqs = {
.pru_send = spx_send,
.pru_shutdown = spx_shutdown,
.pru_sockaddr = ipx_sockaddr,
.pru_close = spx_usr_close,
};
struct pr_usrreqs spx_usrreq_sps = {
@ -149,6 +151,7 @@ struct pr_usrreqs spx_usrreq_sps = {
.pru_send = spx_send,
.pru_shutdown = spx_shutdown,
.pru_sockaddr = ipx_sockaddr,
.pru_close = spx_usr_close,
};
void
@ -1320,9 +1323,7 @@ spx_usr_abort(struct socket *so)
IPX_LIST_LOCK();
IPX_LOCK(ipxp);
spx_drop(cb, ECONNABORTED);
spx_pcbdetach(ipxp);
ipx_pcbdetach(ipxp);
ipx_pcbfree(ipxp);
IPX_UNLOCK(ipxp);
IPX_LIST_UNLOCK();
}
@ -1459,6 +1460,28 @@ spx_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
return (error);
}
static void
spx_usr_close(struct socket *so)
{
struct ipxpcb *ipxp;
struct spxpcb *cb;
ipxp = sotoipxpcb(so);
KASSERT(ipxp != NULL, ("spx_usr_close: ipxp == NULL"));
cb = ipxtospxpcb(ipxp);
KASSERT(cb != NULL, ("spx_usr_close: cb == NULL"));
IPX_LIST_LOCK();
IPX_LOCK(ipxp);
if (cb->s_state > TCPS_LISTEN)
spx_disconnect(cb);
else
spx_close(cb);
IPX_UNLOCK(ipxp);
IPX_LIST_UNLOCK();
}
/*
* Initiate connection to peer. Enter SYN_SENT state, and mark socket as
* connecting. Start keep-alive timer, setup prototype header, send initial
@ -1518,6 +1541,9 @@ spx_detach(struct socket *so)
struct ipxpcb *ipxp;
struct spxpcb *cb;
/*
* XXXRW: Should assert appropriately detached.
*/
ipxp = sotoipxpcb(so);
KASSERT(ipxp != NULL, ("spx_detach: ipxp == NULL"));
@ -1526,12 +1552,7 @@ spx_detach(struct socket *so)
IPX_LIST_LOCK();
IPX_LOCK(ipxp);
if (cb->s_state > TCPS_LISTEN)
spx_disconnect(cb);
else
spx_close(cb);
spx_pcbdetach(ipxp);
ipx_pcbdetach(ipxp);
ipx_pcbfree(ipxp);
IPX_LIST_UNLOCK();
}

View File

@ -347,6 +347,17 @@ key_bind(struct socket *so, struct sockaddr *nam, struct thread *p)
return error;
}
/*
* key_close()
* derived from net/rtsock.c:rts_close()
*/
static void
key_close(struct socket *so)
{
raw_usrreqs.pru_close(so);
}
/*
* key_connect()
* derived from net/rtsock.c:rts_connect()
@ -460,6 +471,7 @@ struct pr_usrreqs key_usrreqs = {
.pru_send = key_send,
.pru_shutdown = key_shutdown,
.pru_sockaddr = key_sockaddr,
.pru_close = key_close,
};
/* sysctl */

View File

@ -336,7 +336,12 @@ static void
natm_usr_abort(struct socket *so)
{
natm_usr_detach(so);
}
static void
natm_usr_close(struct socket *so)
{
}
static int
@ -366,6 +371,7 @@ struct pr_usrreqs natm_usrreqs = {
.pru_send = natm_usr_send,
.pru_shutdown = natm_usr_shutdown,
.pru_sockaddr = natm_usr_sockaddr,
.pru_close = natm_usr_close,
};
/*