summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2006-04-25 11:17:35 +0000
committerrwatson <rwatson@FreeBSD.org>2006-04-25 11:17:35 +0000
commit5d598011b534415b6bfa0b82fe291c836516bbd0 (patch)
treeac3c32c6d4a4115de24383a3ecb36ad35f4fff67 /sys/netinet
parent38b8fecaba7630458a55dc2790b6057e3ee53b53 (diff)
downloadFreeBSD-src-5d598011b534415b6bfa0b82fe291c836516bbd0.zip
FreeBSD-src-5d598011b534415b6bfa0b82fe291c836516bbd0.tar.gz
Abstract inpcb drop logic, previously just setting of INP_DROPPED in TCP,
into in_pcbdrop(). Expand logic to detach the inpcb from its bound address/port so that dropping a TCP connection releases the inpcb resource reservation, which since the introduction of socket/pcb reference count updates, has been persisting until the socket closed rather than being released implicitly due to prior freeing of the inpcb on TCP drop. MFC after: 3 months
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/in_pcb.c28
-rw-r--r--sys/netinet/in_pcb.h1
-rw-r--r--sys/netinet/tcp_subr.c5
-rw-r--r--sys/netinet/tcp_timewait.c5
4 files changed, 33 insertions, 6 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 9dac3ec..4fa5c6f 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -728,6 +728,34 @@ in_pcbfree(struct inpcb *inp)
uma_zfree(ipi->ipi_zone, inp);
}
+/*
+ * TCP needs to maintain its inpcb structure after the TCP connection has
+ * been torn down. However, it must be disconnected from the inpcb hashes as
+ * it must not prevent binding of future connections to the same port/ip
+ * combination by other inpcbs.
+ */
+void
+in_pcbdrop(struct inpcb *inp)
+{
+ struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
+
+ INP_INFO_WLOCK_ASSERT(pcbinfo);
+ INP_LOCK_ASSERT(inp);
+
+ inp->inp_vflag |= INP_DROPPED;
+ if (inp->inp_lport) {
+ struct inpcbport *phd = inp->inp_phd;
+
+ LIST_REMOVE(inp, inp_hash);
+ LIST_REMOVE(inp, inp_portlist);
+ if (LIST_FIRST(&phd->phd_pcblist) == NULL) {
+ LIST_REMOVE(phd, phd_hash);
+ free(phd, M_PCB);
+ }
+ inp->inp_lport = 0;
+ }
+}
+
struct sockaddr *
in_sockaddr(in_port_t port, struct in_addr *addr_p)
{
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
index 0b754db..80ae9e9 100644
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -352,6 +352,7 @@ int in_pcbconnect_setup(struct inpcb *, struct sockaddr *, in_addr_t *,
struct ucred *);
void in_pcbdetach(struct inpcb *);
void in_pcbdisconnect(struct inpcb *);
+void in_pcbdrop(struct inpcb *);
void in_pcbfree(struct inpcb *);
int in_pcbinshash(struct inpcb *);
struct inpcb *
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index d768fb3..89bd41c 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -791,8 +791,7 @@ tcp_close(struct tcpcb *tp)
INP_INFO_WLOCK_ASSERT(&tcbinfo);
INP_LOCK_ASSERT(inp);
- inp->inp_vflag |= INP_DROPPED;
-
+ in_pcbdrop(inp);
tcpstat.tcps_closed++;
KASSERT(inp->inp_socket != NULL, ("tcp_close: inp_socket NULL"));
so = inp->inp_socket;
@@ -1852,7 +1851,7 @@ tcp_twclose(struct tcptw *tw, int reuse)
tw->tw_inpcb = NULL;
tcp_timer_2msl_stop(tw);
inp->inp_ppcb = NULL;
- inp->inp_vflag |= INP_DROPPED;
+ in_pcbdrop(inp);
so = inp->inp_socket;
if (so != NULL) {
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index d768fb3..89bd41c 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -791,8 +791,7 @@ tcp_close(struct tcpcb *tp)
INP_INFO_WLOCK_ASSERT(&tcbinfo);
INP_LOCK_ASSERT(inp);
- inp->inp_vflag |= INP_DROPPED;
-
+ in_pcbdrop(inp);
tcpstat.tcps_closed++;
KASSERT(inp->inp_socket != NULL, ("tcp_close: inp_socket NULL"));
so = inp->inp_socket;
@@ -1852,7 +1851,7 @@ tcp_twclose(struct tcptw *tw, int reuse)
tw->tw_inpcb = NULL;
tcp_timer_2msl_stop(tw);
inp->inp_ppcb = NULL;
- inp->inp_vflag |= INP_DROPPED;
+ in_pcbdrop(inp);
so = inp->inp_socket;
if (so != NULL) {
OpenPOWER on IntegriCloud