diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-06-14 20:48:21 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-06-14 20:48:21 +0200 |
commit | 4971db9e32dadf72dff6df6293774df2a4f57a89 (patch) | |
tree | 2340223fc71d735c2ac95c551c3630380799ea4f | |
parent | 39fb26df70b6d8878953ff18046cdc12817a2e42 (diff) |
udp: fix udp checksum
we did not apply the special case to store 0xFFFF (-0)
in the checksum field when the checksum calculation
returned zero. we survived this for v4 as RFC768 states:
> If the computed checksum is zero, it is transmitted as
> all ones (the equivalent in one's complement arithmetic).
>
> An all zero transmitted checksum value means that the
> transmitter generated no checksum (for debuging or for
> higher level protocols that don't care).
for ipv6 however, the checksum is not optional and receivers
would drop packets with a zero checksum.
-rw-r--r-- | sys/src/9/ip/udp.c | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/sys/src/9/ip/udp.c b/sys/src/9/ip/udp.c index 53e2af3cc..d3fc1e98f 100644 --- a/sys/src/9/ip/udp.c +++ b/sys/src/9/ip/udp.c @@ -190,6 +190,7 @@ udpkick(void *x, Block *bp) Fs *f; int version; Routehint *rh; + ushort csum; upriv = c->p->priv; f = c->p->f; @@ -260,8 +261,10 @@ udpkick(void *x, Block *bp) hnputs(uh4->udplen, ptcllen); uh4->udpcksum[0] = 0; uh4->udpcksum[1] = 0; - hnputs(uh4->udpcksum, - ptclcsum(bp, UDP4_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP4_PHDR_SZ)); + csum = ptclcsum(bp, UDP4_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP4_PHDR_SZ); + if(csum == 0) + csum = 0xffff; /* -0 */ + hnputs(uh4->udpcksum, csum); uh4->vihl = IP_VER4; ipoput4(f, bp, 0, c->ttl, c->tos, rh); break; @@ -294,8 +297,10 @@ udpkick(void *x, Block *bp) hnputs(uh6->udplen, ptcllen); uh6->udpcksum[0] = 0; uh6->udpcksum[1] = 0; - hnputs(uh6->udpcksum, - ptclcsum(bp, UDP6_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP6_PHDR_SZ)); + csum = ptclcsum(bp, UDP6_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP6_PHDR_SZ); + if(csum == 0) + csum = 0xffff; /* -0 */ + hnputs(uh6->udpcksum, csum); memset(uh6, 0, 8); uh6->viclfl[0] = IP_VER6; hnputs(uh6->len, ptcllen); |