Commit 2817a336 authored by Daniel Borkmann's avatar Daniel Borkmann Committed by David S. Miller

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: default avatarDaniel Borkmann <dborkman@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent efba721f
...@@ -2360,8 +2360,6 @@ int skb_copy_datagram_const_iovec(const struct sk_buff *from, int offset, ...@@ -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(struct sock *sk, struct sk_buff *skb);
void skb_free_datagram_locked(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); 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_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); 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, __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); ...@@ -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); 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); int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
void skb_scrub_packet(struct sk_buff *skb, bool xnet); void skb_scrub_packet(struct sk_buff *skb, bool xnet);
struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); 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, static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
int len, void *buffer) int len, void *buffer)
{ {
......
...@@ -78,6 +78,12 @@ csum_block_add(__wsum csum, __wsum csum2, int offset) ...@@ -78,6 +78,12 @@ csum_block_add(__wsum csum, __wsum csum2, int offset)
return csum_add(csum, (__force __wsum)sum); 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 static inline __wsum
csum_block_sub(__wsum csum, __wsum csum2, int offset) 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) ...@@ -1928,9 +1928,8 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
EXPORT_SYMBOL(skb_store_bits); EXPORT_SYMBOL(skb_store_bits);
/* Checksum skb data. */ /* Checksum skb data. */
__wsum __skb_checksum(const struct sk_buff *skb, int offset, int len,
__wsum skb_checksum(const struct sk_buff *skb, int offset, __wsum csum, const struct skb_checksum_ops *ops)
int len, __wsum csum)
{ {
int start = skb_headlen(skb); int start = skb_headlen(skb);
int i, copy = start - offset; int i, copy = start - offset;
...@@ -1941,7 +1940,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, ...@@ -1941,7 +1940,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
if (copy > 0) { if (copy > 0) {
if (copy > len) if (copy > len)
copy = len; copy = len;
csum = csum_partial(skb->data + offset, copy, csum); csum = ops->update(skb->data + offset, copy, csum);
if ((len -= copy) == 0) if ((len -= copy) == 0)
return csum; return csum;
offset += copy; offset += copy;
...@@ -1962,10 +1961,10 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, ...@@ -1962,10 +1961,10 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
if (copy > len) if (copy > len)
copy = len; copy = len;
vaddr = kmap_atomic(skb_frag_page(frag)); 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); offset - start, copy, 0);
kunmap_atomic(vaddr); kunmap_atomic(vaddr);
csum = csum_block_add(csum, csum2, pos); csum = ops->combine(csum, csum2, pos, copy);
if (!(len -= copy)) if (!(len -= copy))
return csum; return csum;
offset += copy; offset += copy;
...@@ -1984,9 +1983,9 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, ...@@ -1984,9 +1983,9 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
__wsum csum2; __wsum csum2;
if (copy > len) if (copy > len)
copy = len; copy = len;
csum2 = skb_checksum(frag_iter, offset - start, csum2 = __skb_checksum(frag_iter, offset - start,
copy, 0); copy, 0, ops);
csum = csum_block_add(csum, csum2, pos); csum = ops->combine(csum, csum2, pos, copy);
if ((len -= copy) == 0) if ((len -= copy) == 0)
return csum; return csum;
offset += copy; offset += copy;
...@@ -1998,6 +1997,18 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, ...@@ -1998,6 +1997,18 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
return csum; 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); EXPORT_SYMBOL(skb_checksum);
/* Both of above in one bottle. */ /* Both of above in one bottle. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment