summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2006-07-21 17:11:15 +0000
committerrwatson <rwatson@FreeBSD.org>2006-07-21 17:11:15 +0000
commit720efebbba89f0ed3381913203af601ee17ba25f (patch)
treec584d49beb0289bc5110816075b0f48383df5bfd
parentec82ec19cb2d1e5f72d91c4479b80a91ec859f6e (diff)
downloadFreeBSD-src-720efebbba89f0ed3381913203af601ee17ba25f.zip
FreeBSD-src-720efebbba89f0ed3381913203af601ee17ba25f.tar.gz
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
-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 4d5936a..6e203d1 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 2c72223..02b641a 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 4f2f006..b584860 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 76913a5..8ab39e4 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 1421c8d..1876856 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 f21ad798..a0534b7 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 8facb95..ad14e84 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 0f28377..b8e98b3 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 a8523ab..deea5b3 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 1939964..a1fdb27 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 16b9a20..3029ffd 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 922184a..6513757 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 21d3766..f6d6fb2 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 85700f9..1bac6d9 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 982705f..4e599cf 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 72bff98..6229739 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 f635c89..dfe1c68 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 676b22e..64574cf 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 676b22e..64574cf 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 111a983..549627b 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 7fff2b6..695a7e1 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 86ff948..cab78eb 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 f031b96..005c2d5 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 a590f1e..b93d6d6 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 489014a..84de629 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 d9a5639..9400df2 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 6a1cb11..abf59d3 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 df4ac2f..2496420 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,
};
/*
OpenPOWER on IntegriCloud