diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -2176,9 +2176,11 @@ * Create a new TCP control block, making an empty reassembly queue and hooking * it to the argument protocol control block. The `inp' parameter must have * come from the zone allocator set up by tcpcbstor declaration. + * The caller can provide a pointer to tcpcb of the listener to inherit the + * TCP function block from the listener. */ struct tcpcb * -tcp_newtcpcb(struct inpcb *inp) +tcp_newtcpcb(struct inpcb *inp, struct tcpcb *listening_tcb) { struct tcpcb *tp = intotcpcb(inp); #ifdef INET6 @@ -2196,8 +2198,19 @@ tp->t_ccv.type = IPPROTO_TCP; tp->t_ccv.ccvc.tcp = tp; rw_rlock(&tcp_function_lock); - tp->t_fb = V_tcp_func_set_ptr; + if (listening_tcb != NULL) { + tp->t_fb = find_tcp_fb_locked(listening_tcb->t_fb, NULL); + KASSERT(tp->t_fb != NULL, ("tcp_newtcpcb: TFB is NULL")); + if ((tp->t_fb->tfb_flags & TCP_FUNC_BEING_REMOVED) != 0) { + rw_runlock(&tcp_function_lock); + return (NULL); + } + } else { + tp->t_fb = V_tcp_func_set_ptr; + } refcount_acquire(&tp->t_fb->tfb_refcnt); + KASSERT((tp->t_fb->tfb_flags & TCP_FUNC_BEING_REMOVED) == 0, + ("tcp_newtcpcb: using TFB being removed")); rw_runlock(&tcp_function_lock); /* * Use the current system default CC algorithm. @@ -2207,16 +2220,12 @@ if (CC_ALGO(tp)->cb_init != NULL) if (CC_ALGO(tp)->cb_init(&tp->t_ccv, NULL) > 0) { cc_detach(tp); - if (tp->t_fb->tfb_tcp_fb_fini) - (*tp->t_fb->tfb_tcp_fb_fini)(tp, 1); refcount_release(&tp->t_fb->tfb_refcnt); return (NULL); } #ifdef TCP_HHOOK if (khelp_init_osd(HELPER_CLASS_TCP, &tp->t_osd)) { - if (tp->t_fb->tfb_tcp_fb_fini) - (*tp->t_fb->tfb_tcp_fb_fini)(tp, 1); refcount_release(&tp->t_fb->tfb_refcnt); return (NULL); } diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c --- a/sys/netinet/tcp_syncache.c +++ b/sys/netinet/tcp_syncache.c @@ -777,7 +777,7 @@ static struct socket * syncache_socket(struct syncache *sc, struct socket *lso, struct mbuf *m) { - struct tcp_function_block *blk; + struct tcpcb *listening_tcb; struct inpcb *inp = NULL; struct socket *so; struct tcpcb *tp; @@ -802,7 +802,11 @@ goto allocfail; } inp = sotoinpcb(so); - if ((tp = tcp_newtcpcb(inp)) == NULL) { + if (V_functions_inherit_listen_socket_stack) + listening_tcb = sototcpcb(lso); + else + listening_tcb = NULL; + if ((tp = tcp_newtcpcb(inp, listening_tcb)) == NULL) { in_pcbfree(inp); sodealloc(so); goto allocfail; @@ -912,37 +916,6 @@ tp->t_port = sc->sc_port; tcp_rcvseqinit(tp); tcp_sendseqinit(tp); - blk = sototcpcb(lso)->t_fb; - if (V_functions_inherit_listen_socket_stack && blk != tp->t_fb) { - /* - * Our parents t_fb was not the default, - * we need to release our ref on tp->t_fb and - * pickup one on the new entry. - */ - struct tcp_function_block *rblk; - void *ptr = NULL; - - rblk = find_and_ref_tcp_fb(blk); - KASSERT(rblk != NULL, - ("cannot find blk %p out of syncache?", blk)); - - if (rblk->tfb_tcp_fb_init == NULL || - (*rblk->tfb_tcp_fb_init)(tp, &ptr) == 0) { - /* Release the old stack */ - if (tp->t_fb->tfb_tcp_fb_fini != NULL) - (*tp->t_fb->tfb_tcp_fb_fini)(tp, 0); - refcount_release(&tp->t_fb->tfb_refcnt); - /* Now set in all the pointers */ - tp->t_fb = rblk; - tp->t_fb_ptr = ptr; - } else { - /* - * Initialization failed. Release the reference count on - * the looked up default stack. - */ - refcount_release(&rblk->tfb_refcnt); - } - } tp->snd_wl1 = sc->sc_irs; tp->snd_max = tp->iss + 1; tp->snd_nxt = tp->iss + 1; @@ -1053,6 +1026,7 @@ return (NULL); abort: + refcount_release(&tp->t_fb->tfb_refcnt); in_pcbfree(inp); sodealloc(so); if ((s = tcp_log_addrs(&sc->sc_inc, NULL, NULL, NULL))) { diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -172,7 +172,7 @@ if (error) goto out; inp = sotoinpcb(so); - tp = tcp_newtcpcb(inp); + tp = tcp_newtcpcb(inp, NULL); if (tp == NULL) { error = ENOBUFS; in_pcbfree(inp); diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -1442,7 +1442,7 @@ void tcp_mss(struct tcpcb *, int); int tcp_mssopt(struct in_conninfo *); struct tcpcb * - tcp_newtcpcb(struct inpcb *); + tcp_newtcpcb(struct inpcb *, struct tcpcb *); int tcp_default_output(struct tcpcb *); void tcp_state_change(struct tcpcb *, int); void tcp_respond(struct tcpcb *, void *,