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} 62EXPORT_SYMBOL(csum_ipv6_magic); 63#endif 64 65int 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 /* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels) 79 * we accept a checksum of zero here. When we find the socket 80 * for the UDP packet we'll check if that socket allows zero checksum 81 * for IPv6 (set by socket option). 82 */ 83 return skb_checksum_init_zero_check(skb, proto, uh->check, 84 ip6_compute_pseudo); 85} 86EXPORT_SYMBOL(udp6_csum_init); 87 88/* Function to set UDP checksum for an IPv6 UDP packet. This is intended 89 * for the simple case like when setting the checksum for a UDP tunnel. 90 */ 91void udp6_set_csum(bool nocheck, struct sk_buff *skb, 92 const struct in6_addr *saddr, 93 const struct in6_addr *daddr, int len) 94{ 95 struct udphdr *uh = udp_hdr(skb); 96 97 if (nocheck) 98 uh->check = 0; 99 else if (skb_is_gso(skb)) 100 uh->check = ~udp_v6_check(len, saddr, daddr, 0); 101 else if (skb_dst(skb) && skb_dst(skb)->dev && 102 (skb_dst(skb)->dev->features & NETIF_F_IPV6_CSUM)) { 103 104 BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL); 105 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 } else { 111 __wsum csum; 112 113 BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL); 114 115 uh->check = 0; 116 csum = skb_checksum(skb, 0, len, 0); 117 uh->check = udp_v6_check(len, saddr, daddr, csum); 118 if (uh->check == 0) 119 uh->check = CSUM_MANGLED_0; 120 121 skb->ip_summed = CHECKSUM_UNNECESSARY; 122 } 123} 124EXPORT_SYMBOL(udp6_set_csum); 125