aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Watson <rwatson@FreeBSD.org>2006-07-21 17:11:15 +0000
committerRobert Watson <rwatson@FreeBSD.org>2006-07-21 17:11:15 +0000
commita152f8a36128ce99cc252941396d7db06ec7084e (patch)
treec584d49beb0289bc5110816075b0f48383df5bfd
parent05a7329cbad79bc2d72b63eee9badbdb4deff62d (diff)
downloadsrc-a152f8a36128ce99cc252941396d7db06ec7084e.tar.gz
src-a152f8a36128ce99cc252941396d7db06ec7084e.zip
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
Notes
Notes: svn path=/head/; revision=160549
-rw-r--r--sys/kern/uipc_socket.c11
-rw-r--r--sys/kern/uipc_usrreq.c19
-rw-r--r--sys/net/raw_usrreq.c12
-rw-r--r--sys/net/rtsock.c8
-rw-r--r--sys/netatalk/ddp_usrreq.c23
-rw-r--r--sys/netatm/atm_aal5.c15
-rw-r--r--sys/netatm/atm_usrreq.c1
-rw-r--r--sys/netgraph/bluetooth/include/ng_btsocket_hci_raw.h1
-rw-r--r--sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h2
-rw-r--r--sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h1
-rw-r--r--sys/netgraph/bluetooth/socket/ng_btsocket.c4
-rw-r--r--sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c6
-rw-r--r--sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c9
-rw-r--r--sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c10
-rw-r--r--sys/netgraph/bluetooth/socket/ng_btsocket_rfcomm.c11
-rw-r--r--sys/netgraph/ng_socket.c4
-rw-r--r--sys/netinet/raw_ip.c49
-rw-r--r--sys/netinet/tcp_subr.c49
-rw-r--r--sys/netinet/tcp_timewait.c49
-rw-r--r--sys/netinet/tcp_usrreq.c147
-rw-r--r--sys/netinet/udp_usrreq.c32
-rw-r--r--sys/netinet6/raw_ip6.c24
-rw-r--r--sys/netinet6/udp6_usrreq.c50
-rw-r--r--sys/netipsec/keysock.c12
-rw-r--r--sys/netipx/ipx_usrreq.c21
-rw-r--r--sys/netipx/spx_usrreq.c37
-rw-r--r--sys/netkey/keysock.c12
-rw-r--r--sys/netnatm/natm.c8
28 files changed, 438 insertions, 189 deletions
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 4d5936a7c4d9..6e203d1d3e60 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -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 @@ drop:
* 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);
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index 2c7222398cb6..02b641a89725 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -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
diff --git a/sys/net/raw_usrreq.c b/sys/net/raw_usrreq.c
index 4f2f006757e2..b584860e3d62 100644
--- a/sys/net/raw_usrreq.c
+++ b/sys/net/raw_usrreq.c
@@ -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,
};
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index 76913a57085d..8ab39e49377f 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -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*/
diff --git a/sys/netatalk/ddp_usrreq.c b/sys/netatalk/ddp_usrreq.c
index 1421c8d02a43..187685611ae1 100644
--- a/sys/netatalk/ddp_usrreq.c
+++ b/sys/netatalk/ddp_usrreq.c
@@ -202,6 +202,10 @@ out:
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,
};
diff --git a/sys/netatm/atm_aal5.c b/sys/netatm/atm_aal5.c
index f21ad7980b56..a0534b7d0d26 100644
--- a/sys/netatm/atm_aal5.c
+++ b/sys/netatm/atm_aal5.c
@@ -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();
}
diff --git a/sys/netatm/atm_usrreq.c b/sys/netatm/atm_usrreq.c
index 8facb95994bc..ad14e84a366f 100644
--- a/sys/netatm/atm_usrreq.c
+++ b/sys/netatm/atm_usrreq.c
@@ -79,6 +79,7 @@ struct pr_usrreqs atm_dgram_usrreqs = {
.pru_sosend = NULL,
.pru_soreceive = NULL,
.pru_sopoll = NULL,
+ .pru_close = atm_proto_notsupp5,
};
diff --git a/sys/netgraph/bluetooth/include/ng_btsocket_hci_raw.h b/sys/netgraph/bluetooth/include/ng_btsocket_hci_raw.h
index 0f2837770cb1..b8e98b31e694 100644
--- a/sys/netgraph/bluetooth/include/ng_btsocket_hci_raw.h
+++ b/sys/netgraph/bluetooth/include/ng_btsocket_hci_raw.h
@@ -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 *);
diff --git a/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h b/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h
index a8523ab44f6b..deea5b3db0df 100644
--- a/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h
+++ b/sys/netgraph/bluetooth/include/ng_btsocket_l2cap.h
@@ -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 *,
diff --git a/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h b/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h
index 1939964bbc76..a1fdb2717a13 100644
--- a/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h
+++ b/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h
@@ -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 *,
diff --git a/sys/netgraph/bluetooth/socket/ng_btsocket.c b/sys/netgraph/bluetooth/socket/ng_btsocket.c
index 16b9a208e3d8..3029ffd4c187 100644
--- a/sys/netgraph/bluetooth/socket/ng_btsocket.c
+++ b/sys/netgraph/bluetooth/socket/ng_btsocket.c
@@ -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,
};
/*
diff --git a/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c b/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c
index 922184a25bf0..6513757181e1 100644
--- a/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c
+++ b/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c
@@ -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
*/
diff --git a/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c b/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c
index 21d3766eb742..f6d6fb2b8456 100644
--- a/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c
+++ b/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap.c
@@ -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.
diff --git a/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c b/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c
index 85700f981c68..1bac6d916d55 100644
--- a/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c
+++ b/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c
@@ -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
*/
diff --git a/sys/netgraph/bluetooth/socket/ng_btsocket_rfcomm.c b/sys/netgraph/bluetooth/socket/ng_btsocket_rfcomm.c
index 982705fbf7f0..4e599cf03281 100644
--- a/sys/netgraph/bluetooth/socket/ng_btsocket_rfcomm.c
+++ b/sys/netgraph/bluetooth/socket/ng_btsocket_rfcomm.c
@@ -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.
diff --git a/sys/netgraph/ng_socket.c b/sys/netgraph/ng_socket.c
index 72bff98f6da4..622973929cae 100644
--- a/sys/netgraph/ng_socket.c
+++ b/sys/netgraph/ng_socket.c
@@ -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,
};
/*
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index f635c8959c34..dfe1c6831a36 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -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,32 +641,48 @@ 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)
+{
+
+ INP_LOCK_ASSERT(inp);
+
+ inp->inp_faddr.s_addr = INADDR_ANY;
+ SOCK_LOCK(so);
+ so->so_state &= ~SS_ISCONNECTED;
+ SOCK_UNLOCK(so);
+}
+
+static void
+rip_abort(struct socket *so)
{
struct inpcb *inp;
inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("rip_detach: inp == NULL"));
+ KASSERT(inp != NULL, ("rip_abort: inp == NULL"));
+
INP_INFO_WLOCK(&ripcbinfo);
INP_LOCK(inp);
- rip_pcbdetach(so, inp);
+ rip_dodisconnect(so, inp);
+ INP_UNLOCK(inp);
INP_INFO_WUNLOCK(&ripcbinfo);
}
static void
-rip_abort(struct socket *so)
+rip_close(struct socket *so)
{
struct inpcb *inp;
inp = sotoinpcb(so);
- KASSERT(inp != NULL, ("rip_abort: inp == NULL"));
+ KASSERT(inp != NULL, ("rip_close: 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);
}
@@ -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,
};
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 676b22e15d94..64574cf9f1f7 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -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,
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index 676b22e15d94..64574cf9f1f7 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -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,
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 111a9830f809..549627bf7992 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -137,12 +137,13 @@ out:
}
/*
- * 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 @@ out:
}
/*
- * 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 */
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 7fff2b62507e..695a7e1569de 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -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,
};
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 86ff948f7902..cab78ebcef86 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -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,
};
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index f031b9690eb4..005c2d597633 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -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 @@ out:
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
};
diff --git a/sys/netipsec/keysock.c b/sys/netipsec/keysock.c
index a590f1ef43d0..b93d6d69d1e3 100644
--- a/sys/netipsec/keysock.c
+++ b/sys/netipsec/keysock.c
@@ -439,6 +439,17 @@ key_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
}
/*
+ * 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 */
diff --git a/sys/netipx/ipx_usrreq.c b/sys/netipx/ipx_usrreq.c
index 489014a0d5c1..84de6294594d 100644
--- a/sys/netipx/ipx_usrreq.c
+++ b/sys/netipx/ipx_usrreq.c
@@ -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);
diff --git a/sys/netipx/spx_usrreq.c b/sys/netipx/spx_usrreq.c
index d9a56397e8f0..9400df276175 100644
--- a/sys/netipx/spx_usrreq.c
+++ b/sys/netipx/spx_usrreq.c
@@ -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 @@ out:
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();
}
diff --git a/sys/netkey/keysock.c b/sys/netkey/keysock.c
index 6a1cb111c584..abf59d3f27c3 100644
--- a/sys/netkey/keysock.c
+++ b/sys/netkey/keysock.c
@@ -348,6 +348,17 @@ key_bind(struct socket *so, struct sockaddr *nam, struct thread *p)
}
/*
+ * 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 */
diff --git a/sys/netnatm/natm.c b/sys/netnatm/natm.c
index df4ac2ff14b3..249642076da4 100644
--- a/sys/netnatm/natm.c
+++ b/sys/netnatm/natm.c
@@ -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,
};
/*