diff options
author | Hiren Panchasara <hiren@FreeBSD.org> | 2016-12-11 23:14:47 +0000 |
---|---|---|
committer | Hiren Panchasara <hiren@FreeBSD.org> | 2016-12-11 23:14:47 +0000 |
commit | b6ff672460ec0910c453d7de047119dd6d34db19 (patch) | |
tree | 4cad0f22fba109a1855c6dda59bd4281e053cc14 | |
parent | 2823b6467ac5bf7c82485778ebe9237d8abf8381 (diff) | |
download | src-b6ff672460ec0910c453d7de047119dd6d34db19.tar.gz src-b6ff672460ec0910c453d7de047119dd6d34db19.zip |
We currently don't do TSO if ip options are present. In case of IPv6, we look at
in6p_options to check that. That is incorrect as we carry ip options in
in6p_outputopts. Also, just checking for in6p_outputopts being NULL won't
suffice as we combine ip options and ip header fields both in that one field.
The commit fixes this by using ip6_optlen() which correctly calculates length
of only ip options for IPv6.
Reviewed by: ae, bz
MFC after: 3 weeks
Sponsored by: Limelight Networks
Notes
Notes:
svn path=/head/; revision=309858
-rw-r--r-- | sys/netinet/tcp_output.c | 40 |
1 files changed, 21 insertions, 19 deletions
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index fd549944022c..6b187dd810d6 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -545,6 +545,11 @@ after_sack_rexmit: * (except for the sequence number) for all generated packets. This * makes it impossible to transmit any options which vary per generated * segment or packet. + * + * IPv4 handling has a clear separation of ip options and ip header + * flags while IPv6 combines both in in6p_outputopts. ip6_optlen() does + * the right thing below to provide length of just ip options and thus + * checking for ipoptlen is enough to decide if ip options are present. */ #ifdef IPSEC /* @@ -553,14 +558,25 @@ after_sack_rexmit: */ ipsec_optlen = ipsec_hdrsiz_tcp(tp); #endif + +#ifdef INET6 + if (isipv6) + ipoptlen = ip6_optlen(tp->t_inpcb); + else +#endif + if (tp->t_inpcb->inp_options) + ipoptlen = tp->t_inpcb->inp_options->m_len - + offsetof(struct ipoption, ipopt_list); + else + ipoptlen = 0; +#ifdef IPSEC + ipoptlen += ipsec_optlen; +#endif + if ((tp->t_flags & TF_TSO) && V_tcp_do_tso && len > tp->t_maxseg && ((tp->t_flags & TF_SIGNATURE) == 0) && tp->rcv_numsacks == 0 && sack_rxmit == 0 && -#ifdef IPSEC - ipsec_optlen == 0 && -#endif - tp->t_inpcb->inp_options == NULL && - tp->t_inpcb->in6p_options == NULL) + ipoptlen == 0) tso = 1; if (sack_rxmit) { @@ -833,20 +849,6 @@ send: hdrlen += optlen = tcp_addoptions(&to, opt); } -#ifdef INET6 - if (isipv6) - ipoptlen = ip6_optlen(tp->t_inpcb); - else -#endif - if (tp->t_inpcb->inp_options) - ipoptlen = tp->t_inpcb->inp_options->m_len - - offsetof(struct ipoption, ipopt_list); - else - ipoptlen = 0; -#ifdef IPSEC - ipoptlen += ipsec_optlen; -#endif - /* * Adjust data length if insertion of options will * bump the packet length beyond the t_maxseg length. |