| 2139 | } |
| 2140 | |
| 2141 | void |
| 2142 | tcp_drain(void) |
| 2143 | { |
| 2144 | VNET_ITERATOR_DECL(vnet_iter); |
| 2145 | |
| 2146 | if (!do_tcpdrain) |
| 2147 | return; |
| 2148 | |
| 2149 | VNET_LIST_RLOCK_NOSLEEP(); |
| 2150 | VNET_FOREACH(vnet_iter) { |
| 2151 | CURVNET_SET(vnet_iter); |
| 2152 | struct inpcb *inpb; |
| 2153 | struct tcpcb *tcpb; |
| 2154 | |
| 2155 | /* |
| 2156 | * Walk the tcpbs, if existing, and flush the reassembly queue, |
| 2157 | * if there is one... |
| 2158 | * XXX: The "Net/3" implementation doesn't imply that the TCP |
| 2159 | * reassembly queue should be flushed, but in a situation |
| 2160 | * where we're really low on mbufs, this is potentially |
| 2161 | * useful. |
| 2162 | */ |
| 2163 | INP_INFO_WLOCK(&V_tcbinfo); |
| 2164 | CK_LIST_FOREACH(inpb, V_tcbinfo.ipi_listhead, inp_list) { |
| 2165 | INP_WLOCK(inpb); |
| 2166 | if (inpb->inp_flags & INP_TIMEWAIT) { |
| 2167 | INP_WUNLOCK(inpb); |
| 2168 | continue; |
| 2169 | } |
| 2170 | if ((tcpb = intotcpcb(inpb)) != NULL) { |
| 2171 | tcp_reass_flush(tcpb); |
| 2172 | tcp_clean_sackreport(tcpb); |
| 2173 | #ifdef TCP_BLACKBOX |
| 2174 | tcp_log_drain(tcpb); |
| 2175 | #endif |
| 2176 | #ifdef TCPPCAP |
| 2177 | if (tcp_pcap_aggressive_free) { |
| 2178 | /* Free the TCP PCAP queues. */ |
| 2179 | tcp_pcap_drain(&(tcpb->t_inpkts)); |
| 2180 | tcp_pcap_drain(&(tcpb->t_outpkts)); |
| 2181 | } |
| 2182 | #endif |
| 2183 | } |
| 2184 | INP_WUNLOCK(inpb); |
| 2185 | } |
| 2186 | INP_INFO_WUNLOCK(&V_tcbinfo); |
| 2187 | CURVNET_RESTORE(); |
| 2188 | } |
| 2189 | VNET_LIST_RUNLOCK_NOSLEEP(); |
| 2190 | } |
| 2191 | |
| 2192 | /* |
| 2193 | * Notify a tcp user of an asynchronous error; |
nothing calls this directly
no test coverage detected