1 #include <net/ip.h> 2 #include <net/udp.h> 3 #include <net/udplite.h> 4 #include <asm/checksum.h> 5 6 #ifndef _HAVE_ARCH_IPV6_CSUM 7 __sum16 csum_ipv6_magic(const struct in6_addr *saddr, 8 const struct in6_addr *daddr, 9 __u32 len, unsigned short proto, 10 __wsum csum) 11 { 12 13 int carry; 14 __u32 ulen; 15 __u32 uproto; 16 __u32 sum = (__force u32)csum; 17 18 sum += (__force u32)saddr->s6_addr32[0]; 19 carry = (sum < (__force u32)saddr->s6_addr32[0]); 20 sum += carry; 21 22 sum += (__force u32)saddr->s6_addr32[1]; 23 carry = (sum < (__force u32)saddr->s6_addr32[1]); 24 sum += carry; 25 26 sum += (__force u32)saddr->s6_addr32[2]; 27 carry = (sum < (__force u32)saddr->s6_addr32[2]); 28 sum += carry; 29 30 sum += (__force u32)saddr->s6_addr32[3]; 31 carry = (sum < (__force u32)saddr->s6_addr32[3]); 32 sum += carry; 33 34 sum += (__force u32)daddr->s6_addr32[0]; 35 carry = (sum < (__force u32)daddr->s6_addr32[0]); 36 sum += carry; 37 38 sum += (__force u32)daddr->s6_addr32[1]; 39 carry = (sum < (__force u32)daddr->s6_addr32[1]); 40 sum += carry; 41 42 sum += (__force u32)daddr->s6_addr32[2]; 43 carry = (sum < (__force u32)daddr->s6_addr32[2]); 44 sum += carry; 45 46 sum += (__force u32)daddr->s6_addr32[3]; 47 carry = (sum < (__force u32)daddr->s6_addr32[3]); 48 sum += carry; 49 50 ulen = (__force u32)htonl((__u32) len); 51 sum += ulen; 52 carry = (sum < ulen); 53 sum += carry; 54 55 uproto = (__force u32)htonl(proto); 56 sum += uproto; 57 carry = (sum < uproto); 58 sum += carry; 59 60 return csum_fold((__force __wsum)sum); 61 } 62 EXPORT_SYMBOL(csum_ipv6_magic); 63 #endif 64 65 int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto) 66 { 67 int err; 68 69 UDP_SKB_CB(skb)->partial_cov = 0; 70 UDP_SKB_CB(skb)->cscov = skb->len; 71 72 if (proto == IPPROTO_UDPLITE) { 73 err = udplite_checksum_init(skb, uh); 74 if (err) 75 return err; 76 } 77 78 if (uh->check == 0) { 79 /* RFC 2460 section 8.1 says that we SHOULD log 80 this error. Well, it is reasonable. 81 */ 82 LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n", 83 &ipv6_hdr(skb)->saddr, ntohs(uh->source), 84 &ipv6_hdr(skb)->daddr, ntohs(uh->dest)); 85 return 1; 86 } 87 if (skb->ip_summed == CHECKSUM_COMPLETE && 88 !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, 89 skb->len, proto, skb->csum)) 90 skb->ip_summed = CHECKSUM_UNNECESSARY; 91 92 if (!skb_csum_unnecessary(skb)) 93 skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, 94 &ipv6_hdr(skb)->daddr, 95 skb->len, proto, 0)); 96 97 return 0; 98 } 99 EXPORT_SYMBOL(udp6_csum_init); 100