1acb3e041SCong Wang #include <net/ip.h> 2acb3e041SCong Wang #include <net/udp.h> 3acb3e041SCong Wang #include <net/udplite.h> 4acb3e041SCong Wang #include <asm/checksum.h> 5acb3e041SCong Wang 6acb3e041SCong Wang #ifndef _HAVE_ARCH_IPV6_CSUM 7acb3e041SCong Wang __sum16 csum_ipv6_magic(const struct in6_addr *saddr, 8acb3e041SCong Wang const struct in6_addr *daddr, 9acb3e041SCong Wang __u32 len, unsigned short proto, 10acb3e041SCong Wang __wsum csum) 11acb3e041SCong Wang { 12acb3e041SCong Wang 13acb3e041SCong Wang int carry; 14acb3e041SCong Wang __u32 ulen; 15acb3e041SCong Wang __u32 uproto; 16acb3e041SCong Wang __u32 sum = (__force u32)csum; 17acb3e041SCong Wang 18acb3e041SCong Wang sum += (__force u32)saddr->s6_addr32[0]; 19acb3e041SCong Wang carry = (sum < (__force u32)saddr->s6_addr32[0]); 20acb3e041SCong Wang sum += carry; 21acb3e041SCong Wang 22acb3e041SCong Wang sum += (__force u32)saddr->s6_addr32[1]; 23acb3e041SCong Wang carry = (sum < (__force u32)saddr->s6_addr32[1]); 24acb3e041SCong Wang sum += carry; 25acb3e041SCong Wang 26acb3e041SCong Wang sum += (__force u32)saddr->s6_addr32[2]; 27acb3e041SCong Wang carry = (sum < (__force u32)saddr->s6_addr32[2]); 28acb3e041SCong Wang sum += carry; 29acb3e041SCong Wang 30acb3e041SCong Wang sum += (__force u32)saddr->s6_addr32[3]; 31acb3e041SCong Wang carry = (sum < (__force u32)saddr->s6_addr32[3]); 32acb3e041SCong Wang sum += carry; 33acb3e041SCong Wang 34acb3e041SCong Wang sum += (__force u32)daddr->s6_addr32[0]; 35acb3e041SCong Wang carry = (sum < (__force u32)daddr->s6_addr32[0]); 36acb3e041SCong Wang sum += carry; 37acb3e041SCong Wang 38acb3e041SCong Wang sum += (__force u32)daddr->s6_addr32[1]; 39acb3e041SCong Wang carry = (sum < (__force u32)daddr->s6_addr32[1]); 40acb3e041SCong Wang sum += carry; 41acb3e041SCong Wang 42acb3e041SCong Wang sum += (__force u32)daddr->s6_addr32[2]; 43acb3e041SCong Wang carry = (sum < (__force u32)daddr->s6_addr32[2]); 44acb3e041SCong Wang sum += carry; 45acb3e041SCong Wang 46acb3e041SCong Wang sum += (__force u32)daddr->s6_addr32[3]; 47acb3e041SCong Wang carry = (sum < (__force u32)daddr->s6_addr32[3]); 48acb3e041SCong Wang sum += carry; 49acb3e041SCong Wang 50acb3e041SCong Wang ulen = (__force u32)htonl((__u32) len); 51acb3e041SCong Wang sum += ulen; 52acb3e041SCong Wang carry = (sum < ulen); 53acb3e041SCong Wang sum += carry; 54acb3e041SCong Wang 55acb3e041SCong Wang uproto = (__force u32)htonl(proto); 56acb3e041SCong Wang sum += uproto; 57acb3e041SCong Wang carry = (sum < uproto); 58acb3e041SCong Wang sum += carry; 59acb3e041SCong Wang 60acb3e041SCong Wang return csum_fold((__force __wsum)sum); 61acb3e041SCong Wang } 62acb3e041SCong Wang EXPORT_SYMBOL(csum_ipv6_magic); 63acb3e041SCong Wang #endif 64acb3e041SCong Wang 65acb3e041SCong Wang int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto) 66acb3e041SCong Wang { 67acb3e041SCong Wang int err; 68acb3e041SCong Wang 69acb3e041SCong Wang UDP_SKB_CB(skb)->partial_cov = 0; 70acb3e041SCong Wang UDP_SKB_CB(skb)->cscov = skb->len; 71acb3e041SCong Wang 72acb3e041SCong Wang if (proto == IPPROTO_UDPLITE) { 73acb3e041SCong Wang err = udplite_checksum_init(skb, uh); 74acb3e041SCong Wang if (err) 75acb3e041SCong Wang return err; 76acb3e041SCong Wang } 77acb3e041SCong Wang 78*4068579eSTom Herbert /* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels) 79*4068579eSTom Herbert * we accept a checksum of zero here. When we find the socket 80*4068579eSTom Herbert * for the UDP packet we'll check if that socket allows zero checksum 81*4068579eSTom Herbert * for IPv6 (set by socket option). 82acb3e041SCong Wang */ 83*4068579eSTom Herbert return skb_checksum_init_zero_check(skb, proto, uh->check, 84*4068579eSTom Herbert ip6_compute_pseudo); 85acb3e041SCong Wang } 86acb3e041SCong Wang EXPORT_SYMBOL(udp6_csum_init); 87