diff options
author | rwatson <rwatson@FreeBSD.org> | 2006-04-25 11:17:35 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2006-04-25 11:17:35 +0000 |
commit | 5d598011b534415b6bfa0b82fe291c836516bbd0 (patch) | |
tree | ac3c32c6d4a4115de24383a3ecb36ad35f4fff67 | |
parent | 38b8fecaba7630458a55dc2790b6057e3ee53b53 (diff) | |
download | FreeBSD-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
-rw-r--r-- | sys/netinet/in_pcb.c | 28 | ||||
-rw-r--r-- | sys/netinet/in_pcb.h | 1 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 5 | ||||
-rw-r--r-- | sys/netinet/tcp_timewait.c | 5 |
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) { |