Commit f35d9d8a authored by Rusty Russell's avatar Rusty Russell
Browse files

virtio: Implement skb_partial_csum_set, for setting partial csums on untrusted packets.



Use it in virtio_net (replacing buggy version there), it's also going
to be used by TAP for partial csum support.

Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Acked-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9135f190
Loading
Loading
Loading
Loading
+1 −10
Original line number Diff line number Diff line
@@ -83,18 +83,9 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,

	if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
		pr_debug("Needs csum!\n");
		skb->ip_summed = CHECKSUM_PARTIAL;
		skb->csum_start = hdr->csum_start;
		skb->csum_offset = hdr->csum_offset;
		if (skb->csum_start > skb->len - 2
		    || skb->csum_offset > skb->len - 2) {
			if (net_ratelimit())
				printk(KERN_WARNING "%s: csum=%u/%u len=%u\n",
				       dev->name, skb->csum_start,
				       skb->csum_offset, skb->len);
		if (!skb_partial_csum_set(skb,hdr->csum_start,hdr->csum_offset))
			goto frame_err;
	}
	}

	if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
		pr_debug("GSO!\n");
+1 −0
Original line number Diff line number Diff line
@@ -1810,5 +1810,6 @@ static inline void skb_forward_csum(struct sk_buff *skb)
		skb->ip_summed = CHECKSUM_NONE;
}

bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off);
#endif	/* __KERNEL__ */
#endif	/* _LINUX_SKBUFF_H */
+29 −0
Original line number Diff line number Diff line
@@ -2461,6 +2461,34 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
	return elt;
}

/**
 * skb_partial_csum_set - set up and verify partial csum values for packet
 * @skb: the skb to set
 * @start: the number of bytes after skb->data to start checksumming.
 * @off: the offset from start to place the checksum.
 *
 * For untrusted partially-checksummed packets, we need to make sure the values
 * for skb->csum_start and skb->csum_offset are valid so we don't oops.
 *
 * This function checks and sets those values and skb->ip_summed: if this
 * returns false you should drop the packet.
 */
bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off)
{
	if (unlikely(start > skb->len - 2) ||
	    unlikely((int)start + off > skb->len - 2)) {
		if (net_ratelimit())
			printk(KERN_WARNING
			       "bad partial csum: csum=%u/%u len=%u\n",
			       start, off, skb->len);
		return false;
	}
	skb->ip_summed = CHECKSUM_PARTIAL;
	skb->csum_start = skb_headroom(skb) + start;
	skb->csum_offset = off;
	return true;
}

EXPORT_SYMBOL(___pskb_trim);
EXPORT_SYMBOL(__kfree_skb);
EXPORT_SYMBOL(kfree_skb);
@@ -2497,3 +2525,4 @@ EXPORT_SYMBOL(skb_append_datato_frags);

EXPORT_SYMBOL_GPL(skb_to_sgvec);
EXPORT_SYMBOL_GPL(skb_cow_data);
EXPORT_SYMBOL_GPL(skb_partial_csum_set);