Commit | Line | Data |
---|---|---|
acb3e041 CW |
1 | #include <net/ip.h> |
2 | #include <net/udp.h> | |
3 | #include <net/udplite.h> | |
4 | #include <asm/checksum.h> | |
5 | ||
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, | |
10 | __wsum csum) | |
11 | { | |
12 | ||
13 | int carry; | |
14 | __u32 ulen; | |
15 | __u32 uproto; | |
16 | __u32 sum = (__force u32)csum; | |
17 | ||
18 | sum += (__force u32)saddr->s6_addr32[0]; | |
19 | carry = (sum < (__force u32)saddr->s6_addr32[0]); | |
20 | sum += carry; | |
21 | ||
22 | sum += (__force u32)saddr->s6_addr32[1]; | |
23 | carry = (sum < (__force u32)saddr->s6_addr32[1]); | |
24 | sum += carry; | |
25 | ||
26 | sum += (__force u32)saddr->s6_addr32[2]; | |
27 | carry = (sum < (__force u32)saddr->s6_addr32[2]); | |
28 | sum += carry; | |
29 | ||
30 | sum += (__force u32)saddr->s6_addr32[3]; | |
31 | carry = (sum < (__force u32)saddr->s6_addr32[3]); | |
32 | sum += carry; | |
33 | ||
34 | sum += (__force u32)daddr->s6_addr32[0]; | |
35 | carry = (sum < (__force u32)daddr->s6_addr32[0]); | |
36 | sum += carry; | |
37 | ||
38 | sum += (__force u32)daddr->s6_addr32[1]; | |
39 | carry = (sum < (__force u32)daddr->s6_addr32[1]); | |
40 | sum += carry; | |
41 | ||
42 | sum += (__force u32)daddr->s6_addr32[2]; | |
43 | carry = (sum < (__force u32)daddr->s6_addr32[2]); | |
44 | sum += carry; | |
45 | ||
46 | sum += (__force u32)daddr->s6_addr32[3]; | |
47 | carry = (sum < (__force u32)daddr->s6_addr32[3]); | |
48 | sum += carry; | |
49 | ||
50 | ulen = (__force u32)htonl((__u32) len); | |
51 | sum += ulen; | |
52 | carry = (sum < ulen); | |
53 | sum += carry; | |
54 | ||
55 | uproto = (__force u32)htonl(proto); | |
56 | sum += uproto; | |
57 | carry = (sum < uproto); | |
58 | sum += carry; | |
59 | ||
60 | return csum_fold((__force __wsum)sum); | |
61 | } | |
62 | EXPORT_SYMBOL(csum_ipv6_magic); | |
63 | #endif | |
64 | ||
65 | int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto) | |
66 | { | |
67 | int err; | |
68 | ||
69 | UDP_SKB_CB(skb)->partial_cov = 0; | |
70 | UDP_SKB_CB(skb)->cscov = skb->len; | |
71 | ||
72 | if (proto == IPPROTO_UDPLITE) { | |
73 | err = udplite_checksum_init(skb, uh); | |
74 | if (err) | |
75 | return err; | |
76 | } | |
77 | ||
78 | if (uh->check == 0) { | |
79 | /* RFC 2460 section 8.1 says that we SHOULD log | |
80 | this error. Well, it is reasonable. | |
81 | */ | |
84a3e72c BM |
82 | LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n", |
83 | &ipv6_hdr(skb)->saddr, ntohs(uh->source), | |
84 | &ipv6_hdr(skb)->daddr, ntohs(uh->dest)); | |
acb3e041 CW |
85 | return 1; |
86 | } | |
87 | if (skb->ip_summed == CHECKSUM_COMPLETE && | |
88 | !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | |
89 | skb->len, proto, skb->csum)) | |
90 | skb->ip_summed = CHECKSUM_UNNECESSARY; | |
91 | ||
92 | if (!skb_csum_unnecessary(skb)) | |
93 | skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | |
94 | &ipv6_hdr(skb)->daddr, | |
95 | skb->len, proto, 0)); | |
96 | ||
97 | return 0; | |
98 | } | |
99 | EXPORT_SYMBOL(udp6_csum_init); |