aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet')
-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
5 files changed, 178 insertions, 148 deletions
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,
};