Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 : : /* 3 : : * INET An implementation of the TCP/IP protocol suite for the LINUX 4 : : * operating system. INET is implemented using the BSD Socket 5 : : * interface as the means of communication with the user level. 6 : : * 7 : : * Checksumming functions for IPv6 8 : : * 9 : : * Authors: Jorge Cwik, <jorge@laser.satlink.net> 10 : : * Arnt Gulbrandsen, <agulbra@nvg.unit.no> 11 : : * Borrows very liberally from tcp.c and ip.c, see those 12 : : * files for more names. 13 : : */ 14 : : 15 : : /* 16 : : * Fixes: 17 : : * 18 : : * Ralf Baechle : generic ipv6 checksum 19 : : * <ralf@waldorf-gmbh.de> 20 : : */ 21 : : 22 : : #ifndef _CHECKSUM_IPV6_H 23 : : #define _CHECKSUM_IPV6_H 24 : : 25 : : #include <asm/types.h> 26 : : #include <asm/byteorder.h> 27 : : #include <net/ip.h> 28 : : #include <asm/checksum.h> 29 : : #include <linux/in6.h> 30 : : #include <linux/tcp.h> 31 : : #include <linux/ipv6.h> 32 : : 33 : : #ifndef _HAVE_ARCH_IPV6_CSUM 34 : : __sum16 csum_ipv6_magic(const struct in6_addr *saddr, 35 : : const struct in6_addr *daddr, 36 : : __u32 len, __u8 proto, __wsum csum); 37 : : #endif 38 : : 39 : 3 : static inline __wsum ip6_compute_pseudo(struct sk_buff *skb, int proto) 40 : : { 41 : 3 : return ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, 42 : 3 : &ipv6_hdr(skb)->daddr, 43 : : skb->len, proto, 0)); 44 : : } 45 : : 46 : 0 : static inline __wsum ip6_gro_compute_pseudo(struct sk_buff *skb, int proto) 47 : : { 48 : : const struct ipv6hdr *iph = skb_gro_network_header(skb); 49 : : 50 : 0 : return ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr, 51 : : skb_gro_len(skb), proto, 0)); 52 : : } 53 : : 54 : : static __inline__ __sum16 tcp_v6_check(int len, 55 : : const struct in6_addr *saddr, 56 : : const struct in6_addr *daddr, 57 : : __wsum base) 58 : : { 59 : : return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base); 60 : : } 61 : : 62 : 0 : static inline void __tcp_v6_send_check(struct sk_buff *skb, 63 : : const struct in6_addr *saddr, 64 : : const struct in6_addr *daddr) 65 : : { 66 : : struct tcphdr *th = tcp_hdr(skb); 67 : : 68 : 0 : if (skb->ip_summed == CHECKSUM_PARTIAL) { 69 : 0 : th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0); 70 : 0 : skb->csum_start = skb_transport_header(skb) - skb->head; 71 : 0 : skb->csum_offset = offsetof(struct tcphdr, check); 72 : : } else { 73 : 0 : th->check = tcp_v6_check(skb->len, saddr, daddr, 74 : 0 : csum_partial(th, th->doff << 2, 75 : : skb->csum)); 76 : : } 77 : 0 : } 78 : : 79 : : #if IS_ENABLED(CONFIG_IPV6) 80 : 0 : static inline void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb) 81 : : { 82 : : struct ipv6_pinfo *np = inet6_sk(sk); 83 : : 84 : 0 : __tcp_v6_send_check(skb, &np->saddr, &sk->sk_v6_daddr); 85 : 0 : } 86 : : #endif 87 : : 88 : : static inline __sum16 udp_v6_check(int len, 89 : : const struct in6_addr *saddr, 90 : : const struct in6_addr *daddr, 91 : : __wsum base) 92 : : { 93 : 0 : return csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, base); 94 : : } 95 : : 96 : : void udp6_set_csum(bool nocheck, struct sk_buff *skb, 97 : : const struct in6_addr *saddr, 98 : : const struct in6_addr *daddr, int len); 99 : : 100 : : int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto); 101 : : #endif