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