Hi,

Simplex interfaces reinject broadcast packets back into the IP
stack.  As this is a software features, no hardware checksumming
occurs.  So local broadcast packets are dropped with wrong checksum
if the underlying hardware supports checksumming.

Do software checksumming in ip_output() if the copy of a broadcast
packet will be delivered locally.  Put the logic into a separate
in_ifcap_cksum() function.

Found by regress/sys/kern/sosplice/loop which fails on some machines.

ok?

bluhm

Index: netinet/ip_output.c
===================================================================
RCS file: /mount/openbsd/cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.361
diff -u -p -r1.361 ip_output.c
--- netinet/ip_output.c 16 Jan 2021 07:58:12 -0000      1.361
+++ netinet/ip_output.c 20 Jan 2021 00:27:12 -0000
@@ -79,6 +79,7 @@ void ip_mloopback(struct ifnet *, struct
 static __inline u_int16_t __attribute__((__unused__))
     in_cksum_phdr(u_int32_t, u_int32_t, u_int32_t);
 void in_delayed_cksum(struct mbuf *);
+int in_ifcap_cksum(struct mbuf *, struct ifnet *, int);
 
 #ifdef IPSEC
 struct tdb *
@@ -458,8 +459,7 @@ sendit:
         */
        if (ntohs(ip->ip_len) <= mtu) {
                ip->ip_sum = 0;
-               if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
-                   (ifp->if_bridgeidx == 0))
+               if (in_ifcap_cksum(m, ifp, IFCAP_CSUM_IPv4))
                        m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
                else {
                        ipstat_inc(ips_outswcsum);
@@ -716,9 +716,7 @@ ip_fragment(struct mbuf *m, struct ifnet
                m->m_pkthdr.ph_ifidx = 0;
                mhip->ip_off = htons((u_int16_t)mhip->ip_off);
                mhip->ip_sum = 0;
-               if ((ifp != NULL) &&
-                   (ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
-                   (ifp->if_bridgeidx == 0))
+               if (in_ifcap_cksum(m, ifp, IFCAP_CSUM_IPv4))
                        m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
                else {
                        ipstat_inc(ips_outswcsum);
@@ -737,9 +735,7 @@ ip_fragment(struct mbuf *m, struct ifnet
        ip->ip_len = htons((u_int16_t)m->m_pkthdr.len);
        ip->ip_off |= htons(IP_MF);
        ip->ip_sum = 0;
-       if ((ifp != NULL) &&
-           (ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
-           (ifp->if_bridgeidx == 0))
+       if (in_ifcap_cksum(m, ifp, IFCAP_CSUM_IPv4))
                m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
        else {
                ipstat_inc(ips_outswcsum);
@@ -1849,15 +1845,15 @@ in_proto_cksum_out(struct mbuf *m, struc
        }
 
        if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT) {
-               if (!ifp || !(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
-                   ip->ip_hl != 5 || ifp->if_bridgeidx != 0) {
+               if (!in_ifcap_cksum(m, ifp, IFCAP_CSUM_TCPv4) ||
+                   ip->ip_hl != 5) {
                        tcpstat_inc(tcps_outswcsum);
                        in_delayed_cksum(m);
                        m->m_pkthdr.csum_flags &= ~M_TCP_CSUM_OUT; /* Clear */
                }
        } else if (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT) {
-               if (!ifp || !(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
-                   ip->ip_hl != 5 || ifp->if_bridgeidx != 0) {
+               if (!in_ifcap_cksum(m, ifp, IFCAP_CSUM_UDPv4) ||
+                   ip->ip_hl != 5) {
                        udpstat_inc(udps_outswcsum);
                        in_delayed_cksum(m);
                        m->m_pkthdr.csum_flags &= ~M_UDP_CSUM_OUT; /* Clear */
@@ -1866,4 +1862,19 @@ in_proto_cksum_out(struct mbuf *m, struc
                in_delayed_cksum(m);
                m->m_pkthdr.csum_flags &= ~M_ICMP_CSUM_OUT; /* Clear */
        }
+}
+
+int
+in_ifcap_cksum(struct mbuf *m, struct ifnet *ifp, int ifcap)
+{
+       if ((ifp == NULL) ||
+           !ISSET(ifp->if_capabilities, ifcap) ||
+           (ifp->if_bridgeidx != 0))
+               return (0);
+       /* Simplex interface sends packet back without hardware cksum. */
+       if (ISSET(m->m_flags, M_BCAST) &&
+           ISSET(ifp->if_flags, IFF_SIMPLEX) &&
+           !m->m_pkthdr.pf.routed)
+               return (0);
+       return (1);
 }

Reply via email to