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