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 39static inline __wsum ip6_compute_pseudo(struct sk_buff *skb, int proto) 40{ 41 return ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, 42 &ipv6_hdr(skb)->daddr, 43 skb->len, proto, 0)); 44} 45 46static 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 return ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr, 51 skb_gro_len(skb), proto, 0)); 52} 53 54static __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 62static 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 if (skb->ip_summed == CHECKSUM_PARTIAL) { 69 th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0); 70 skb->csum_start = skb_transport_header(skb) - skb->head; 71 skb->csum_offset = offsetof(struct tcphdr, check); 72 } else { 73 th->check = tcp_v6_check(skb->len, saddr, daddr, 74 csum_partial(th, th->doff << 2, 75 skb->csum)); 76 } 77} 78 79static inline void tcp_v6_gso_csum_prep(struct sk_buff *skb) 80{ 81 struct ipv6hdr *ipv6h = ipv6_hdr(skb); 82 struct tcphdr *th = tcp_hdr(skb); 83 84 ipv6h->payload_len = 0; 85 th->check = ~tcp_v6_check(0, &ipv6h->saddr, &ipv6h->daddr, 0); 86} 87 88static inline __sum16 udp_v6_check(int len, 89 const struct in6_addr *saddr, 90 const struct in6_addr *daddr, 91 __wsum base) 92{ 93 return csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, base); 94} 95 96void udp6_set_csum(bool nocheck, struct sk_buff *skb, 97 const struct in6_addr *saddr, 98 const struct in6_addr *daddr, int len); 99 100int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto); 101#endif 102