* tcp_usr_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. */
| 219 | * inpcb state: time wait. |
| 220 | */ |
| 221 | static void |
| 222 | tcp_usr_detach(struct socket *so) |
| 223 | { |
| 224 | struct inpcb *inp; |
| 225 | struct tcpcb *tp; |
| 226 | |
| 227 | inp = sotoinpcb(so); |
| 228 | KASSERT(inp != NULL, ("%s: inp == NULL", __func__)); |
| 229 | INP_WLOCK(inp); |
| 230 | KASSERT(so->so_pcb == inp && inp->inp_socket == so, |
| 231 | ("%s: socket %p inp %p mismatch", __func__, so, inp)); |
| 232 | |
| 233 | tp = intotcpcb(inp); |
| 234 | |
| 235 | if (inp->inp_flags & INP_TIMEWAIT) { |
| 236 | /* |
| 237 | * There are two cases to handle: one in which the time wait |
| 238 | * state is being discarded (INP_DROPPED), and one in which |
| 239 | * this connection will remain in timewait. In the former, |
| 240 | * it is time to discard all state (except tcptw, which has |
| 241 | * already been discarded by the timewait close code, which |
| 242 | * should be further up the call stack somewhere). In the |
| 243 | * latter case, we detach from the socket, but leave the pcb |
| 244 | * present until timewait ends. |
| 245 | * |
| 246 | * XXXRW: Would it be cleaner to free the tcptw here? |
| 247 | * |
| 248 | * Astute question indeed, from twtcp perspective there are |
| 249 | * four cases to consider: |
| 250 | * |
| 251 | * #1 tcp_usr_detach is called at tcptw creation time by |
| 252 | * tcp_twstart, then do not discard the newly created tcptw |
| 253 | * and leave inpcb present until timewait ends |
| 254 | * #2 tcp_usr_detach is called at tcptw creation time by |
| 255 | * tcp_twstart, but connection is local and tw will be |
| 256 | * discarded immediately |
| 257 | * #3 tcp_usr_detach is called at timewait end (or reuse) by |
| 258 | * tcp_twclose, then the tcptw has already been discarded |
| 259 | * (or reused) and inpcb is freed here |
| 260 | * #4 tcp_usr_detach is called() after timewait ends (or reuse) |
| 261 | * (e.g. by soclose), then tcptw has already been discarded |
| 262 | * (or reused) and inpcb is freed here |
| 263 | * |
| 264 | * In all three cases the tcptw should not be freed here. |
| 265 | */ |
| 266 | if (inp->inp_flags & INP_DROPPED) { |
| 267 | in_pcbdetach(inp); |
| 268 | if (__predict_true(tp == NULL)) { |
| 269 | in_pcbfree(inp); |
| 270 | } else { |
| 271 | /* |
| 272 | * This case should not happen as in TIMEWAIT |
| 273 | * state the inp should not be destroyed before |
| 274 | * its tcptw. If INVARIANTS is defined, panic. |
| 275 | */ |
| 276 | #ifdef INVARIANTS |
| 277 | panic("%s: Panic before an inp double-free: " |
| 278 | "INP_TIMEWAIT && INP_DROPPED && tp != NULL" |
nothing calls this directly
no test coverage detected