diff options
| author | David S. Miller <davem@davemloft.net> | 2013-11-03 23:05:16 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-11-03 23:05:16 -0500 |
| commit | b397f99921827e114d7f5600447e172a99c50165 (patch) | |
| tree | de3bbb3dc4e08fd17fcde46aedb239d274e45d6b /include | |
| parent | 296c10639a33941d0090afa17b7535fcbf81d97a (diff) | |
| parent | e6d8b64b34aa8a9fe39609bc2db8a243b0331ceb (diff) | |
Merge branch 'sctp_csum'
Daniel Borkmann says:
====================
SCTP fix/updates
Please see patch 5 for the main description/motivation, the rest just
brings in the needed functionality for that. Although this is actually
a fix, I've based it against net-next as some additional work for
fixing it was needed.
====================
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Acked-by: Vlad Yasevich <vyasevich@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include')
| -rw-r--r-- | include/linux/crc32.h | 40 | ||||
| -rw-r--r-- | include/linux/skbuff.h | 13 | ||||
| -rw-r--r-- | include/net/checksum.h | 6 | ||||
| -rw-r--r-- | include/net/sctp/checksum.h | 56 |
4 files changed, 75 insertions, 40 deletions
diff --git a/include/linux/crc32.h b/include/linux/crc32.h index 68267b64bb98..7d275c4fc011 100644 --- a/include/linux/crc32.h +++ b/include/linux/crc32.h | |||
| @@ -11,8 +11,48 @@ | |||
| 11 | extern u32 crc32_le(u32 crc, unsigned char const *p, size_t len); | 11 | extern u32 crc32_le(u32 crc, unsigned char const *p, size_t len); |
| 12 | extern u32 crc32_be(u32 crc, unsigned char const *p, size_t len); | 12 | extern u32 crc32_be(u32 crc, unsigned char const *p, size_t len); |
| 13 | 13 | ||
| 14 | /** | ||
| 15 | * crc32_le_combine - Combine two crc32 check values into one. For two | ||
| 16 | * sequences of bytes, seq1 and seq2 with lengths len1 | ||
| 17 | * and len2, crc32_le() check values were calculated | ||
| 18 | * for each, crc1 and crc2. | ||
| 19 | * | ||
| 20 | * @crc1: crc32 of the first block | ||
| 21 | * @crc2: crc32 of the second block | ||
| 22 | * @len2: length of the second block | ||
| 23 | * | ||
| 24 | * Return: The crc32_le() check value of seq1 and seq2 concatenated, | ||
| 25 | * requiring only crc1, crc2, and len2. Note: If seq_full denotes | ||
| 26 | * the concatenated memory area of seq1 with seq2, and crc_full | ||
| 27 | * the crc32_le() value of seq_full, then crc_full == | ||
| 28 | * crc32_le_combine(crc1, crc2, len2) when crc_full was seeded | ||
| 29 | * with the same initializer as crc1, and crc2 seed was 0. See | ||
| 30 | * also crc32_combine_test(). | ||
| 31 | */ | ||
| 32 | extern u32 crc32_le_combine(u32 crc1, u32 crc2, size_t len2); | ||
| 33 | |||
| 14 | extern u32 __crc32c_le(u32 crc, unsigned char const *p, size_t len); | 34 | extern u32 __crc32c_le(u32 crc, unsigned char const *p, size_t len); |
| 15 | 35 | ||
| 36 | /** | ||
| 37 | * __crc32c_le_combine - Combine two crc32c check values into one. For two | ||
| 38 | * sequences of bytes, seq1 and seq2 with lengths len1 | ||
| 39 | * and len2, __crc32c_le() check values were calculated | ||
| 40 | * for each, crc1 and crc2. | ||
| 41 | * | ||
| 42 | * @crc1: crc32c of the first block | ||
| 43 | * @crc2: crc32c of the second block | ||
| 44 | * @len2: length of the second block | ||
| 45 | * | ||
| 46 | * Return: The __crc32c_le() check value of seq1 and seq2 concatenated, | ||
| 47 | * requiring only crc1, crc2, and len2. Note: If seq_full denotes | ||
| 48 | * the concatenated memory area of seq1 with seq2, and crc_full | ||
| 49 | * the __crc32c_le() value of seq_full, then crc_full == | ||
| 50 | * __crc32c_le_combine(crc1, crc2, len2) when crc_full was | ||
| 51 | * seeded with the same initializer as crc1, and crc2 seed | ||
| 52 | * was 0. See also crc32c_combine_test(). | ||
| 53 | */ | ||
| 54 | extern u32 __crc32c_le_combine(u32 crc1, u32 crc2, size_t len2); | ||
| 55 | |||
| 16 | #define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)(data), length) | 56 | #define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)(data), length) |
| 17 | 57 | ||
| 18 | /* | 58 | /* |
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 2c154976394b..44727b5d4981 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
| @@ -2360,8 +2360,6 @@ int skb_copy_datagram_const_iovec(const struct sk_buff *from, int offset, | |||
| 2360 | void skb_free_datagram(struct sock *sk, struct sk_buff *skb); | 2360 | void skb_free_datagram(struct sock *sk, struct sk_buff *skb); |
| 2361 | void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb); | 2361 | void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb); |
| 2362 | int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags); | 2362 | int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags); |
| 2363 | __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, | ||
| 2364 | __wsum csum); | ||
| 2365 | int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len); | 2363 | int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len); |
| 2366 | int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len); | 2364 | int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len); |
| 2367 | __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, | 2365 | __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 | void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len); | 2371 | void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len); |
| 2374 | int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen); | 2372 | int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen); |
| 2375 | void skb_scrub_packet(struct sk_buff *skb, bool xnet); | 2373 | void skb_scrub_packet(struct sk_buff *skb, bool xnet); |
| 2376 | |||
| 2377 | struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); | 2374 | struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); |
| 2378 | 2375 | ||
| 2376 | struct skb_checksum_ops { | ||
| 2377 | __wsum (*update)(const void *mem, int len, __wsum wsum); | ||
| 2378 | __wsum (*combine)(__wsum csum, __wsum csum2, int offset, int len); | ||
| 2379 | }; | ||
| 2380 | |||
| 2381 | __wsum __skb_checksum(const struct sk_buff *skb, int offset, int len, | ||
| 2382 | __wsum csum, const struct skb_checksum_ops *ops); | ||
| 2383 | __wsum skb_checksum(const struct sk_buff *skb, int offset, int len, | ||
| 2384 | __wsum csum); | ||
| 2385 | |||
| 2379 | static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, | 2386 | static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, |
| 2380 | int len, void *buffer) | 2387 | int len, void *buffer) |
| 2381 | { | 2388 | { |
diff --git a/include/net/checksum.h b/include/net/checksum.h index 8f59ca50477c..15f33fde826e 100644 --- a/include/net/checksum.h +++ b/include/net/checksum.h | |||
| @@ -79,6 +79,12 @@ csum_block_add(__wsum csum, __wsum csum2, int offset) | |||
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | static inline __wsum | 81 | static inline __wsum |
| 82 | csum_block_add_ext(__wsum csum, __wsum csum2, int offset, int len) | ||
| 83 | { | ||
| 84 | return csum_block_add(csum, csum2, offset); | ||
| 85 | } | ||
| 86 | |||
| 87 | static inline __wsum | ||
| 82 | csum_block_sub(__wsum csum, __wsum csum2, int offset) | 88 | csum_block_sub(__wsum csum, __wsum csum2, int offset) |
| 83 | { | 89 | { |
| 84 | u32 sum = (__force u32)csum2; | 90 | u32 sum = (__force u32)csum2; |
diff --git a/include/net/sctp/checksum.h b/include/net/sctp/checksum.h index 259924d63ba6..6bd44fe94c26 100644 --- a/include/net/sctp/checksum.h +++ b/include/net/sctp/checksum.h | |||
| @@ -42,56 +42,38 @@ | |||
| 42 | #include <linux/types.h> | 42 | #include <linux/types.h> |
| 43 | #include <net/sctp/sctp.h> | 43 | #include <net/sctp/sctp.h> |
| 44 | #include <linux/crc32c.h> | 44 | #include <linux/crc32c.h> |
| 45 | #include <linux/crc32.h> | ||
| 45 | 46 | ||
| 46 | static inline __u32 sctp_crc32c(__u32 crc, u8 *buffer, u16 length) | 47 | static inline __wsum sctp_csum_update(const void *buff, int len, __wsum sum) |
| 47 | { | 48 | { |
| 48 | return crc32c(crc, buffer, length); | 49 | /* This uses the crypto implementation of crc32c, which is either |
| 49 | } | 50 | * implemented w/ hardware support or resolves to __crc32c_le(). |
| 50 | |||
| 51 | static inline __u32 sctp_start_cksum(__u8 *buffer, __u16 length) | ||
| 52 | { | ||
| 53 | __u32 crc = ~(__u32)0; | ||
| 54 | __u8 zero[sizeof(__u32)] = {0}; | ||
| 55 | |||
| 56 | /* Optimize this routine to be SCTP specific, knowing how | ||
| 57 | * to skip the checksum field of the SCTP header. | ||
| 58 | */ | 51 | */ |
| 59 | 52 | return crc32c(sum, buff, len); | |
| 60 | /* Calculate CRC up to the checksum. */ | ||
| 61 | crc = sctp_crc32c(crc, buffer, sizeof(struct sctphdr) - sizeof(__u32)); | ||
| 62 | |||
| 63 | /* Skip checksum field of the header. */ | ||
| 64 | crc = sctp_crc32c(crc, zero, sizeof(__u32)); | ||
| 65 | |||
| 66 | /* Calculate the rest of the CRC. */ | ||
| 67 | crc = sctp_crc32c(crc, &buffer[sizeof(struct sctphdr)], | ||
| 68 | length - sizeof(struct sctphdr)); | ||
| 69 | return crc; | ||
| 70 | } | ||
| 71 | |||
| 72 | static inline __u32 sctp_update_cksum(__u8 *buffer, __u16 length, __u32 crc32) | ||
| 73 | { | ||
| 74 | return sctp_crc32c(crc32, buffer, length); | ||
| 75 | } | 53 | } |
| 76 | 54 | ||
| 77 | static inline __le32 sctp_end_cksum(__u32 crc32) | 55 | static inline __wsum sctp_csum_combine(__wsum csum, __wsum csum2, |
| 56 | int offset, int len) | ||
| 78 | { | 57 | { |
| 79 | return cpu_to_le32(~crc32); | 58 | return __crc32c_le_combine(csum, csum2, len); |
| 80 | } | 59 | } |
| 81 | 60 | ||
| 82 | /* Calculate the CRC32C checksum of an SCTP packet. */ | ||
| 83 | static inline __le32 sctp_compute_cksum(const struct sk_buff *skb, | 61 | static inline __le32 sctp_compute_cksum(const struct sk_buff *skb, |
| 84 | unsigned int offset) | 62 | unsigned int offset) |
| 85 | { | 63 | { |
| 86 | const struct sk_buff *iter; | 64 | struct sctphdr *sh = sctp_hdr(skb); |
| 65 | __le32 ret, old = sh->checksum; | ||
| 66 | const struct skb_checksum_ops ops = { | ||
| 67 | .update = sctp_csum_update, | ||
| 68 | .combine = sctp_csum_combine, | ||
| 69 | }; | ||
| 87 | 70 | ||
| 88 | __u32 crc32 = sctp_start_cksum(skb->data + offset, | 71 | sh->checksum = 0; |
| 89 | skb_headlen(skb) - offset); | 72 | ret = cpu_to_le32(~__skb_checksum(skb, offset, skb->len - offset, |
| 90 | skb_walk_frags(skb, iter) | 73 | ~(__u32)0, &ops)); |
| 91 | crc32 = sctp_update_cksum((__u8 *) iter->data, | 74 | sh->checksum = old; |
| 92 | skb_headlen(iter), crc32); | ||
| 93 | 75 | ||
| 94 | return sctp_end_cksum(crc32); | 76 | return ret; |
| 95 | } | 77 | } |
| 96 | 78 | ||
| 97 | #endif /* __sctp_checksum_h__ */ | 79 | #endif /* __sctp_checksum_h__ */ |
