Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: Handle CHECKSUM_COMPLETE more adequately in pskb_trim_rcsum().

Currently pskb_trim_rcsum() just balks on CHECKSUM_COMPLETE packets
and remarks them as CHECKSUM_NONE, forcing a software checksum
validation later.

We have all of the mechanics available to fixup the skb->csum value,
even for complicated fragmented packets, via the helpers
skb_checksum() and csum_sub().

So just use them.

Based upon a suggestion by Herbert Xu.

Signed-off-by: David S. Miller <davem@davemloft.net>

+21 -18
+21 -18
include/linux/skbuff.h
··· 2263 2263 2264 2264 unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len); 2265 2265 2266 - /** 2267 - * pskb_trim_rcsum - trim received skb and update checksum 2268 - * @skb: buffer to trim 2269 - * @len: new length 2270 - * 2271 - * This is exactly the same as pskb_trim except that it ensures the 2272 - * checksum of received packets are still valid after the operation. 2273 - */ 2274 - 2275 - static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len) 2276 - { 2277 - if (likely(len >= skb->len)) 2278 - return 0; 2279 - if (skb->ip_summed == CHECKSUM_COMPLETE) 2280 - skb->ip_summed = CHECKSUM_NONE; 2281 - return __pskb_trim(skb, len); 2282 - } 2283 - 2284 2266 #define skb_queue_walk(queue, skb) \ 2285 2267 for (skb = (queue)->next; \ 2286 2268 skb != (struct sk_buff *)(queue); \ ··· 2359 2377 __wsum csum, const struct skb_checksum_ops *ops); 2360 2378 __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, 2361 2379 __wsum csum); 2380 + 2381 + /** 2382 + * pskb_trim_rcsum - trim received skb and update checksum 2383 + * @skb: buffer to trim 2384 + * @len: new length 2385 + * 2386 + * This is exactly the same as pskb_trim except that it ensures the 2387 + * checksum of received packets are still valid after the operation. 2388 + */ 2389 + 2390 + static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len) 2391 + { 2392 + if (likely(len >= skb->len)) 2393 + return 0; 2394 + if (skb->ip_summed == CHECKSUM_COMPLETE) { 2395 + __wsum adj = skb_checksum(skb, len, skb->len - len, 0); 2396 + 2397 + skb->csum = csum_sub(skb->csum, adj); 2398 + } 2399 + return __pskb_trim(skb, len); 2400 + } 2362 2401 2363 2402 static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, 2364 2403 int len, void *buffer)