forked from mirrors/linux
		
	net: skb_checksum: allow custom update/combine for walking skb
Currently, skb_checksum walks over 1) linearized, 2) frags[], and 3) frag_list data and calculats the one's complement, a 32 bit result suitable for feeding into itself or csum_tcpudp_magic(), but unsuitable for SCTP as we're calculating CRC32c there. Hence, in order to not re-implement the very same function in SCTP (and maybe other protocols) over and over again, use an update() + combine() callback internally to allow for walking over the skb with different algorithms. Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									efba721f63
								
							
						
					
					
						commit
						2817a336d4
					
				
					 3 changed files with 37 additions and 13 deletions
				
			
		| 
						 | 
				
			
			@ -2360,8 +2360,6 @@ int skb_copy_datagram_const_iovec(const struct sk_buff *from, int offset,
 | 
			
		|||
void skb_free_datagram(struct sock *sk, struct sk_buff *skb);
 | 
			
		||||
void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb);
 | 
			
		||||
int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags);
 | 
			
		||||
__wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
 | 
			
		||||
		    __wsum csum);
 | 
			
		||||
int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
 | 
			
		||||
int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);
 | 
			
		||||
__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,
 | 
			
		||||
| 
						 | 
				
			
			@ -2373,9 +2371,18 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
 | 
			
		|||
void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len);
 | 
			
		||||
int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
 | 
			
		||||
void skb_scrub_packet(struct sk_buff *skb, bool xnet);
 | 
			
		||||
 | 
			
		||||
struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
 | 
			
		||||
 | 
			
		||||
struct skb_checksum_ops {
 | 
			
		||||
	__wsum (*update)(const void *mem, int len, __wsum wsum);
 | 
			
		||||
	__wsum (*combine)(__wsum csum, __wsum csum2, int offset, int len);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
__wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
 | 
			
		||||
		      __wsum csum, const struct skb_checksum_ops *ops);
 | 
			
		||||
__wsum skb_checksum(const struct sk_buff *skb, int offset, int len,
 | 
			
		||||
		    __wsum csum);
 | 
			
		||||
 | 
			
		||||
static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
 | 
			
		||||
				       int len, void *buffer)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -78,6 +78,12 @@ csum_block_add(__wsum csum, __wsum csum2, int offset)
 | 
			
		|||
	return csum_add(csum, (__force __wsum)sum);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __wsum
 | 
			
		||||
csum_block_add_ext(__wsum csum, __wsum csum2, int offset, int len)
 | 
			
		||||
{
 | 
			
		||||
	return csum_block_add(csum, csum2, offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline __wsum
 | 
			
		||||
csum_block_sub(__wsum csum, __wsum csum2, int offset)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1928,9 +1928,8 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
 | 
			
		|||
EXPORT_SYMBOL(skb_store_bits);
 | 
			
		||||
 | 
			
		||||
/* Checksum skb data. */
 | 
			
		||||
 | 
			
		||||
__wsum skb_checksum(const struct sk_buff *skb, int offset,
 | 
			
		||||
			  int len, __wsum csum)
 | 
			
		||||
__wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
 | 
			
		||||
		      __wsum csum, const struct skb_checksum_ops *ops)
 | 
			
		||||
{
 | 
			
		||||
	int start = skb_headlen(skb);
 | 
			
		||||
	int i, copy = start - offset;
 | 
			
		||||
| 
						 | 
				
			
			@ -1941,7 +1940,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
 | 
			
		|||
	if (copy > 0) {
 | 
			
		||||
		if (copy > len)
 | 
			
		||||
			copy = len;
 | 
			
		||||
		csum = csum_partial(skb->data + offset, copy, csum);
 | 
			
		||||
		csum = ops->update(skb->data + offset, copy, csum);
 | 
			
		||||
		if ((len -= copy) == 0)
 | 
			
		||||
			return csum;
 | 
			
		||||
		offset += copy;
 | 
			
		||||
| 
						 | 
				
			
			@ -1962,10 +1961,10 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
 | 
			
		|||
			if (copy > len)
 | 
			
		||||
				copy = len;
 | 
			
		||||
			vaddr = kmap_atomic(skb_frag_page(frag));
 | 
			
		||||
			csum2 = csum_partial(vaddr + frag->page_offset +
 | 
			
		||||
			csum2 = ops->update(vaddr + frag->page_offset +
 | 
			
		||||
					    offset - start, copy, 0);
 | 
			
		||||
			kunmap_atomic(vaddr);
 | 
			
		||||
			csum = csum_block_add(csum, csum2, pos);
 | 
			
		||||
			csum = ops->combine(csum, csum2, pos, copy);
 | 
			
		||||
			if (!(len -= copy))
 | 
			
		||||
				return csum;
 | 
			
		||||
			offset += copy;
 | 
			
		||||
| 
						 | 
				
			
			@ -1984,9 +1983,9 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
 | 
			
		|||
			__wsum csum2;
 | 
			
		||||
			if (copy > len)
 | 
			
		||||
				copy = len;
 | 
			
		||||
			csum2 = skb_checksum(frag_iter, offset - start,
 | 
			
		||||
					     copy, 0);
 | 
			
		||||
			csum = csum_block_add(csum, csum2, pos);
 | 
			
		||||
			csum2 = __skb_checksum(frag_iter, offset - start,
 | 
			
		||||
					       copy, 0, ops);
 | 
			
		||||
			csum = ops->combine(csum, csum2, pos, copy);
 | 
			
		||||
			if ((len -= copy) == 0)
 | 
			
		||||
				return csum;
 | 
			
		||||
			offset += copy;
 | 
			
		||||
| 
						 | 
				
			
			@ -1998,6 +1997,18 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
 | 
			
		|||
 | 
			
		||||
	return csum;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(__skb_checksum);
 | 
			
		||||
 | 
			
		||||
__wsum skb_checksum(const struct sk_buff *skb, int offset,
 | 
			
		||||
		    int len, __wsum csum)
 | 
			
		||||
{
 | 
			
		||||
	const struct skb_checksum_ops ops = {
 | 
			
		||||
		.update  = csum_partial,
 | 
			
		||||
		.combine = csum_block_add_ext,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	return __skb_checksum(skb, offset, len, csum, &ops);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(skb_checksum);
 | 
			
		||||
 | 
			
		||||
/* Both of above in one bottle. */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue