diff options
author | Daniel Borkmann <dborkman@redhat.com> | 2013-10-30 06:50:51 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-11-03 23:04:57 -0500 |
commit | 2817a336d4d533fb8b68719723cd60ea7dd7c09e (patch) | |
tree | 71aac3aa2a48588fd0b5372cca9499bd1cbe2a5f /net/core/skbuff.c | |
parent | efba721f636ee016859d86d15748650119402b10 (diff) |
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>
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r-- | net/core/skbuff.c | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 0ab32faa520f..31aab5376cb4 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -1928,9 +1928,8 @@ fault: | |||
1928 | EXPORT_SYMBOL(skb_store_bits); | 1928 | EXPORT_SYMBOL(skb_store_bits); |
1929 | 1929 | ||
1930 | /* Checksum skb data. */ | 1930 | /* Checksum skb data. */ |
1931 | 1931 | __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len, | |
1932 | __wsum skb_checksum(const struct sk_buff *skb, int offset, | 1932 | __wsum csum, const struct skb_checksum_ops *ops) |
1933 | int len, __wsum csum) | ||
1934 | { | 1933 | { |
1935 | int start = skb_headlen(skb); | 1934 | int start = skb_headlen(skb); |
1936 | int i, copy = start - offset; | 1935 | int i, copy = start - offset; |
@@ -1941,7 +1940,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, | |||
1941 | if (copy > 0) { | 1940 | if (copy > 0) { |
1942 | if (copy > len) | 1941 | if (copy > len) |
1943 | copy = len; | 1942 | copy = len; |
1944 | csum = csum_partial(skb->data + offset, copy, csum); | 1943 | csum = ops->update(skb->data + offset, copy, csum); |
1945 | if ((len -= copy) == 0) | 1944 | if ((len -= copy) == 0) |
1946 | return csum; | 1945 | return csum; |
1947 | offset += copy; | 1946 | offset += copy; |
@@ -1962,10 +1961,10 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, | |||
1962 | if (copy > len) | 1961 | if (copy > len) |
1963 | copy = len; | 1962 | copy = len; |
1964 | vaddr = kmap_atomic(skb_frag_page(frag)); | 1963 | vaddr = kmap_atomic(skb_frag_page(frag)); |
1965 | csum2 = csum_partial(vaddr + frag->page_offset + | 1964 | csum2 = ops->update(vaddr + frag->page_offset + |
1966 | offset - start, copy, 0); | 1965 | offset - start, copy, 0); |
1967 | kunmap_atomic(vaddr); | 1966 | kunmap_atomic(vaddr); |
1968 | csum = csum_block_add(csum, csum2, pos); | 1967 | csum = ops->combine(csum, csum2, pos, copy); |
1969 | if (!(len -= copy)) | 1968 | if (!(len -= copy)) |
1970 | return csum; | 1969 | return csum; |
1971 | offset += copy; | 1970 | offset += copy; |
@@ -1984,9 +1983,9 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, | |||
1984 | __wsum csum2; | 1983 | __wsum csum2; |
1985 | if (copy > len) | 1984 | if (copy > len) |
1986 | copy = len; | 1985 | copy = len; |
1987 | csum2 = skb_checksum(frag_iter, offset - start, | 1986 | csum2 = __skb_checksum(frag_iter, offset - start, |
1988 | copy, 0); | 1987 | copy, 0, ops); |
1989 | csum = csum_block_add(csum, csum2, pos); | 1988 | csum = ops->combine(csum, csum2, pos, copy); |
1990 | if ((len -= copy) == 0) | 1989 | if ((len -= copy) == 0) |
1991 | return csum; | 1990 | return csum; |
1992 | offset += copy; | 1991 | offset += copy; |
@@ -1998,6 +1997,18 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset, | |||
1998 | 1997 | ||
1999 | return csum; | 1998 | return csum; |
2000 | } | 1999 | } |
2000 | EXPORT_SYMBOL(__skb_checksum); | ||
2001 | |||
2002 | __wsum skb_checksum(const struct sk_buff *skb, int offset, | ||
2003 | int len, __wsum csum) | ||
2004 | { | ||
2005 | const struct skb_checksum_ops ops = { | ||
2006 | .update = csum_partial, | ||
2007 | .combine = csum_block_add_ext, | ||
2008 | }; | ||
2009 | |||
2010 | return __skb_checksum(skb, offset, len, csum, &ops); | ||
2011 | } | ||
2001 | EXPORT_SYMBOL(skb_checksum); | 2012 | EXPORT_SYMBOL(skb_checksum); |
2002 | 2013 | ||
2003 | /* Both of above in one bottle. */ | 2014 | /* Both of above in one bottle. */ |