Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lib: crc32: add functionality to combine two crc32{, c}s in GF(2)

This patch adds a combinator to merge two or more crc32{,c}s
into a new one. This is useful for checksum computations of
fragmented skbs that use crc32/crc32c as checksums.

The arithmetics for combining both in the GF(2) was taken and
slightly modified from zlib. Only passing two crcs is insufficient
as two crcs and the length of the second piece is needed for
merging. The code is made generic, so that only polynomials
need to be passed for crc32_le resp. crc32c_le.

Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Daniel Borkmann and committed by
David S. Miller
6e95fcaa d921e049

+121
+40
include/linux/crc32.h
··· 11 11 extern u32 crc32_le(u32 crc, unsigned char const *p, size_t len); 12 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 34 extern u32 __crc32c_le(u32 crc, unsigned char const *p, size_t len); 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); 15 55 16 56 #define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)(data), length) 17 57
+81
lib/crc32.c
··· 49 49 MODULE_DESCRIPTION("Various CRC32 calculations"); 50 50 MODULE_LICENSE("GPL"); 51 51 52 + #define GF2_DIM 32 53 + 54 + static u32 gf2_matrix_times(u32 *mat, u32 vec) 55 + { 56 + u32 sum = 0; 57 + 58 + while (vec) { 59 + if (vec & 1) 60 + sum ^= *mat; 61 + vec >>= 1; 62 + mat++; 63 + } 64 + 65 + return sum; 66 + } 67 + 68 + static void gf2_matrix_square(u32 *square, u32 *mat) 69 + { 70 + int i; 71 + 72 + for (i = 0; i < GF2_DIM; i++) 73 + square[i] = gf2_matrix_times(mat, mat[i]); 74 + } 75 + 52 76 #if CRC_LE_BITS > 8 || CRC_BE_BITS > 8 53 77 54 78 /* implements slicing-by-4 or slicing-by-8 algorithm */ ··· 154 130 } 155 131 #endif 156 132 133 + /* For conditions of distribution and use, see copyright notice in zlib.h */ 134 + static u32 crc32_generic_combine(u32 crc1, u32 crc2, size_t len2, 135 + u32 polynomial) 136 + { 137 + u32 even[GF2_DIM]; /* Even-power-of-two zeros operator */ 138 + u32 odd[GF2_DIM]; /* Odd-power-of-two zeros operator */ 139 + u32 row; 140 + int i; 141 + 142 + if (len2 <= 0) 143 + return crc1; 144 + 145 + /* Put operator for one zero bit in odd */ 146 + odd[0] = polynomial; 147 + row = 1; 148 + for (i = 1; i < GF2_DIM; i++) { 149 + odd[i] = row; 150 + row <<= 1; 151 + } 152 + 153 + gf2_matrix_square(even, odd); /* Put operator for two zero bits in even */ 154 + gf2_matrix_square(odd, even); /* Put operator for four zero bits in odd */ 155 + 156 + /* Apply len2 zeros to crc1 (first square will put the operator for one 157 + * zero byte, eight zero bits, in even). 158 + */ 159 + do { 160 + /* Apply zeros operator for this bit of len2 */ 161 + gf2_matrix_square(even, odd); 162 + if (len2 & 1) 163 + crc1 = gf2_matrix_times(even, crc1); 164 + len2 >>= 1; 165 + /* If no more bits set, then done */ 166 + if (len2 == 0) 167 + break; 168 + /* Another iteration of the loop with odd and even swapped */ 169 + gf2_matrix_square(odd, even); 170 + if (len2 & 1) 171 + crc1 = gf2_matrix_times(odd, crc1); 172 + len2 >>= 1; 173 + } while (len2 != 0); 174 + 175 + crc1 ^= crc2; 176 + return crc1; 177 + } 178 + 157 179 /** 158 180 * crc32_le_generic() - Calculate bitwise little-endian Ethernet AUTODIN II 159 181 * CRC32/CRC32C ··· 270 200 (const u32 (*)[256])crc32ctable_le, CRC32C_POLY_LE); 271 201 } 272 202 #endif 203 + u32 __pure crc32_le_combine(u32 crc1, u32 crc2, size_t len2) 204 + { 205 + return crc32_generic_combine(crc1, crc2, len2, CRCPOLY_LE); 206 + } 207 + 208 + u32 __pure __crc32c_le_combine(u32 crc1, u32 crc2, size_t len2) 209 + { 210 + return crc32_generic_combine(crc1, crc2, len2, CRC32C_POLY_LE); 211 + } 273 212 EXPORT_SYMBOL(crc32_le); 213 + EXPORT_SYMBOL(crc32_le_combine); 274 214 EXPORT_SYMBOL(__crc32c_le); 215 + EXPORT_SYMBOL(__crc32c_le_combine); 275 216 276 217 /** 277 218 * crc32_be_generic() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32