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); }