Index: in.h =================================================================== RCS file: /cvs/src/sys/netinet/in.h,v retrieving revision 1.137 diff -u -p -r1.137 in.h --- in.h 4 Nov 2019 23:52:28 -0000 1.137 +++ in.h 11 Jul 2020 05:59:52 -0000 @@ -807,6 +807,7 @@ struct sockaddr; struct sockaddr_in; struct ifaddr; struct in_ifaddr; +struct ip; void ipv4_input(struct ifnet *, struct mbuf *); @@ -814,6 +815,7 @@ int in_broadcast(struct in_addr, u_in int in_canforward(struct in_addr); int in_cksum(struct mbuf *, int); int in4_cksum(struct mbuf *, u_int8_t, int, int); +uint16_t ip_cksum(const struct ip *); void in_proto_cksum_out(struct mbuf *, struct ifnet *); void in_ifdetach(struct ifnet *); int in_mask2len(struct in_addr *); Index: in_cksum.c =================================================================== RCS file: /cvs/src/sys/netinet/in_cksum.c,v retrieving revision 1.9 diff -u -p -r1.9 in_cksum.c --- in_cksum.c 22 Apr 2019 22:47:49 -0000 1.9 +++ in_cksum.c 11 Jul 2020 05:59:52 -0000 @@ -144,3 +144,29 @@ in_cksum(struct mbuf *m, int len) REDUCE; return (~sum & 0xffff); } + +#include +#include + +uint16_t +ip_cksum(const struct ip *ip) +{ + const uint32_t *w = (const uint32_t *)ip; + uint64_t s; + unsigned int i; + + s = (uint64_t)w[0] + + (uint64_t)w[1] + + (uint64_t)w[2] + + (uint64_t)w[3] + + (uint64_t)w[4]; + + for (i = 5; i < ip->ip_hl; i++) + s += (uint64_t)w[i]; + + do { + s = (s >> 16) + (s & 0xffff); + } while (s >> 16); + + return (~s); +} Index: ip_input.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_input.c,v retrieving revision 1.348 diff -u -p -r1.348 ip_input.c --- ip_input.c 12 Apr 2020 11:56:52 -0000 1.348 +++ ip_input.c 11 Jul 2020 05:59:52 -0000 @@ -267,7 +267,7 @@ ip_input_if(struct mbuf **mp, int *offp, } ipstat_inc(ips_inswcsum); - if (in_cksum(m, hlen) != 0) { + if (ip_cksum(ip) != 0x0000) { ipstat_inc(ips_badsum); goto bad; } @@ -1446,7 +1446,12 @@ ip_forward(struct mbuf *m, struct ifnet fake = 1; } - ip->ip_ttl -= IPTTLDEC; + { + uint32_t nsum = ip->ip_sum + htons(IPTTLDEC << 8); + + ip->ip_ttl -= IPTTLDEC; + ip->ip_sum = (nsum) + (nsum >> 16); + } /* * If forwarding packet using same interface that it came in on, @@ -1477,8 +1482,8 @@ ip_forward(struct mbuf *m, struct ifnet ro.ro_rt = rt; ro.ro_tableid = m->m_pkthdr.ph_rtableid; - error = ip_output(m, NULL, &ro, - (IP_FORWARDING | (ip_directedbcast ? IP_ALLOWBROADCAST : 0)), + error = ip_output(m, NULL, &ro, IP_CSUMOK | IP_FORWARDING | + (ip_directedbcast ? IP_ALLOWBROADCAST : 0), NULL, NULL, 0); rt = ro.ro_rt; if (error) Index: ip_output.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_output.c,v retrieving revision 1.357 diff -u -p -r1.357 ip_output.c --- ip_output.c 24 Jun 2020 22:03:43 -0000 1.357 +++ ip_output.c 11 Jul 2020 05:59:52 -0000 @@ -129,7 +129,7 @@ ip_output(struct mbuf *m0, struct mbuf * /* * Fill in IP header. */ - if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) { + if (!ISSET(flags, IP_FORWARDING|IP_RAWOUTPUT)) { ip->ip_v = IPVERSION; ip->ip_off &= htons(IP_DF); ip->ip_id = htons(ip_randomid()); @@ -192,8 +192,10 @@ reroute: struct in_ifaddr *ia; IFP_TO_IA(ifp, ia); - if (ia != NULL) + if (ia != NULL) { ip->ip_src = ia->ia_addr.sin_addr; + CLR(flags, IP_CSUMOK); + } } } else { struct in_ifaddr *ia; @@ -231,8 +233,10 @@ reroute: dst = satosin(ro->ro_rt->rt_gateway); /* Set the source IP address */ - if (ip->ip_src.s_addr == INADDR_ANY && ia) + if (ip->ip_src.s_addr == INADDR_ANY && ia) { ip->ip_src = ia->ia_addr.sin_addr; + CLR(flags, IP_CSUMOK); + } } #ifdef IPSEC @@ -277,6 +281,7 @@ reroute: ip->ip_ttl = imo->imo_ttl; else ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL; + CLR(flags, IP_CSUMOK); /* * if we don't know the outgoing ifp yet, we can't generate @@ -310,8 +315,10 @@ reroute: struct in_ifaddr *ia; IFP_TO_IA(ifp, ia); - if (ia != NULL) + if (ia != NULL) { ip->ip_src = ia->ia_addr.sin_addr; + CLR(flags, IP_CSUMOK); + } } if ((imo == NULL || imo->imo_loop) && @@ -399,8 +406,10 @@ sendit: * the route's MTU is locked. */ if ((flags & IP_MTUDISC) && ro && ro->ro_rt && - (ro->ro_rt->rt_locks & RTV_MTU) == 0) + (ro->ro_rt->rt_locks & RTV_MTU) == 0) { ip->ip_off |= htons(IP_DF); + CLR(flags, IP_CSUMOK); + } #ifdef IPSEC /* @@ -456,13 +465,15 @@ sendit: * If small enough for interface, can just send directly. */ if (ntohs(ip->ip_len) <= mtu) { - ip->ip_sum = 0; - if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) && - (ifp->if_bridgeidx == 0)) - m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT; - else { - ipstat_inc(ips_outswcsum); - ip->ip_sum = in_cksum(m, hlen); + if (!ISSET(flags, IP_CSUMOK)) { + ip->ip_sum = 0; + if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) && + (ifp->if_bridgeidx == 0)) + m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT; + else { + ipstat_inc(ips_outswcsum); + ip->ip_sum = ip_cksum(ip); + } } error = ifp->if_output(ifp, m, sintosa(dst), ro->ro_rt); @@ -721,7 +732,7 @@ ip_fragment(struct mbuf *m, struct ifnet m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT; else { ipstat_inc(ips_outswcsum); - mhip->ip_sum = in_cksum(m, mhlen); + mhip->ip_sum = ip_cksum(mhip); } ipstat_inc(ips_ofragments); fragments++; @@ -742,7 +753,7 @@ ip_fragment(struct mbuf *m, struct ifnet m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT; else { ipstat_inc(ips_outswcsum); - ip->ip_sum = in_cksum(m, hlen); + ip->ip_sum = ip_cksum(ip); } sendorfree: if (error) { @@ -1709,7 +1720,7 @@ ip_mloopback(struct ifnet *ifp, struct m */ ip = mtod(copym, struct ip *); ip->ip_sum = 0; - ip->ip_sum = in_cksum(copym, ip->ip_hl << 2); + ip->ip_sum = ip_cksum(ip); if_input_local(ifp, copym, dst->sin_family); } } Index: ip_var.h =================================================================== RCS file: /cvs/src/sys/netinet/ip_var.h,v retrieving revision 1.86 diff -u -p -r1.86 ip_var.h --- ip_var.h 8 Dec 2019 11:08:22 -0000 1.86 +++ ip_var.h 11 Jul 2020 05:59:52 -0000 @@ -189,6 +189,7 @@ struct ipq { /* flags passed to ip_output */ #define IP_FORWARDING 0x1 /* most of ip header exists */ #define IP_RAWOUTPUT 0x2 /* raw ip header exists */ +#define IP_CSUMOK 0x4 /* ip cksum is ok */ #define IP_ALLOWBROADCAST SO_BROADCAST /* can send broadcast packets */ #define IP_MTUDISC 0x0800 /* pmtu discovery, set DF */