3 #include <net/udplite.h>
4 #include <asm/checksum.h>
6 #ifndef _HAVE_ARCH_IPV6_CSUM
7 __sum16
csum_ipv6_magic(const struct in6_addr
*saddr
,
8 const struct in6_addr
*daddr
,
9 __u32 len
, __u8 proto
, __wsum csum
)
15 __u32 sum
= (__force u32
)csum
;
17 sum
+= (__force u32
)saddr
->s6_addr32
[0];
18 carry
= (sum
< (__force u32
)saddr
->s6_addr32
[0]);
21 sum
+= (__force u32
)saddr
->s6_addr32
[1];
22 carry
= (sum
< (__force u32
)saddr
->s6_addr32
[1]);
25 sum
+= (__force u32
)saddr
->s6_addr32
[2];
26 carry
= (sum
< (__force u32
)saddr
->s6_addr32
[2]);
29 sum
+= (__force u32
)saddr
->s6_addr32
[3];
30 carry
= (sum
< (__force u32
)saddr
->s6_addr32
[3]);
33 sum
+= (__force u32
)daddr
->s6_addr32
[0];
34 carry
= (sum
< (__force u32
)daddr
->s6_addr32
[0]);
37 sum
+= (__force u32
)daddr
->s6_addr32
[1];
38 carry
= (sum
< (__force u32
)daddr
->s6_addr32
[1]);
41 sum
+= (__force u32
)daddr
->s6_addr32
[2];
42 carry
= (sum
< (__force u32
)daddr
->s6_addr32
[2]);
45 sum
+= (__force u32
)daddr
->s6_addr32
[3];
46 carry
= (sum
< (__force u32
)daddr
->s6_addr32
[3]);
49 ulen
= (__force u32
)htonl((__u32
) len
);
54 uproto
= (__force u32
)htonl(proto
);
56 carry
= (sum
< uproto
);
59 return csum_fold((__force __wsum
)sum
);
61 EXPORT_SYMBOL(csum_ipv6_magic
);
64 int udp6_csum_init(struct sk_buff
*skb
, struct udphdr
*uh
, int proto
)
68 UDP_SKB_CB(skb
)->partial_cov
= 0;
69 UDP_SKB_CB(skb
)->cscov
= skb
->len
;
71 if (proto
== IPPROTO_UDPLITE
) {
72 err
= udplite_checksum_init(skb
, uh
);
77 /* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels)
78 * we accept a checksum of zero here. When we find the socket
79 * for the UDP packet we'll check if that socket allows zero checksum
80 * for IPv6 (set by socket option).
82 * Note, we are only interested in != 0 or == 0, thus the
85 return (__force
int)skb_checksum_init_zero_check(skb
, proto
, uh
->check
,
88 EXPORT_SYMBOL(udp6_csum_init
);
90 /* Function to set UDP checksum for an IPv6 UDP packet. This is intended
91 * for the simple case like when setting the checksum for a UDP tunnel.
93 void udp6_set_csum(bool nocheck
, struct sk_buff
*skb
,
94 const struct in6_addr
*saddr
,
95 const struct in6_addr
*daddr
, int len
)
97 struct udphdr
*uh
= udp_hdr(skb
);
101 else if (skb_is_gso(skb
))
102 uh
->check
= ~udp_v6_check(len
, saddr
, daddr
, 0);
103 else if (skb
->ip_summed
== CHECKSUM_PARTIAL
) {
105 uh
->check
= udp_v6_check(len
, saddr
, daddr
, lco_csum(skb
));
107 uh
->check
= CSUM_MANGLED_0
;
109 skb
->ip_summed
= CHECKSUM_PARTIAL
;
110 skb
->csum_start
= skb_transport_header(skb
) - skb
->head
;
111 skb
->csum_offset
= offsetof(struct udphdr
, check
);
112 uh
->check
= ~udp_v6_check(len
, saddr
, daddr
, 0);
115 EXPORT_SYMBOL(udp6_set_csum
);