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
, unsigned short proto
,
16 __u32 sum
= (__force u32
)csum
;
18 sum
+= (__force u32
)saddr
->s6_addr32
[0];
19 carry
= (sum
< (__force u32
)saddr
->s6_addr32
[0]);
22 sum
+= (__force u32
)saddr
->s6_addr32
[1];
23 carry
= (sum
< (__force u32
)saddr
->s6_addr32
[1]);
26 sum
+= (__force u32
)saddr
->s6_addr32
[2];
27 carry
= (sum
< (__force u32
)saddr
->s6_addr32
[2]);
30 sum
+= (__force u32
)saddr
->s6_addr32
[3];
31 carry
= (sum
< (__force u32
)saddr
->s6_addr32
[3]);
34 sum
+= (__force u32
)daddr
->s6_addr32
[0];
35 carry
= (sum
< (__force u32
)daddr
->s6_addr32
[0]);
38 sum
+= (__force u32
)daddr
->s6_addr32
[1];
39 carry
= (sum
< (__force u32
)daddr
->s6_addr32
[1]);
42 sum
+= (__force u32
)daddr
->s6_addr32
[2];
43 carry
= (sum
< (__force u32
)daddr
->s6_addr32
[2]);
46 sum
+= (__force u32
)daddr
->s6_addr32
[3];
47 carry
= (sum
< (__force u32
)daddr
->s6_addr32
[3]);
50 ulen
= (__force u32
)htonl((__u32
) len
);
55 uproto
= (__force u32
)htonl(proto
);
57 carry
= (sum
< uproto
);
60 return csum_fold((__force __wsum
)sum
);
62 EXPORT_SYMBOL(csum_ipv6_magic
);
65 int udp6_csum_init(struct sk_buff
*skb
, struct udphdr
*uh
, int proto
)
69 UDP_SKB_CB(skb
)->partial_cov
= 0;
70 UDP_SKB_CB(skb
)->cscov
= skb
->len
;
72 if (proto
== IPPROTO_UDPLITE
) {
73 err
= udplite_checksum_init(skb
, uh
);
78 /* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels)
79 * we accept a checksum of zero here. When we find the socket
80 * for the UDP packet we'll check if that socket allows zero checksum
81 * for IPv6 (set by socket option).
83 return skb_checksum_init_zero_check(skb
, proto
, uh
->check
,
86 EXPORT_SYMBOL(udp6_csum_init
);
88 /* Function to set UDP checksum for an IPv6 UDP packet. This is intended
89 * for the simple case like when setting the checksum for a UDP tunnel.
91 void udp6_set_csum(bool nocheck
, struct sk_buff
*skb
,
92 const struct in6_addr
*saddr
,
93 const struct in6_addr
*daddr
, int len
)
95 struct udphdr
*uh
= udp_hdr(skb
);
99 else if (skb_is_gso(skb
))
100 uh
->check
= ~udp_v6_check(len
, saddr
, daddr
, 0);
101 else if (skb_dst(skb
) && skb_dst(skb
)->dev
&&
102 (skb_dst(skb
)->dev
->features
& NETIF_F_IPV6_CSUM
)) {
104 BUG_ON(skb
->ip_summed
== CHECKSUM_PARTIAL
);
106 skb
->ip_summed
= CHECKSUM_PARTIAL
;
107 skb
->csum_start
= skb_transport_header(skb
) - skb
->head
;
108 skb
->csum_offset
= offsetof(struct udphdr
, check
);
109 uh
->check
= ~udp_v6_check(len
, saddr
, daddr
, 0);
113 BUG_ON(skb
->ip_summed
== CHECKSUM_PARTIAL
);
116 csum
= skb_checksum(skb
, 0, len
, 0);
117 uh
->check
= udp_v6_check(len
, saddr
, daddr
, csum
);
119 uh
->check
= CSUM_MANGLED_0
;
121 skb
->ip_summed
= CHECKSUM_UNNECESSARY
;
124 EXPORT_SYMBOL(udp6_set_csum
);