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