From: itojun Date: Tue, 1 Aug 2000 17:36:49 +0000 (+0000) Subject: udp header checksum. from netbsd. X-Git-Tag: tcpdump-3.5.1~190 X-Git-Url: https://git.tcpdump.org/tcpdump/commitdiff_plain/cb4e517e9aae83b3bc0beac4ad9fb9f2318a4dd2 udp header checksum. from netbsd. --- diff --git a/print-udp.c b/print-udp.c index ef0266c3..11f60838 100644 --- a/print-udp.c +++ b/print-udp.c @@ -21,7 +21,7 @@ #ifndef lint static const char rcsid[] = - "@(#) $Header: /tcpdump/master/tcpdump/print-udp.c,v 1.75 2000-07-22 23:58:01 assar Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/tcpdump/print-udp.c,v 1.76 2000-08-01 17:36:49 itojun Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -292,6 +292,100 @@ rtcp_print(const u_char *hdr, const u_char *ep) return (hdr + len); } +static int udp_cksum(register const struct ip *ip, + register const struct udphdr *up, + register int len) +{ + int i, tlen; + union phu { + struct phdr { + u_int32_t src; + u_int32_t dst; + u_char mbz; + u_char proto; + u_int16_t len; + } ph; + u_int16_t pa[6]; + } phu; + register const u_int16_t *sp; + u_int32_t sum; + tlen = ntohs(ip->ip_len) - ((const char *)up-(const char*)ip); + + /* pseudo-header.. */ + phu.ph.len = htons(tlen); + phu.ph.mbz = 0; + phu.ph.proto = IPPROTO_UDP; + memcpy(&phu.ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t)); + memcpy(&phu.ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t)); + + sp = &phu.pa[0]; + sum = sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]; + + sp = (const u_int16_t *)up; + + for (i=0; i<(tlen&~1); i+= 2) + sum += *sp++; + + if (tlen & 1) { + sum += htons( (*(const char *)sp) << 8); + } + + while (sum > 0xffff) + sum = (sum & 0xffff) + (sum >> 16); + sum = ~sum & 0xffff; + + return (sum); +} + +#ifdef INET6 +static int udp6_cksum(const struct ip6_hdr *ip6, const struct udphdr *up, + int len) +{ + int i, tlen; + register const u_int16_t *sp; + u_int32_t sum; + union { + struct { + struct in6_addr ph_src; + struct in6_addr ph_dst; + u_int32_t ph_len; + u_int8_t ph_zero[3]; + u_int8_t ph_nxt; + } ph; + u_int16_t pa[20]; + } phu; + + tlen = ntohs(ip6->ip6_plen) + sizeof(struct ip6_hdr) - + ((const char *)up - (const char*)ip6); + + /* pseudo-header */ + memset(&phu, 0, sizeof(phu)); + phu.ph.ph_src = ip6->ip6_src; + phu.ph.ph_dst = ip6->ip6_dst; + phu.ph.ph_len = htonl(tlen); + phu.ph.ph_nxt = IPPROTO_UDP; + + sum = 0; + for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) + sum += phu.pa[i]; + + sp = (const u_int16_t *)up; + + for (i = 0; i < (tlen & ~1); i += 2) + sum += *sp++; + + if (tlen & 1) + sum += htons((*(const char *)sp) << 8); + + while (sum > 0xffff) + sum = (sum & 0xffff) + (sum >> 16); + sum = ~sum & 0xffff; + + return (sum); +} +#endif + + /* XXX probably should use getservbyname() and cache answers */ #define TFTP_PORT 69 /*XXX*/ #define KERBEROS_PORT 88 /*XXX*/ @@ -504,6 +598,32 @@ udp_print(register const u_char *bp, u_int length, register const u_char *bp2) } #endif + if (ip->ip_v == 4 && vflag) { + int sum = up->uh_sum; + if (sum == 0) { + (void)printf(" [no cksum]"); + } else if (TTEST2(cp[0], length)) { + sum = udp_cksum(ip, up, length); + if (sum != 0) + (void)printf(" [bad udp cksum %x!]", sum); + else + (void)printf(" [udp sum ok]"); + } + } +#ifdef INET6 + if (ip->ip_v == 6 && ip6->ip6_plen && vflag) { + int sum = up->uh_sum; + /* for IPv6, UDP checksum is mandatory */ + if (TTEST2(cp[0], length)) { + sum = udp6_cksum(ip6, up, length); + if (sum != 0) + (void)printf(" [bad udp cksum %x!]", sum); + else + (void)printf(" [udp sum ok]"); + } + } +#endif + if (!qflag) { #define ISPORT(p) (dport == (p) || sport == (p)) if (ISPORT(NAMESERVER_PORT))