diff options
author | Patrick McHardy <kaber@trash.net> | 2008-03-20 10:15:53 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2008-04-14 05:15:49 -0400 |
commit | d63a650736f566a1f9e9434725d2089597c0d2cc (patch) | |
tree | f0a3d5dbc9ced46f95582e4133b55bb70a1ae365 /net/ipv6 | |
parent | 6185f870e293a0a3eae5c81eb0106480cf03dfde (diff) |
[NETFILTER]: Add partial checksum validation helper
Move the UDP-Lite conntrack checksum validation to a generic helper
similar to nf_checksum() and make it fall back to nf_checksum()
in case the full packet is to be checksummed and hardware checksums
are available. This is to be used by DCCP conntrack, which also
needs to verify partial checksums.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/netfilter.c | 42 |
1 files changed, 35 insertions, 7 deletions
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index aed51bcc66b4..8c6c5e71f210 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c | |||
@@ -121,16 +121,44 @@ __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, | |||
121 | } | 121 | } |
122 | return csum; | 122 | return csum; |
123 | } | 123 | } |
124 | |||
125 | EXPORT_SYMBOL(nf_ip6_checksum); | 124 | EXPORT_SYMBOL(nf_ip6_checksum); |
126 | 125 | ||
126 | static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook, | ||
127 | unsigned int dataoff, unsigned int len, | ||
128 | u_int8_t protocol) | ||
129 | { | ||
130 | struct ipv6hdr *ip6h = ipv6_hdr(skb); | ||
131 | __wsum hsum; | ||
132 | __sum16 csum = 0; | ||
133 | |||
134 | switch (skb->ip_summed) { | ||
135 | case CHECKSUM_COMPLETE: | ||
136 | if (len == skb->len - dataoff) | ||
137 | return nf_ip6_checksum(skb, hook, dataoff, protocol); | ||
138 | /* fall through */ | ||
139 | case CHECKSUM_NONE: | ||
140 | hsum = skb_checksum(skb, 0, dataoff, 0); | ||
141 | skb->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr, | ||
142 | &ip6h->daddr, | ||
143 | skb->len - dataoff, | ||
144 | protocol, | ||
145 | csum_sub(0, hsum))); | ||
146 | skb->ip_summed = CHECKSUM_NONE; | ||
147 | csum = __skb_checksum_complete_head(skb, dataoff + len); | ||
148 | if (!csum) | ||
149 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
150 | } | ||
151 | return csum; | ||
152 | }; | ||
153 | |||
127 | static const struct nf_afinfo nf_ip6_afinfo = { | 154 | static const struct nf_afinfo nf_ip6_afinfo = { |
128 | .family = AF_INET6, | 155 | .family = AF_INET6, |
129 | .checksum = nf_ip6_checksum, | 156 | .checksum = nf_ip6_checksum, |
130 | .route = nf_ip6_route, | 157 | .checksum_partial = nf_ip6_checksum_partial, |
131 | .saveroute = nf_ip6_saveroute, | 158 | .route = nf_ip6_route, |
132 | .reroute = nf_ip6_reroute, | 159 | .saveroute = nf_ip6_saveroute, |
133 | .route_key_size = sizeof(struct ip6_rt_info), | 160 | .reroute = nf_ip6_reroute, |
161 | .route_key_size = sizeof(struct ip6_rt_info), | ||
134 | }; | 162 | }; |
135 | 163 | ||
136 | int __init ipv6_netfilter_init(void) | 164 | int __init ipv6_netfilter_init(void) |