Index: netinet/tcp_input.c =================================================================== --- netinet/tcp_input.c (revision 184855) +++ netinet/tcp_input.c (working copy) @@ -2765,6 +2765,12 @@ if (maxmtu == 0) return; + if (tp->t_usermss) { + if (maxmtu > (tp->t_usermss + min_protoh)) + maxmtu = tp->t_usermss + min_protoh; + if (offer > tp->t_usermss) + offer = tp->t_usermss; + } /* What have we got? */ switch (offer) { case 0: Index: netinet/tcp_var.h =================================================================== --- netinet/tcp_var.h (revision 184855) +++ netinet/tcp_var.h (working copy) @@ -210,6 +210,7 @@ void *t_pspare[3]; /* toe usrreqs / toepcb * / congestion algo / vimage / 1 general use */ struct toe_usrreqs *t_tu; /* offload operations vector */ void *t_toe; /* TOE pcb pointer */ + u_int t_usermss; /* User requested t_maxseg */ }; #define IN_FASTRECOVERY(tp) (tp->t_flags & TF_FASTRECOVERY) Index: netinet/tcp_output.c =================================================================== --- netinet/tcp_output.c (revision 184855) +++ netinet/tcp_output.c (working copy) @@ -649,6 +649,8 @@ if (flags & TH_SYN) { tp->snd_nxt = tp->iss; to.to_mss = tcp_mssopt(&tp->t_inpcb->inp_inc); + if (tp->t_usermss && to.to_mss > tp->t_usermss) + to.to_mss = tp->t_usermss; to.to_flags |= TOF_MSS; } /* Window scaling. */ Index: netinet/tcp_syncache.c =================================================================== --- netinet/tcp_syncache.c (revision 184855) +++ netinet/tcp_syncache.c (working copy) @@ -115,6 +115,7 @@ struct in_conninfo sc_inc; /* addresses */ int sc_rxttime; /* retransmit time */ u_int16_t sc_rxmits; /* retransmit counter */ + u_int16_t sc_usermss; /* User-requested mss cap */ u_int32_t sc_tsreflect; /* timestamp to reflect */ u_int32_t sc_ts; /* our timestamp to send */ @@ -1017,6 +1018,7 @@ struct mbuf *ipopts = NULL; u_int32_t flowtmp; int win, sb_hiwat, ip_ttl, ip_tos, noopt; + u_int16_t usermss; char *s; #ifdef INET6 int autoflowlabel = 0; @@ -1050,6 +1052,7 @@ win = sbspace(&so->so_rcv); sb_hiwat = so->so_rcv.sb_hiwat; noopt = (tp->t_flags & TF_NOOPT); + usermss = tp->t_usermss; /* By the time we drop the lock these should no longer be used. */ so = NULL; @@ -1188,6 +1191,7 @@ sc->sc_iss = arc4random(); sc->sc_flags = 0; sc->sc_flowlabel = 0; + sc->sc_usermss = usermss; /* * Initial receive window: clip sbspace to [0 .. TCP_MAXWIN]. @@ -1252,8 +1256,11 @@ #endif if (to->to_flags & TOF_SACKPERM) sc->sc_flags |= SCF_SACK; - if (to->to_flags & TOF_MSS) + if (to->to_flags & TOF_MSS) { sc->sc_peer_mss = to->to_mss; /* peer mss may be zero */ + if (sc->sc_usermss && sc->sc_peer_mss > sc->sc_usermss) + sc->sc_peer_mss = sc->sc_usermss; + } if (noopt) sc->sc_flags |= SCF_NOOPT; @@ -1321,6 +1328,8 @@ /* Determine MSS we advertize to other end of connection. */ mssopt = tcp_mssopt(&sc->sc_inc); + if (sc->sc_usermss && mssopt > sc->sc_usermss) + mssopt = sc->sc_usermss; if (sc->sc_peer_mss) mssopt = max( min(sc->sc_peer_mss, mssopt), tcp_minmss); @@ -1723,6 +1732,8 @@ sc->sc_rxmits = 0; sc->sc_peer_mss = tcp_sc_msstab[mss]; + if (sc->sc_usermss && sc->sc_peer_mss > sc->sc_usermss) + sc->sc_peer_mss = sc->sc_usermss; tcpstat.tcps_sc_recvcookie++; return (sc); Index: netinet/tcp_usrreq.c =================================================================== --- netinet/tcp_usrreq.c (revision 184855) +++ netinet/tcp_usrreq.c (working copy) @@ -1357,11 +1357,18 @@ return (error); INP_WLOCK_RECHECK(inp); - if (optval > 0 && optval <= tp->t_maxseg && - optval + 40 >= tcp_minmss) - tp->t_maxseg = optval; - else - error = EINVAL; + if ((so->so_state & SS_ISCONNECTED) == 0) { + if (optval > 0 && optval + 40 >= tcp_minmss) + tp->t_usermss = optval; + else + error = EINVAL; + } else { + if (optval > 0 && optval <= tp->t_maxseg && + optval + 40 >= tcp_minmss) + tp->t_maxseg = optval; + else + error = EINVAL; + } INP_WUNLOCK(inp); break; @@ -1394,7 +1401,10 @@ error = sooptcopyout(sopt, &optval, sizeof optval); break; case TCP_MAXSEG: - optval = tp->t_maxseg; + if ((so->so_state & SS_ISCONNECTED) == 0) + optval = tp->t_usermss; + else + optval = tp->t_maxseg; INP_WUNLOCK(inp); error = sooptcopyout(sopt, &optval, sizeof optval); break;