1 /*
2 * Copyright (C) 2008-2010 Daisuke Aoyama <aoyama@peach.ne.jp>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <inttypes.h>
33 #include <stdint.h>
34
35 #include <ctype.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <sys/uio.h>
39
40 #include "istgt_iscsi.h"
41 #include "istgt_crc32c.h"
42
43 /* defined in RFC3720(12.1) */
44 static uint32_t istgt_crc32c_initial = ISTGT_CRC32C_INITIAL;
45 static uint32_t istgt_crc32c_xor = ISTGT_CRC32C_XOR;
46 static uint32_t istgt_crc32c_polynomial = ISTGT_CRC32C_POLYNOMIAL;
47 #ifdef ISTGT_USE_CRC32C_TABLE
48 static uint32_t istgt_crc32c_table[256];
49 static int istgt_crc32c_initialized = 0;
50 #endif /* ISTGT_USE_CRC32C_TABLE */
51
52 static uint32_t
istgt_reflect(uint32_t val,int bits)53 istgt_reflect(uint32_t val, int bits)
54 {
55 int i;
56 uint32_t r;
57
58 if (bits < 1 || bits > 32)
59 return 0;
60 r = 0;
61 for (i = 0; i < bits; i++) {
62 r |= ((val >> ((bits - 1) - i)) & 1) << i;
63 }
64 return r;
65 }
66
67 #ifdef ISTGT_USE_CRC32C_TABLE
68 void
istgt_init_crc32c_table(void)69 istgt_init_crc32c_table(void)
70 {
71 int i, j;
72 uint32_t val;
73 uint32_t reflect_polynomial;
74
75 reflect_polynomial = istgt_reflect(istgt_crc32c_polynomial, 32);
76 for (i = 0; i < 256; i++) {
77 val = i;
78 for (j = 0; j < 8; j++) {
79 if (val & 1) {
80 val = (val >> 1) ^ reflect_polynomial;
81 } else {
82 val = (val >> 1);
83 }
84 }
85 istgt_crc32c_table[i] = val;
86 }
87 istgt_crc32c_initialized = 1;
88 }
89 #endif /* ISTGT_USE_CRC32C_TABLE */
90
91 uint32_t
istgt_update_crc32c(const uint8_t * buf,size_t len,uint32_t crc)92 istgt_update_crc32c(const uint8_t *buf, size_t len, uint32_t crc)
93 {
94 size_t s;
95 #ifndef ISTGT_USE_CRC32C_TABLE
96 int i;
97 uint32_t val;
98 uint32_t reflect_polynomial;
99 #endif /* ISTGT_USE_CRC32C_TABLE */
100
101 #ifdef ISTGT_USE_CRC32C_TABLE
102 #if 0
103 /* initialize by main() */
104 if (!istgt_crc32c_initialized) {
105 istgt_init_crc32c_table();
106 }
107 #endif
108 #else
109 reflect_polynomial = istgt_reflect(istgt_crc32c_polynomial, 32);
110 #endif /* ISTGT_USE_CRC32C_TABLE */
111
112 for (s = 0; s < len; s++) {
113 #ifdef ISTGT_USE_CRC32C_TABLE
114 crc = (crc >> 8) ^ istgt_crc32c_table[(crc ^ buf[s]) & 0xff];
115 #else
116 val = buf[s];
117 for (i = 0; i < 8; i++) {
118 if ((crc ^ val) & 1) {
119 crc = (crc >> 1) ^ reflect_polynomial;
120 } else {
121 crc = (crc >> 1);
122 }
123 val = val >> 1;
124 }
125 #endif /* ISTGT_USE_CRC32C_TABLE */
126 }
127 return crc;
128 }
129
130 uint32_t
istgt_fixup_crc32c(size_t total,uint32_t crc)131 istgt_fixup_crc32c(size_t total, uint32_t crc)
132 {
133 uint8_t padding[ISCSI_ALIGNMENT];
134 size_t pad_length;
135 size_t rest;
136
137 if (total == 0)
138 return crc;
139 #if 0
140 /* alignment must be power of 2 */
141 rest = total & ~(ISCSI_ALIGNMENT - 1);
142 #endif
143 rest = total % ISCSI_ALIGNMENT;
144 if (rest != 0) {
145 pad_length = ISCSI_ALIGNMENT;
146 pad_length -= rest;
147 if (pad_length > 0 && pad_length < sizeof padding){
148 memset(padding, 0, sizeof padding);
149 crc = istgt_update_crc32c(padding, pad_length, crc);
150 }
151 }
152 return crc;
153 }
154
155 uint32_t
istgt_crc32c(const uint8_t * buf,size_t len)156 istgt_crc32c(const uint8_t *buf, size_t len)
157 {
158 uint32_t crc32c;
159
160 crc32c = istgt_crc32c_initial;
161 crc32c = istgt_update_crc32c(buf, len, crc32c);
162 if ((len % ISCSI_ALIGNMENT) != 0) {
163 crc32c = istgt_fixup_crc32c(len, crc32c);
164 }
165 crc32c = crc32c ^ istgt_crc32c_xor;
166 return crc32c;
167 }
168
169 uint32_t
istgt_iovec_crc32c(const struct iovec * iovp,int iovc,uint32_t offset,uint32_t len)170 istgt_iovec_crc32c(const struct iovec *iovp, int iovc, uint32_t offset, uint32_t len)
171 {
172 const uint8_t *p;
173 uint32_t total;
174 uint32_t pos;
175 uint32_t n;
176 uint32_t crc32c;
177 int i;
178
179 pos = 0;
180 total = 0;
181 crc32c = istgt_crc32c_initial;
182 for (i = 0; i < iovc; i++) {
183 if (len == 0)
184 break;
185 if (pos + iovp[i].iov_len > offset) {
186 p = (const uint8_t *) iovp[i].iov_base + (offset - pos);
187 if (iovp[i].iov_len > len) {
188 n = len;
189 len = 0;
190 } else {
191 n = iovp[i].iov_len;
192 len -= n;
193 }
194 crc32c = istgt_update_crc32c(p, n, crc32c);
195 offset += n;
196 total += n;
197 }
198 pos += iovp[i].iov_len;
199 }
200 #if 0
201 printf("update %d bytes\n", total);
202 #endif
203 crc32c = istgt_fixup_crc32c(total, crc32c);
204 crc32c = crc32c ^ istgt_crc32c_xor;
205 return crc32c;
206 }
207