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 0 : static inline __wsum ip6_compute_pseudo(struct sk_buff *skb, int proto)
40 : {
41 0 : return ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
42 0 : &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 0 : 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 0 : 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 0 : 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 0 : 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 : static 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 :
88 0 : 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
|