Skip to content

Commit b397f99

Browse files
committed
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>
2 parents 296c106 + e6d8b64 commit b397f99

File tree

7 files changed

+350
-258
lines changed

7 files changed

+350
-258
lines changed

include/linux/crc32.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,48 @@
1111
extern u32 crc32_le(u32 crc, unsigned char const *p, size_t len);
1212
extern u32 crc32_be(u32 crc, unsigned char const *p, size_t len);
1313

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+
1434
extern u32 __crc32c_le(u32 crc, unsigned char const *p, size_t len);
1535

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+
1656
#define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)(data), length)
1757

1858
/*

include/linux/skbuff.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2360,8 +2360,6 @@ int skb_copy_datagram_const_iovec(const struct sk_buff *from, int offset,
23602360
void skb_free_datagram(struct sock *sk, struct sk_buff *skb);
23612361
void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb);
23622362
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);
23652363
int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
23662364
int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);
23672365
__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);
23732371
void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len);
23742372
int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
23752373
void skb_scrub_packet(struct sk_buff *skb, bool xnet);
2376-
23772374
struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
23782375

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+
23792386
static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
23802387
int len, void *buffer)
23812388
{

include/net/checksum.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ csum_block_add(__wsum csum, __wsum csum2, int offset)
7878
return csum_add(csum, (__force __wsum)sum);
7979
}
8080

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+
8187
static inline __wsum
8288
csum_block_sub(__wsum csum, __wsum csum2, int offset)
8389
{

include/net/sctp/checksum.h

Lines changed: 19 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -42,56 +42,38 @@
4242
#include <linux/types.h>
4343
#include <net/sctp/sctp.h>
4444
#include <linux/crc32c.h>
45+
#include <linux/crc32.h>
4546

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)
4748
{
48-
return crc32c(crc, buffer, length);
49-
}
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.
49+
/* This uses the crypto implementation of crc32c, which is either
50+
* implemented w/ hardware support or resolves to __crc32c_le().
5851
*/
59-
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);
52+
return crc32c(sum, buff, len);
7553
}
7654

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)
7857
{
79-
return cpu_to_le32(~crc32);
58+
return __crc32c_le_combine(csum, csum2, len);
8059
}
8160

82-
/* Calculate the CRC32C checksum of an SCTP packet. */
8361
static inline __le32 sctp_compute_cksum(const struct sk_buff *skb,
8462
unsigned int offset)
8563
{
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+
};
8770

88-
__u32 crc32 = sctp_start_cksum(skb->data + offset,
89-
skb_headlen(skb) - offset);
90-
skb_walk_frags(skb, iter)
91-
crc32 = sctp_update_cksum((__u8 *) iter->data,
92-
skb_headlen(iter), crc32);
71+
sh->checksum = 0;
72+
ret = cpu_to_le32(~__skb_checksum(skb, offset, skb->len - offset,
73+
~(__u32)0, &ops));
74+
sh->checksum = old;
9375

94-
return sctp_end_cksum(crc32);
76+
return ret;
9577
}
9678

9779
#endif /* __sctp_checksum_h__ */

0 commit comments

Comments
 (0)