From 1fdbfb909fa976ece3655bea8f4bc419aeed732b Mon Sep 17 00:00:00 2001 From: Tom Jones Date: Wed, 6 Jun 2018 07:04:40 +0000 Subject: [PATCH] Use UDP len when calculating UDP checksums The length of the IP payload is normally equal to the UDP length, UDP Options (draft-ietf-tsvwg-udp-options-02) suggests using the difference between IP length and UDP length to create space for trailing data. Correct checksum length calculation to use the UDP length rather than the IP length when not offloading UDP checksums. Approved by: jtl (mentor) Differential Revision: https://reviews.freebsd.org/D15222 --- sys/netinet/ip_output.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index b2580cc0863..51bc2d88540 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -80,6 +80,10 @@ __FBSDID("$FreeBSD$"); #include #include #include + +#include +#include + #ifdef SCTP #include #include @@ -920,14 +924,28 @@ void in_delayed_cksum(struct mbuf *m) { struct ip *ip; - uint16_t csum, offset, ip_len; + struct udphdr *uh; + uint16_t cklen, csum, offset; ip = mtod(m, struct ip *); offset = ip->ip_hl << 2 ; - ip_len = ntohs(ip->ip_len); - csum = in_cksum_skip(m, ip_len, offset); - if (m->m_pkthdr.csum_flags & CSUM_UDP && csum == 0) - csum = 0xffff; + + if (m->m_pkthdr.csum_flags & CSUM_UDP) { + /* if udp header is not in the first mbuf copy udplen */ + if (offset + sizeof(struct udphdr) > m->m_len) + m_copydata(m, offset + offsetof(struct udphdr, uh_ulen), + 2, (caddr_t)&cklen); + else { + uh = (struct udphdr *)((caddr_t)ip + offset); + cklen = ntohs(uh->uh_ulen); + } + csum = in_cksum_skip(m, cklen + offset, offset); + if (csum == 0) + csum = 0xffff; + } else { + cklen = ntohs(ip->ip_len); + csum = in_cksum_skip(m, cklen, offset); + } offset += m->m_pkthdr.csum_data; /* checksum offset */ /* find the mbuf in the chain where the checksum starts*/