Index: sys/netinet/tcp_stacks/bbr.c =================================================================== --- sys/netinet/tcp_stacks/bbr.c +++ sys/netinet/tcp_stacks/bbr.c @@ -14238,6 +14238,7 @@ .tfb_tcp_handoff_ok = bbr_handoff_ok, .tfb_tcp_mtu_chg = bbr_mtu_chg, .tfb_pru_options = bbr_pru_options, + .tfb_tcp_ll_socketopt = tcp_ll_socketopt, }; /* Index: sys/netinet/tcp_stacks/rack.c =================================================================== --- sys/netinet/tcp_stacks/rack.c +++ sys/netinet/tcp_stacks/rack.c @@ -12508,6 +12508,7 @@ ip6, rack->r_ctl.fsb.th); } else #endif /* INET6 */ +#ifdef INET { rack->r_ctl.fsb.tcp_ip_hdr_len = sizeof(struct tcpiphdr); ip = (struct ip *)rack->r_ctl.fsb.tcp_ip_hdr; @@ -12527,9 +12528,80 @@ tp->t_port, ip, rack->r_ctl.fsb.th); } +#endif rack->r_fsb_inited = 1; } +static void +rack_ll_socketopt(struct tcpcb *tp, int sopt_level, int sopt_name) +{ +#ifdef INET6 + struct ip6_hdr *ip6 = NULL; +#endif +#ifdef INET + struct ip *ip = NULL; +#endif + struct tcp_rack *rack; + /* + * A socket option changed the outgoing TOS/TCLASS update + * the fast send block. + */ + rack = (struct tcp_rack *)tp->t_fb_ptr; +#ifdef INET6 + /* + * In case of the IPV6_USE_MIN_MTU socket option, + * the INC_IPV6MINMTU flag to announce a corresponding + * MSS during the initial handshake. + * If the TCP connection is not in the front states, + * just reduce the MSS being used. + * This avoids the sending of TCP segments which will + * be fragmented at the IPv6 layer. + */ + if ((sopt_level == IPPROTO_IPV6) && + (sopt_name == IPV6_USE_MIN_MTU)) { + tp->t_inpcb->inp_inc.inc_flags |= INC_IPV6MINMTU; + if ((tp->t_state >= TCPS_SYN_SENT) && + (tp->t_inpcb->inp_inc.inc_flags & INC_ISIPV6)) { + struct ip6_pktopts *opt; + + opt = tp->t_inpcb->in6p_outputopts; + if ((opt != NULL) && + (opt->ip6po_minmtu == + IP6PO_MINMTU_ALL)) { + if (tp->t_maxseg > TCP6_MSS) { + tp->t_maxseg = TCP6_MSS; + } + } + } + } else if ((sopt_level == IPPROTO_IPV6) && + (sopt_name == IPV6_TCLASS)) { + /* + * The DSCP codepoint has changed, update the fsb. + */ + ip6 = (struct ip6_hdr *)rack->r_ctl.fsb.tcp_ip_hdr; + ip6->ip6_flow = (ip6->ip6_flow & ~IPV6_FLOWINFO_MASK) | + (rack->rc_inp->inp_flow & IPV6_FLOWINFO_MASK); + } +#endif +#ifdef INET + else if ((sopt_level == IPPROTO_IP) && + (sopt_name == IP_TOS)) { + /* + * The DSCP codepoint has changed, update the fsb. + */ + ip = (struct ip *)rack->r_ctl.fsb.tcp_ip_hdr; + ip->ip_tos = rack->rc_inp->inp_ip_tos; + } else if ((sopt_level == IPPROTO_IP) && + (sopt_name == IP_TTL)) { + /* + * The TTL has changed, update the fsb. + */ + ip = (struct ip *)rack->r_ctl.fsb.tcp_ip_hdr; + ip->ip_ttl = rack->rc_inp->inp_ip_ttl; + } +#endif +} + static int rack_init_fsb(struct tcpcb *tp, struct tcp_rack *rack) { @@ -20232,6 +20304,7 @@ .tfb_tcp_mtu_chg = rack_mtu_change, .tfb_pru_options = rack_pru_options, .tfb_hwtls_change = rack_hw_tls_change, + .tfb_tcp_ll_socketopt = rack_ll_socketopt, }; /* Index: sys/netinet/tcp_subr.c =================================================================== --- sys/netinet/tcp_subr.c +++ sys/netinet/tcp_subr.c @@ -384,6 +384,7 @@ .tfb_tcp_handoff_ok = tcp_default_handoff_ok, .tfb_tcp_fb_init = tcp_default_fb_init, .tfb_tcp_fb_fini = tcp_default_fb_fini, + .tfb_tcp_ll_socketopt = tcp_ll_socketopt, }; static int tcp_fb_cnt = 0; @@ -1187,6 +1188,7 @@ if ((blk->tfb_tcp_output == NULL) || (blk->tfb_tcp_do_segment == NULL) || (blk->tfb_tcp_ctloutput == NULL) || + (blk->tfb_tcp_ll_socketopt == NULL) || (strlen(blk->tfb_tcp_block_name) == 0)) { /* * These functions are required and you @@ -4129,3 +4131,4 @@ } } } + Index: sys/netinet/tcp_usrreq.c =================================================================== --- sys/netinet/tcp_usrreq.c +++ sys/netinet/tcp_usrreq.c @@ -1712,6 +1712,39 @@ #endif } +void +tcp_ll_socketopt(struct tcpcb *tp, int sopt_level, int sopt_name) +{ + /* + * In case of the IPV6_USE_MIN_MTU socket option, + * the INC_IPV6MINMTU flag to announce a corresponding + * MSS during the initial handshake. + * If the TCP connection is not in the front states, + * just reduce the MSS being used. + * This avoids the sending of TCP segments which will + * be fragmented at the IPv6 layer. + */ +#ifdef INET6 + if ((sopt_level == IPPROTO_IPV6) && + (sopt_name == IPV6_USE_MIN_MTU)) { + tp->t_inpcb->inp_inc.inc_flags |= INC_IPV6MINMTU; + if ((tp->t_state >= TCPS_SYN_SENT) && + (tp->t_inpcb->inp_inc.inc_flags & INC_ISIPV6)) { + struct ip6_pktopts *opt; + + opt = tp->t_inpcb->in6p_outputopts; + if ((opt != NULL) && + (opt->ip6po_minmtu == + IP6PO_MINMTU_ALL)) { + if (tp->t_maxseg > TCP6_MSS) { + tp->t_maxseg = TCP6_MSS; + } + } + } + } +#endif +} + /* * tcp_ctloutput() must drop the inpcb lock before performing copyin on * socket option arguments. When it re-acquires the lock after the copy, it @@ -1745,42 +1778,6 @@ #ifdef INET6 if (inp->inp_vflag & INP_IPV6PROTO) { error = ip6_ctloutput(so, sopt); - /* - * In case of the IPV6_USE_MIN_MTU socket option, - * the INC_IPV6MINMTU flag to announce a corresponding - * MSS during the initial handshake. - * If the TCP connection is not in the front states, - * just reduce the MSS being used. - * This avoids the sending of TCP segments which will - * be fragmented at the IPv6 layer. - */ - if ((error == 0) && - (sopt->sopt_dir == SOPT_SET) && - (sopt->sopt_level == IPPROTO_IPV6) && - (sopt->sopt_name == IPV6_USE_MIN_MTU)) { - INP_WLOCK(inp); - if ((inp->inp_flags & - (INP_TIMEWAIT | INP_DROPPED))) { - INP_WUNLOCK(inp); - return (ECONNRESET); - } - inp->inp_inc.inc_flags |= INC_IPV6MINMTU; - tp = intotcpcb(inp); - if ((tp->t_state >= TCPS_SYN_SENT) && - (inp->inp_inc.inc_flags & INC_ISIPV6)) { - struct ip6_pktopts *opt; - - opt = inp->in6p_outputopts; - if ((opt != NULL) && - (opt->ip6po_minmtu == - IP6PO_MINMTU_ALL)) { - if (tp->t_maxseg > TCP6_MSS) { - tp->t_maxseg = TCP6_MSS; - } - } - } - INP_WUNLOCK(inp); - } } #endif /* INET6 */ #if defined(INET6) && defined(INET) @@ -1791,6 +1788,22 @@ error = ip_ctloutput(so, sopt); } #endif + if (error == 0) { + INP_WLOCK(inp); + if ((inp->inp_flags & + (INP_TIMEWAIT | INP_DROPPED))) { + INP_WUNLOCK(inp); + return (ECONNRESET); + } + tp = intotcpcb(inp); + /* + * All stacks must provide a function that looks at the + * lower layer changes, they can use tcp_ll_socketopt() above + * if they don't have any specifics besides the V6 MSS options. + */ + (tp->t_fb->tfb_tcp_ll_socketopt)(tp, sopt->sopt_level, sopt->sopt_name); + INP_WUNLOCK(inp); + } return (error); } INP_WLOCK(inp); Index: sys/netinet/tcp_var.h =================================================================== --- sys/netinet/tcp_var.h +++ sys/netinet/tcp_var.h @@ -373,6 +373,7 @@ void (*tfb_tcp_mtu_chg)(struct tcpcb *); int (*tfb_pru_options)(struct tcpcb *, int); void (*tfb_hwtls_change)(struct tcpcb *, int); + void (*tfb_tcp_ll_socketopt)(struct tcpcb *, int, int); volatile uint32_t tfb_refcnt; uint32_t tfb_flags; uint8_t tfb_id; @@ -990,6 +991,7 @@ struct tcpcb *, int, int); void tcp_pulloutofband(struct socket *, struct tcphdr *, struct mbuf *, int); +void tcp_ll_socketopt(struct tcpcb *, int , int); void tcp_xmit_timer(struct tcpcb *, int); void tcp_newreno_partial_ack(struct tcpcb *, struct tcphdr *); void cc_ack_received(struct tcpcb *tp, struct tcphdr *th,