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, __u8 proto, __wsum csum) 10 { 11 12 int carry; 13 __u32 ulen; 14 __u32 uproto; 15 __u32 sum = (__force u32)csum; 16 17 sum += (__force u32)saddr->s6_addr32[0]; 18 carry = (sum < (__force u32)saddr->s6_addr32[0]); 19 sum += carry; 20 21 sum += (__force u32)saddr->s6_addr32[1]; 22 carry = (sum < (__force u32)saddr->s6_addr32[1]); 23 sum += carry; 24 25 sum += (__force u32)saddr->s6_addr32[2]; 26 carry = (sum < (__force u32)saddr->s6_addr32[2]); 27 sum += carry; 28 29 sum += (__force u32)saddr->s6_addr32[3]; 30 carry = (sum < (__force u32)saddr->s6_addr32[3]); 31 sum += carry; 32 33 sum += (__force u32)daddr->s6_addr32[0]; 34 carry = (sum < (__force u32)daddr->s6_addr32[0]); 35 sum += carry; 36 37 sum += (__force u32)daddr->s6_addr32[1]; 38 carry = (sum < (__force u32)daddr->s6_addr32[1]); 39 sum += carry; 40 41 sum += (__force u32)daddr->s6_addr32[2]; 42 carry = (sum < (__force u32)daddr->s6_addr32[2]); 43 sum += carry; 44 45 sum += (__force u32)daddr->s6_addr32[3]; 46 carry = (sum < (__force u32)daddr->s6_addr32[3]); 47 sum += carry; 48 49 ulen = (__force u32)htonl((__u32) len); 50 sum += ulen; 51 carry = (sum < ulen); 52 sum += carry; 53 54 uproto = (__force u32)htonl(proto); 55 sum += uproto; 56 carry = (sum < uproto); 57 sum += carry; 58 59 return csum_fold((__force __wsum)sum); 60 } 61 EXPORT_SYMBOL(csum_ipv6_magic); 62 #endif 63 64 int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto) 65 { 66 int err; 67 68 UDP_SKB_CB(skb)->partial_cov = 0; 69 UDP_SKB_CB(skb)->cscov = skb->len; 70 71 if (proto == IPPROTO_UDPLITE) { 72 err = udplite_checksum_init(skb, uh); 73 if (err) 74 return err; 75 } 76 77 /* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels) 78 * we accept a checksum of zero here. When we find the socket 79 * for the UDP packet we'll check if that socket allows zero checksum 80 * for IPv6 (set by socket option). 81 */ 82 return skb_checksum_init_zero_check(skb, proto, uh->check, 83 ip6_compute_pseudo); 84 } 85 EXPORT_SYMBOL(udp6_csum_init); 86 87 /* Function to set UDP checksum for an IPv6 UDP packet. This is intended 88 * for the simple case like when setting the checksum for a UDP tunnel. 89 */ 90 void udp6_set_csum(bool nocheck, struct sk_buff *skb, 91 const struct in6_addr *saddr, 92 const struct in6_addr *daddr, int len) 93 { 94 struct udphdr *uh = udp_hdr(skb); 95 96 if (nocheck) 97 uh->check = 0; 98 else if (skb_is_gso(skb)) 99 uh->check = ~udp_v6_check(len, saddr, daddr, 0); 100 else if (skb->ip_summed == CHECKSUM_PARTIAL) { 101 uh->check = 0; 102 uh->check = udp_v6_check(len, saddr, daddr, lco_csum(skb)); 103 if (uh->check == 0) 104 uh->check = CSUM_MANGLED_0; 105 } else { 106 skb->ip_summed = CHECKSUM_PARTIAL; 107 skb->csum_start = skb_transport_header(skb) - skb->head; 108 skb->csum_offset = offsetof(struct udphdr, check); 109 uh->check = ~udp_v6_check(len, saddr, daddr, 0); 110 } 111 } 112 EXPORT_SYMBOL(udp6_set_csum); 113