aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/ip_output.c
diff options
context:
space:
mode:
authorRuslan Ermilov <ru@FreeBSD.org>2001-03-13 17:07:06 +0000
committerRuslan Ermilov <ru@FreeBSD.org>2001-03-13 17:07:06 +0000
commit206a3274ef285fdc2f2f6eace4b49b33d76e9e17 (patch)
tree081e692480b2aed64384afea6a19125f60bfd95d /sys/netinet/ip_output.c
parent90010f94de0313d96784e58e560569a7fec0ecb4 (diff)
downloadsrc-206a3274ef285fdc2f2f6eace4b49b33d76e9e17.tar.gz
src-206a3274ef285fdc2f2f6eace4b49b33d76e9e17.zip
RFC768 (UDP) requires that "if the computed checksum is zero, it
is transmitted as all ones". This got broken after introduction of delayed checksums as follows. Some guys (including Jonathan) think that it is allowed to transmit all ones in place of a zero checksum for TCP the same way as for UDP. (The discussion still takes place on -net.) Thus, the 0 -> 0xffff checksum fixup was first moved from udp_output() (see udp_usrreq.c, 1.64 -> 1.65) to in_cksum_skip() (see sys/i386/i386/in_cksum.c, 1.17 -> 1.18, INVERT expression). Besides that I disagree that it is valid for TCP, there was no real problem until in_cksum.c,v 1.20, where the in_cksum() was made just a special version of in_cksum_skip(). The side effect was that now every incoming IP datagram failed to pass the checksum test (in_cksum() returned 0xffff when it should actually return zero). It was fixed next day in revision 1.21, by removing the INVERT expression. The latter also broke the 0 -> 0xffff fixup for UDP checksums. Before this change: : tcpdump: listening on lo0 : 127.0.0.1.33005 > 127.0.0.1.33006: udp 0 (ttl 64, id 1) : 4500 001c 0001 0000 4011 7cce 7f00 0001 : 7f00 0001 80ed 80ee 0008 0000 After this change: : tcpdump: listening on lo0 : 127.0.0.1.33005 > 127.0.0.1.33006: udp 0 (ttl 64, id 1) : 4500 001c 0001 0000 4011 7cce 7f00 0001 : 7f00 0001 80ed 80ee 0008 ffff
Notes
Notes: svn path=/head/; revision=74213
Diffstat (limited to 'sys/netinet/ip_output.c')
-rw-r--r--sys/netinet/ip_output.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index bca751db281d..ed201682cd8a 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -784,13 +784,13 @@ pass:
skip_ipsec:
#endif /*IPSEC*/
- sw_csum = m->m_pkthdr.csum_flags | CSUM_IP;
- m->m_pkthdr.csum_flags = sw_csum & ifp->if_hwassist;
- sw_csum &= ~ifp->if_hwassist;
+ m->m_pkthdr.csum_flags |= CSUM_IP;
+ sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_hwassist;
if (sw_csum & CSUM_DELAY_DATA) {
in_delayed_cksum(m);
sw_csum &= ~CSUM_DELAY_DATA;
}
+ m->m_pkthdr.csum_flags &= ifp->if_hwassist;
/*
* If small enough for interface, or the interface will take
@@ -982,6 +982,8 @@ in_delayed_cksum(struct mbuf *m)
ip = mtod(m, struct ip *);
offset = IP_VHL_HL(ip->ip_vhl) << 2 ;
csum = in_cksum_skip(m, ip->ip_len, offset);
+ if (m->m_pkthdr.csum_flags & CSUM_UDP && csum == 0)
+ csum = 0xffff;
offset += m->m_pkthdr.csum_data; /* checksum offset */
if (offset + sizeof(u_short) > m->m_len) {