1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 #include <net/ip.h> 2 #include <net/ip.h> 3 #include <net/udp.h> 3 #include <net/udp.h> 4 #include <net/udplite.h> 4 #include <net/udplite.h> 5 #include <asm/checksum.h> 5 #include <asm/checksum.h> 6 6 7 #ifndef _HAVE_ARCH_IPV6_CSUM 7 #ifndef _HAVE_ARCH_IPV6_CSUM 8 __sum16 csum_ipv6_magic(const struct in6_addr 8 __sum16 csum_ipv6_magic(const struct in6_addr *saddr, 9 const struct in6_addr 9 const struct in6_addr *daddr, 10 __u32 len, __u8 proto, 10 __u32 len, __u8 proto, __wsum csum) 11 { 11 { 12 12 13 int carry; 13 int carry; 14 __u32 ulen; 14 __u32 ulen; 15 __u32 uproto; 15 __u32 uproto; 16 __u32 sum = (__force u32)csum; 16 __u32 sum = (__force u32)csum; 17 17 18 sum += (__force u32)saddr->s6_addr32[0 18 sum += (__force u32)saddr->s6_addr32[0]; 19 carry = (sum < (__force u32)saddr->s6_ 19 carry = (sum < (__force u32)saddr->s6_addr32[0]); 20 sum += carry; 20 sum += carry; 21 21 22 sum += (__force u32)saddr->s6_addr32[1 22 sum += (__force u32)saddr->s6_addr32[1]; 23 carry = (sum < (__force u32)saddr->s6_ 23 carry = (sum < (__force u32)saddr->s6_addr32[1]); 24 sum += carry; 24 sum += carry; 25 25 26 sum += (__force u32)saddr->s6_addr32[2 26 sum += (__force u32)saddr->s6_addr32[2]; 27 carry = (sum < (__force u32)saddr->s6_ 27 carry = (sum < (__force u32)saddr->s6_addr32[2]); 28 sum += carry; 28 sum += carry; 29 29 30 sum += (__force u32)saddr->s6_addr32[3 30 sum += (__force u32)saddr->s6_addr32[3]; 31 carry = (sum < (__force u32)saddr->s6_ 31 carry = (sum < (__force u32)saddr->s6_addr32[3]); 32 sum += carry; 32 sum += carry; 33 33 34 sum += (__force u32)daddr->s6_addr32[0 34 sum += (__force u32)daddr->s6_addr32[0]; 35 carry = (sum < (__force u32)daddr->s6_ 35 carry = (sum < (__force u32)daddr->s6_addr32[0]); 36 sum += carry; 36 sum += carry; 37 37 38 sum += (__force u32)daddr->s6_addr32[1 38 sum += (__force u32)daddr->s6_addr32[1]; 39 carry = (sum < (__force u32)daddr->s6_ 39 carry = (sum < (__force u32)daddr->s6_addr32[1]); 40 sum += carry; 40 sum += carry; 41 41 42 sum += (__force u32)daddr->s6_addr32[2 42 sum += (__force u32)daddr->s6_addr32[2]; 43 carry = (sum < (__force u32)daddr->s6_ 43 carry = (sum < (__force u32)daddr->s6_addr32[2]); 44 sum += carry; 44 sum += carry; 45 45 46 sum += (__force u32)daddr->s6_addr32[3 46 sum += (__force u32)daddr->s6_addr32[3]; 47 carry = (sum < (__force u32)daddr->s6_ 47 carry = (sum < (__force u32)daddr->s6_addr32[3]); 48 sum += carry; 48 sum += carry; 49 49 50 ulen = (__force u32)htonl((__u32) len) 50 ulen = (__force u32)htonl((__u32) len); 51 sum += ulen; 51 sum += ulen; 52 carry = (sum < ulen); 52 carry = (sum < ulen); 53 sum += carry; 53 sum += carry; 54 54 55 uproto = (__force u32)htonl(proto); 55 uproto = (__force u32)htonl(proto); 56 sum += uproto; 56 sum += uproto; 57 carry = (sum < uproto); 57 carry = (sum < uproto); 58 sum += carry; 58 sum += carry; 59 59 60 return csum_fold((__force __wsum)sum); 60 return csum_fold((__force __wsum)sum); 61 } 61 } 62 EXPORT_SYMBOL(csum_ipv6_magic); 62 EXPORT_SYMBOL(csum_ipv6_magic); 63 #endif 63 #endif 64 64 65 int udp6_csum_init(struct sk_buff *skb, struct 65 int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto) 66 { 66 { 67 int err; 67 int err; 68 68 69 UDP_SKB_CB(skb)->partial_cov = 0; 69 UDP_SKB_CB(skb)->partial_cov = 0; 70 UDP_SKB_CB(skb)->cscov = skb->len; 70 UDP_SKB_CB(skb)->cscov = skb->len; 71 71 72 if (proto == IPPROTO_UDPLITE) { 72 if (proto == IPPROTO_UDPLITE) { 73 err = udplite_checksum_init(sk 73 err = udplite_checksum_init(skb, uh); 74 if (err) 74 if (err) 75 return err; 75 return err; 76 76 77 if (UDP_SKB_CB(skb)->partial_c 77 if (UDP_SKB_CB(skb)->partial_cov) { 78 skb->csum = ip6_comput 78 skb->csum = ip6_compute_pseudo(skb, proto); 79 return 0; 79 return 0; 80 } 80 } 81 } 81 } 82 82 83 /* To support RFC 6936 (allow zero che 83 /* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels) 84 * we accept a checksum of zero here. 84 * we accept a checksum of zero here. When we find the socket 85 * for the UDP packet we'll check if t 85 * for the UDP packet we'll check if that socket allows zero checksum 86 * for IPv6 (set by socket option). 86 * for IPv6 (set by socket option). 87 * 87 * 88 * Note, we are only interested in != 88 * Note, we are only interested in != 0 or == 0, thus the 89 * force to int. 89 * force to int. 90 */ 90 */ 91 err = (__force int)skb_checksum_init_z 91 err = (__force int)skb_checksum_init_zero_check(skb, proto, uh->check, 92 92 ip6_compute_pseudo); 93 if (err) 93 if (err) 94 return err; 94 return err; 95 95 96 if (skb->ip_summed == CHECKSUM_COMPLET 96 if (skb->ip_summed == CHECKSUM_COMPLETE && !skb->csum_valid) { 97 /* If SW calculated the value, 97 /* If SW calculated the value, we know it's bad */ 98 if (skb->csum_complete_sw) 98 if (skb->csum_complete_sw) 99 return 1; 99 return 1; 100 100 101 /* HW says the value is bad. L 101 /* HW says the value is bad. Let's validate that. 102 * skb->csum is no longer the 102 * skb->csum is no longer the full packet checksum, 103 * so don't treat is as such. 103 * so don't treat is as such. 104 */ 104 */ 105 skb_checksum_complete_unset(sk 105 skb_checksum_complete_unset(skb); 106 } 106 } 107 107 108 return 0; 108 return 0; 109 } 109 } 110 EXPORT_SYMBOL(udp6_csum_init); 110 EXPORT_SYMBOL(udp6_csum_init); 111 111 112 /* Function to set UDP checksum for an IPv6 UD 112 /* Function to set UDP checksum for an IPv6 UDP packet. This is intended 113 * for the simple case like when setting the c 113 * for the simple case like when setting the checksum for a UDP tunnel. 114 */ 114 */ 115 void udp6_set_csum(bool nocheck, struct sk_buf 115 void udp6_set_csum(bool nocheck, struct sk_buff *skb, 116 const struct in6_addr *sadd 116 const struct in6_addr *saddr, 117 const struct in6_addr *dadd 117 const struct in6_addr *daddr, int len) 118 { 118 { 119 struct udphdr *uh = udp_hdr(skb); 119 struct udphdr *uh = udp_hdr(skb); 120 120 121 if (nocheck) 121 if (nocheck) 122 uh->check = 0; 122 uh->check = 0; 123 else if (skb_is_gso(skb)) 123 else if (skb_is_gso(skb)) 124 uh->check = ~udp_v6_check(len, 124 uh->check = ~udp_v6_check(len, saddr, daddr, 0); 125 else if (skb->ip_summed == CHECKSUM_PA 125 else if (skb->ip_summed == CHECKSUM_PARTIAL) { 126 uh->check = 0; 126 uh->check = 0; 127 uh->check = udp_v6_check(len, 127 uh->check = udp_v6_check(len, saddr, daddr, lco_csum(skb)); 128 if (uh->check == 0) 128 if (uh->check == 0) 129 uh->check = CSUM_MANGL 129 uh->check = CSUM_MANGLED_0; 130 } else { 130 } else { 131 skb->ip_summed = CHECKSUM_PART 131 skb->ip_summed = CHECKSUM_PARTIAL; 132 skb->csum_start = skb_transpor 132 skb->csum_start = skb_transport_header(skb) - skb->head; 133 skb->csum_offset = offsetof(st 133 skb->csum_offset = offsetof(struct udphdr, check); 134 uh->check = ~udp_v6_check(len, 134 uh->check = ~udp_v6_check(len, saddr, daddr, 0); 135 } 135 } 136 } 136 } 137 EXPORT_SYMBOL(udp6_set_csum); 137 EXPORT_SYMBOL(udp6_set_csum); 138 138
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.