diff options
-rw-r--r-- | drivers/net/virtio_net.c | 11 | ||||
-rw-r--r-- | include/linux/skbuff.h | 1 | ||||
-rw-r--r-- | net/core/skbuff.c | 29 |
3 files changed, 31 insertions, 10 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 5413dbf3d4ac..a60505c8f82a 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c | |||
@@ -83,17 +83,8 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, | |||
83 | 83 | ||
84 | if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { | 84 | if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { |
85 | pr_debug("Needs csum!\n"); | 85 | pr_debug("Needs csum!\n"); |
86 | skb->ip_summed = CHECKSUM_PARTIAL; | 86 | if (!skb_partial_csum_set(skb,hdr->csum_start,hdr->csum_offset)) |
87 | skb->csum_start = hdr->csum_start; | ||
88 | skb->csum_offset = hdr->csum_offset; | ||
89 | if (skb->csum_start > skb->len - 2 | ||
90 | || skb->csum_offset > skb->len - 2) { | ||
91 | if (net_ratelimit()) | ||
92 | printk(KERN_WARNING "%s: csum=%u/%u len=%u\n", | ||
93 | dev->name, skb->csum_start, | ||
94 | skb->csum_offset, skb->len); | ||
95 | goto frame_err; | 87 | goto frame_err; |
96 | } | ||
97 | } | 88 | } |
98 | 89 | ||
99 | if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { | 90 | if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { |
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index dfe975a9967e..412672a79e8a 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -1810,5 +1810,6 @@ static inline void skb_forward_csum(struct sk_buff *skb) | |||
1810 | skb->ip_summed = CHECKSUM_NONE; | 1810 | skb->ip_summed = CHECKSUM_NONE; |
1811 | } | 1811 | } |
1812 | 1812 | ||
1813 | bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off); | ||
1813 | #endif /* __KERNEL__ */ | 1814 | #endif /* __KERNEL__ */ |
1814 | #endif /* _LINUX_SKBUFF_H */ | 1815 | #endif /* _LINUX_SKBUFF_H */ |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 98420f9c4b6d..4e354221ec23 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -2461,6 +2461,34 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) | |||
2461 | return elt; | 2461 | return elt; |
2462 | } | 2462 | } |
2463 | 2463 | ||
2464 | /** | ||
2465 | * skb_partial_csum_set - set up and verify partial csum values for packet | ||
2466 | * @skb: the skb to set | ||
2467 | * @start: the number of bytes after skb->data to start checksumming. | ||
2468 | * @off: the offset from start to place the checksum. | ||
2469 | * | ||
2470 | * For untrusted partially-checksummed packets, we need to make sure the values | ||
2471 | * for skb->csum_start and skb->csum_offset are valid so we don't oops. | ||
2472 | * | ||
2473 | * This function checks and sets those values and skb->ip_summed: if this | ||
2474 | * returns false you should drop the packet. | ||
2475 | */ | ||
2476 | bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off) | ||
2477 | { | ||
2478 | if (unlikely(start > skb->len - 2) || | ||
2479 | unlikely((int)start + off > skb->len - 2)) { | ||
2480 | if (net_ratelimit()) | ||
2481 | printk(KERN_WARNING | ||
2482 | "bad partial csum: csum=%u/%u len=%u\n", | ||
2483 | start, off, skb->len); | ||
2484 | return false; | ||
2485 | } | ||
2486 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
2487 | skb->csum_start = skb_headroom(skb) + start; | ||
2488 | skb->csum_offset = off; | ||
2489 | return true; | ||
2490 | } | ||
2491 | |||
2464 | EXPORT_SYMBOL(___pskb_trim); | 2492 | EXPORT_SYMBOL(___pskb_trim); |
2465 | EXPORT_SYMBOL(__kfree_skb); | 2493 | EXPORT_SYMBOL(__kfree_skb); |
2466 | EXPORT_SYMBOL(kfree_skb); | 2494 | EXPORT_SYMBOL(kfree_skb); |
@@ -2497,3 +2525,4 @@ EXPORT_SYMBOL(skb_append_datato_frags); | |||
2497 | 2525 | ||
2498 | EXPORT_SYMBOL_GPL(skb_to_sgvec); | 2526 | EXPORT_SYMBOL_GPL(skb_to_sgvec); |
2499 | EXPORT_SYMBOL_GPL(skb_cow_data); | 2527 | EXPORT_SYMBOL_GPL(skb_cow_data); |
2528 | EXPORT_SYMBOL_GPL(skb_partial_csum_set); | ||