Fix TSO for traffic to a local address on a physical interface.
authorbluhm <bluhm@openbsd.org>
Mon, 22 May 2023 16:08:34 +0000 (16:08 +0000)
committerbluhm <bluhm@openbsd.org>
Mon, 22 May 2023 16:08:34 +0000 (16:08 +0000)
When sending TCP packets with software TSO to the local address of
a physical interface, the TCP checksum was miscalculated.  As the
small MSS is taken from the physical interface, but the large MTU
of the loopback interface is used, large TSO packets are generated,
but sent directly to the loopback interface.  There we need the
regular pseudo header checksum and not the modified without packet
length.

To avoid this confusion, use the same decision for checksum generation
in in_proto_cksum_out() as for using hardware TSO in tcp_if_output_tso().

bug reported and tested by robert@ bket@ Hrvoje Popovski
OK claudio@ jan@

sys/netinet/ip_output.c
sys/netinet6/ip6_output.c

index a44ee06..86288bc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip_output.c,v 1.387 2023/05/15 16:34:56 bluhm Exp $   */
+/*     $OpenBSD: ip_output.c,v 1.388 2023/05/22 16:08:34 bluhm Exp $   */
 /*     $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $  */
 
 /*
@@ -1882,7 +1882,8 @@ in_proto_cksum_out(struct mbuf *m, struct ifnet *ifp)
                u_int16_t csum = 0, offset;
 
                offset = ip->ip_hl << 2;
-               if (ISSET(m->m_pkthdr.csum_flags, M_TCP_TSO)) {
+               if (ISSET(m->m_pkthdr.csum_flags, M_TCP_TSO) &&
+                   in_ifcap_cksum(m, ifp, IFCAP_TSOv4)) {
                        csum = in_cksum_phdr(ip->ip_src.s_addr,
                            ip->ip_dst.s_addr, htonl(ip->ip_p));
                } else if (ISSET(m->m_pkthdr.csum_flags,
index add8fb2..05c1189 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ip6_output.c,v 1.276 2023/05/15 16:34:57 bluhm Exp $  */
+/*     $OpenBSD: ip6_output.c,v 1.277 2023/05/22 16:08:34 bluhm Exp $  */
 /*     $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $    */
 
 /*
@@ -2710,7 +2710,8 @@ in6_proto_cksum_out(struct mbuf *m, struct ifnet *ifp)
                u_int16_t csum;
 
                offset = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
-               if (ISSET(m->m_pkthdr.csum_flags, M_TCP_TSO)) {
+               if (ISSET(m->m_pkthdr.csum_flags, M_TCP_TSO) &&
+                   in_ifcap_cksum(m, ifp, IFCAP_TSOv6)) {
                        csum = in6_cksum_phdr(&ip6->ip6_src, &ip6->ip6_dst,
                            htonl(0), htonl(nxt));
                } else {