From 5d598011b534415b6bfa0b82fe291c836516bbd0 Mon Sep 17 00:00:00 2001 From: rwatson Date: Tue, 25 Apr 2006 11:17:35 +0000 Subject: 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 --- sys/netinet/in_pcb.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'sys/netinet/in_pcb.c') 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) { -- cgit v1.1