1 use bytes::Bytes;
2 use crc::{Crc, CRC_32_ISCSI};
3
4 pub(crate) const PADDING_MULTIPLE: usize = 4;
5
get_padding_size(len: usize) -> usize6 pub(crate) fn get_padding_size(len: usize) -> usize {
7 (PADDING_MULTIPLE - (len % PADDING_MULTIPLE)) % PADDING_MULTIPLE
8 }
9
10 /// Allocate and zero this data once.
11 /// We need to use it for the checksum and don't want to allocate/clear each time.
12 pub(crate) static FOUR_ZEROES: Bytes = Bytes::from_static(&[0, 0, 0, 0]);
13
14 pub(crate) const ISCSI_CRC: Crc<u32> = Crc::<u32>::new(&CRC_32_ISCSI);
15
16 /// Fastest way to do a crc32 without allocating.
generate_packet_checksum(raw: &Bytes) -> u3217 pub(crate) fn generate_packet_checksum(raw: &Bytes) -> u32 {
18 let mut digest = ISCSI_CRC.digest();
19 digest.update(&raw[0..8]);
20 digest.update(&FOUR_ZEROES[..]);
21 digest.update(&raw[12..]);
22 digest.finalize()
23 }
24
25 /// Serial Number Arithmetic (RFC 1982)
26 #[inline]
sna32lt(i1: u32, i2: u32) -> bool27 pub(crate) fn sna32lt(i1: u32, i2: u32) -> bool {
28 (i1 < i2 && i2 - i1 < 1 << 31) || (i1 > i2 && i1 - i2 > 1 << 31)
29 }
30
31 #[inline]
sna32lte(i1: u32, i2: u32) -> bool32 pub(crate) fn sna32lte(i1: u32, i2: u32) -> bool {
33 i1 == i2 || sna32lt(i1, i2)
34 }
35
36 #[inline]
sna32gt(i1: u32, i2: u32) -> bool37 pub(crate) fn sna32gt(i1: u32, i2: u32) -> bool {
38 (i1 < i2 && (i2 - i1) >= 1 << 31) || (i1 > i2 && (i1 - i2) <= 1 << 31)
39 }
40
41 #[inline]
sna32gte(i1: u32, i2: u32) -> bool42 pub(crate) fn sna32gte(i1: u32, i2: u32) -> bool {
43 i1 == i2 || sna32gt(i1, i2)
44 }
45
46 #[inline]
sna32eq(i1: u32, i2: u32) -> bool47 pub(crate) fn sna32eq(i1: u32, i2: u32) -> bool {
48 i1 == i2
49 }
50
51 #[inline]
sna16lt(i1: u16, i2: u16) -> bool52 pub(crate) fn sna16lt(i1: u16, i2: u16) -> bool {
53 (i1 < i2 && (i2 - i1) < 1 << 15) || (i1 > i2 && (i1 - i2) > 1 << 15)
54 }
55
56 #[inline]
sna16lte(i1: u16, i2: u16) -> bool57 pub(crate) fn sna16lte(i1: u16, i2: u16) -> bool {
58 i1 == i2 || sna16lt(i1, i2)
59 }
60
61 #[inline]
sna16gt(i1: u16, i2: u16) -> bool62 pub(crate) fn sna16gt(i1: u16, i2: u16) -> bool {
63 (i1 < i2 && (i2 - i1) >= 1 << 15) || (i1 > i2 && (i1 - i2) <= 1 << 15)
64 }
65
66 #[inline]
sna16gte(i1: u16, i2: u16) -> bool67 pub(crate) fn sna16gte(i1: u16, i2: u16) -> bool {
68 i1 == i2 || sna16gt(i1, i2)
69 }
70
71 #[inline]
sna16eq(i1: u16, i2: u16) -> bool72 pub(crate) fn sna16eq(i1: u16, i2: u16) -> bool {
73 i1 == i2
74 }
75
76 #[cfg(test)]
77 mod test {
78 use crate::error::Result;
79
80 use super::*;
81
82 const DIV: isize = 16;
83
84 #[test]
test_serial_number_arithmetic32bit() -> Result<()>85 fn test_serial_number_arithmetic32bit() -> Result<()> {
86 const SERIAL_BITS: u32 = 32;
87 const INTERVAL: u32 = ((1u64 << (SERIAL_BITS as u64)) / (DIV as u64)) as u32;
88 const MAX_FORWARD_DISTANCE: u32 = 1 << ((SERIAL_BITS - 1) - 1);
89 const MAX_BACKWARD_DISTANCE: u32 = 1 << (SERIAL_BITS - 1);
90
91 for i in 0..DIV as u32 {
92 let s1 = i * INTERVAL;
93 let s2f = s1.checked_add(MAX_FORWARD_DISTANCE);
94 let s2b = s1.checked_add(MAX_BACKWARD_DISTANCE);
95
96 if let (Some(s2f), Some(s2b)) = (s2f, s2b) {
97 assert!(sna32lt(s1, s2f), "s1 < s2 should be true: s1={s1} s2={s2f}");
98 assert!(
99 !sna32lt(s1, s2b),
100 "s1 < s2 should be false: s1={s1} s2={s2b}"
101 );
102
103 assert!(
104 !sna32gt(s1, s2f),
105 "s1 > s2 should be false: s1={s1} s2={s2f}"
106 );
107 assert!(sna32gt(s1, s2b), "s1 > s2 should be true: s1={s1} s2={s2b}");
108
109 assert!(
110 sna32lte(s1, s2f),
111 "s1 <= s2 should be true: s1={s1} s2={s2f}"
112 );
113 assert!(
114 !sna32lte(s1, s2b),
115 "s1 <= s2 should be false: s1={s1} s2={s2b}"
116 );
117
118 assert!(
119 !sna32gte(s1, s2f),
120 "s1 >= s2 should be fales: s1={s1} s2={s2f}"
121 );
122 assert!(
123 sna32gte(s1, s2b),
124 "s1 >= s2 should be true: s1={s1} s2={s2b}"
125 );
126
127 assert!(
128 sna32eq(s2b, s2b),
129 "s2 == s2 should be true: s2={s2b} s2={s2b}"
130 );
131 assert!(
132 sna32lte(s2b, s2b),
133 "s2 == s2 should be true: s2={s2b} s2={s2b}"
134 );
135 assert!(
136 sna32gte(s2b, s2b),
137 "s2 == s2 should be true: s2={s2b} s2={s2b}"
138 );
139 }
140
141 if let Some(s1add1) = s1.checked_add(1) {
142 assert!(
143 !sna32eq(s1, s1add1),
144 "s1 == s1+1 should be false: s1={s1} s1+1={s1add1}"
145 );
146 }
147
148 if let Some(s1sub1) = s1.checked_sub(1) {
149 assert!(
150 !sna32eq(s1, s1sub1),
151 "s1 == s1-1 hould be false: s1={s1} s1-1={s1sub1}"
152 );
153 }
154
155 assert!(sna32eq(s1, s1), "s1 == s1 should be true: s1={s1} s2={s1}");
156 assert!(sna32lte(s1, s1), "s1 == s1 should be true: s1={s1} s2={s1}");
157
158 assert!(sna32gte(s1, s1), "s1 == s1 should be true: s1={s1} s2={s1}");
159 }
160
161 Ok(())
162 }
163
164 #[test]
test_serial_number_arithmetic16bit() -> Result<()>165 fn test_serial_number_arithmetic16bit() -> Result<()> {
166 const SERIAL_BITS: u16 = 16;
167 const INTERVAL: u16 = ((1u64 << (SERIAL_BITS as u64)) / (DIV as u64)) as u16;
168 const MAX_FORWARD_DISTANCE: u16 = 1 << ((SERIAL_BITS - 1) - 1);
169 const MAX_BACKWARD_DISTANCE: u16 = 1 << (SERIAL_BITS - 1);
170
171 for i in 0..DIV as u16 {
172 let s1 = i * INTERVAL;
173 let s2f = s1.checked_add(MAX_FORWARD_DISTANCE);
174 let s2b = s1.checked_add(MAX_BACKWARD_DISTANCE);
175
176 if let (Some(s2f), Some(s2b)) = (s2f, s2b) {
177 assert!(sna16lt(s1, s2f), "s1 < s2 should be true: s1={s1} s2={s2f}");
178 assert!(
179 !sna16lt(s1, s2b),
180 "s1 < s2 should be false: s1={s1} s2={s2b}"
181 );
182
183 assert!(
184 !sna16gt(s1, s2f),
185 "s1 > s2 should be fales: s1={s1} s2={s2f}"
186 );
187 assert!(sna16gt(s1, s2b), "s1 > s2 should be true: s1={s1} s2={s2b}");
188
189 assert!(
190 sna16lte(s1, s2f),
191 "s1 <= s2 should be true: s1={s1} s2={s2f}"
192 );
193 assert!(
194 !sna16lte(s1, s2b),
195 "s1 <= s2 should be false: s1={s1} s2={s2b}"
196 );
197
198 assert!(
199 !sna16gte(s1, s2f),
200 "s1 >= s2 should be fales: s1={s1} s2={s2f}"
201 );
202 assert!(
203 sna16gte(s1, s2b),
204 "s1 >= s2 should be true: s1={s1} s2={s2b}"
205 );
206
207 assert!(
208 sna16eq(s2b, s2b),
209 "s2 == s2 should be true: s2={s2b} s2={s2b}"
210 );
211 assert!(
212 sna16lte(s2b, s2b),
213 "s2 == s2 should be true: s2={s2b} s2={s2b}"
214 );
215 assert!(
216 sna16gte(s2b, s2b),
217 "s2 == s2 should be true: s2={s2b} s2={s2b}"
218 );
219 }
220
221 assert!(sna16eq(s1, s1), "s1 == s1 should be true: s1={s1} s2={s1}");
222
223 if let Some(s1add1) = s1.checked_add(1) {
224 assert!(
225 !sna16eq(s1, s1add1),
226 "s1 == s1+1 should be false: s1={s1} s1+1={s1add1}"
227 );
228 }
229 if let Some(s1sub1) = s1.checked_sub(1) {
230 assert!(
231 !sna16eq(s1, s1sub1),
232 "s1 == s1-1 hould be false: s1={s1} s1-1={s1sub1}"
233 );
234 }
235
236 assert!(sna16lte(s1, s1), "s1 == s1 should be true: s1={s1} s2={s1}");
237 assert!(sna16gte(s1, s1), "s1 == s1 should be true: s1={s1} s2={s1}");
238 }
239
240 Ok(())
241 }
242 }
243