Skip to content
File

Blob: firmware/vendor/sctp-proto/src/util.rs

rust535 lines
1use crate::shared::AssociationId;
2 
3use alloc::borrow::ToOwned;
4use bytes::Bytes;
5use core::time::Duration;
6use crc::{CRC_32_ISCSI, Crc, Table};
7 
8/// This function is non-inline to prevent the optimizer from looking inside it.
9#[inline(never)]
10fn constant_time_ne(a: &[u8], b: &[u8]) -> u8 {
11 assert!(a.len() == b.len());
12 
13 // These useless slices make the optimizer elide the bounds checks.
14 // See the comment in clone_from_slice() added on Rust commit 6a7bc47.
15 let len = a.len();
16 let a = &a[..len];
17 let b = &b[..len];
18 
19 let mut tmp = 0;
20 for i in 0..len {
21 tmp |= a[i] ^ b[i];
22 }
23 tmp // The compare with 0 must happen outside this function.
24}
25 
26/// Compares byte strings in constant time.
27pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
28 a.len() == b.len() && constant_time_ne(a, b) == 0
29}
30 
31/// Generates association id for incoming associations
32pub trait AssociationIdGenerator: Send + Sync {
33 /// Generates a new AID
34 ///
35 /// Association IDs MUST NOT contain any information that can be used by
36 /// an external observer (that is, one that does not cooperate with the
37 /// issuer) to correlate them with other Association IDs for the same
38 /// Association.
39 fn generate_aid(&mut self) -> AssociationId;
40 
41 /// Returns the lifetime of generated Association IDs
42 ///
43 /// Association IDs will be retired after the returned `Duration`, if any. Assumed to be constant.
44 fn aid_lifetime(&self) -> Option<Duration>;
45}
46 
47/// Generates purely random Association IDs of a certain length
48#[derive(Default, Debug, Clone, Copy)]
49pub struct RandomAssociationIdGenerator {
50 lifetime: Option<Duration>,
51}
52 
53impl RandomAssociationIdGenerator {
54 /// Initialize Random AID generator
55 pub fn new() -> Self {
56 RandomAssociationIdGenerator::default()
57 }
58 
59 /// Set the lifetime of CIDs created by this generator
60 pub fn set_lifetime(&mut self, d: Duration) -> &mut Self {
61 self.lifetime = Some(d);
62 self
63 }
64}
65 
66impl AssociationIdGenerator for RandomAssociationIdGenerator {
67 fn generate_aid(&mut self) -> AssociationId {
68 rand::random::<u32>()
69 }
70 
71 fn aid_lifetime(&self) -> Option<Duration> {
72 self.lifetime
73 }
74}
75 
76pub(crate) const PADDING_MULTIPLE: usize = 4;
77 
78pub(crate) fn get_padding_size(len: usize) -> usize {
79 (PADDING_MULTIPLE - (len % PADDING_MULTIPLE)) % PADDING_MULTIPLE
80}
81 
82/// Allocate and zero this data once.
83/// We need to use it for the checksum and don't want to allocate/clear each time.
84pub(crate) static FOUR_ZEROES: Bytes = Bytes::from_static(&[0, 0, 0, 0]);
85pub(crate) const ISCSI_CRC: Crc<u32, Table<16>> = Crc::<u32, Table<16>>::new(&CRC_32_ISCSI);
86 
87/// Fastest way to do a crc32 without allocating.
88pub(crate) fn generate_packet_checksum(raw: &Bytes) -> u32 {
89 let mut digest = ISCSI_CRC.digest();
90 digest.update(&raw[0..8]);
91 digest.update(&FOUR_ZEROES[..]);
92 digest.update(&raw[12..]);
93 digest.finalize()
94}
95 
96/// A [`BytesSource`] implementation for `&'a mut [Bytes]`
97///
98/// The type allows to dequeue [`Bytes`] chunks from an array of chunks, up to
99/// a configured limit.
100pub struct BytesArray<'a> {
101 /// The wrapped slice of `Bytes`
102 chunks: &'a mut [Bytes],
103 /// The amount of chunks consumed from this source
104 consumed: usize,
105 length: usize,
106}
107 
108impl<'a> BytesArray<'a> {
109 pub fn from_chunks(chunks: &'a mut [Bytes]) -> Self {
110 let mut length = 0;
111 for chunk in chunks.iter() {
112 length += chunk.len();
113 }
114 
115 Self {
116 chunks,
117 consumed: 0,
118 length,
119 }
120 }
121}
122 
123impl<'a> BytesSource for BytesArray<'a> {
124 fn pop_chunk(&mut self, limit: usize) -> (Bytes, usize) {
125 // The loop exists to skip empty chunks while still marking them as
126 // consumed
127 let mut chunks_consumed = 0;
128 
129 while self.consumed < self.chunks.len() {
130 let chunk = &mut self.chunks[self.consumed];
131 
132 if chunk.len() <= limit {
133 let chunk = core::mem::take(chunk);
134 self.consumed += 1;
135 chunks_consumed += 1;
136 if chunk.is_empty() {
137 continue;
138 }
139 return (chunk, chunks_consumed);
140 } else if limit > 0 {
141 let chunk = chunk.split_to(limit);
142 return (chunk, chunks_consumed);
143 } else {
144 break;
145 }
146 }
147 
148 (Bytes::new(), chunks_consumed)
149 }
150 
151 fn has_remaining(&self) -> bool {
152 self.consumed < self.length
153 }
154 
155 fn remaining(&self) -> usize {
156 self.length - self.consumed
157 }
158}
159 
160/// A [`BytesSource`] implementation for `&[u8]`
161///
162/// The type allows to dequeue a single [`Bytes`] chunk, which will be lazily
163/// created from a reference. This allows to defer the allocation until it is
164/// known how much data needs to be copied.
165pub struct ByteSlice<'a> {
166 /// The wrapped byte slice
167 data: &'a [u8],
168}
169 
170impl<'a> ByteSlice<'a> {
171 pub fn from_slice(data: &'a [u8]) -> Self {
172 Self { data }
173 }
174}
175 
176impl<'a> BytesSource for ByteSlice<'a> {
177 fn pop_chunk(&mut self, limit: usize) -> (Bytes, usize) {
178 let limit = limit.min(self.data.len());
179 if limit == 0 {
180 return (Bytes::new(), 0);
181 }
182 
183 let chunk = Bytes::from(self.data[..limit].to_owned());
184 self.data = &self.data[chunk.len()..];
185 
186 let chunks_consumed = if self.data.is_empty() { 1 } else { 0 };
187 (chunk, chunks_consumed)
188 }
189 
190 fn has_remaining(&self) -> bool {
191 !self.data.is_empty()
192 }
193 
194 fn remaining(&self) -> usize {
195 self.data.len()
196 }
197}
198 
199/// A source of one or more buffers which can be converted into `Bytes` buffers on demand
200///
201/// The purpose of this data type is to defer conversion as long as possible,
202/// so that no heap allocation is required in case no data is writable.
203pub trait BytesSource {
204 /// Returns the next chunk from the source of owned chunks.
205 ///
206 /// This method will consume parts of the source.
207 /// Calling it will yield `Bytes` elements up to the configured `limit`.
208 ///
209 /// The method returns a tuple:
210 /// - The first item is the yielded `Bytes` element. The element will be
211 /// empty if the limit is zero or no more data is available.
212 /// - The second item returns how many complete chunks inside the source had
213 /// had been consumed. This can be less than 1, if a chunk inside the
214 /// source had been truncated in order to adhere to the limit. It can also
215 /// be more than 1, if zero-length chunks had been skipped.
216 fn pop_chunk(&mut self, limit: usize) -> (Bytes, usize);
217 
218 fn has_remaining(&self) -> bool;
219 
220 fn remaining(&self) -> usize;
221}
222 
223/// Serial Number Arithmetic (RFC 1982)
224#[inline]
225pub(crate) fn sna32lt(i1: u32, i2: u32) -> bool {
226 (i1 < i2 && i2 - i1 < 1 << 31) || (i1 > i2 && i1 - i2 > 1 << 31)
227}
228 
229#[inline]
230pub(crate) fn sna32lte(i1: u32, i2: u32) -> bool {
231 i1 == i2 || sna32lt(i1, i2)
232}
233 
234#[inline]
235pub(crate) fn sna32gt(i1: u32, i2: u32) -> bool {
236 (i1 < i2 && (i2 - i1) >= 1 << 31) || (i1 > i2 && (i1 - i2) <= 1 << 31)
237}
238 
239#[inline]
240pub(crate) fn sna32gte(i1: u32, i2: u32) -> bool {
241 i1 == i2 || sna32gt(i1, i2)
242}
243 
244#[inline]
245pub(crate) fn sna32eq(i1: u32, i2: u32) -> bool {
246 i1 == i2
247}
248 
249#[inline]
250pub(crate) fn sna16lt(i1: u16, i2: u16) -> bool {
251 (i1 < i2 && (i2 - i1) < 1 << 15) || (i1 > i2 && (i1 - i2) > 1 << 15)
252}
253 
254#[inline]
255pub(crate) fn sna16lte(i1: u16, i2: u16) -> bool {
256 i1 == i2 || sna16lt(i1, i2)
257}
258 
259#[inline]
260pub(crate) fn sna16gt(i1: u16, i2: u16) -> bool {
261 (i1 < i2 && (i2 - i1) >= 1 << 15) || (i1 > i2 && (i1 - i2) <= 1 << 15)
262}
263 
264#[inline]
265pub(crate) fn sna16gte(i1: u16, i2: u16) -> bool {
266 i1 == i2 || sna16gt(i1, i2)
267}
268 
269#[inline]
270pub(crate) fn sna16eq(i1: u16, i2: u16) -> bool {
271 i1 == i2
272}
273 
274#[cfg(test)]
275mod test {
276 use crate::error::Result;
277 
278 use super::*;
279 
280 const DIV: isize = 16;
281 
282 #[test]
283 fn test_serial_number_arithmetic32bit() -> Result<()> {
284 const SERIAL_BITS: u32 = 32;
285 const INTERVAL: u32 = ((1u64 << (SERIAL_BITS as u64)) / (DIV as u64)) as u32;
286 const MAX_FORWARD_DISTANCE: u32 = 1 << ((SERIAL_BITS - 1) - 1);
287 const MAX_BACKWARD_DISTANCE: u32 = 1 << (SERIAL_BITS - 1);
288 
289 for i in 0..DIV as u32 {
290 let s1 = i * INTERVAL;
291 let s2f = s1.checked_add(MAX_FORWARD_DISTANCE);
292 let s2b = s1.checked_add(MAX_BACKWARD_DISTANCE);
293 
294 if let (Some(s2f), Some(s2b)) = (s2f, s2b) {
295 assert!(
296 sna32lt(s1, s2f),
297 "s1 < s2 should be true: s1={} s2={}",
298 s1,
299 s2f
300 );
301 assert!(
302 !sna32lt(s1, s2b),
303 "s1 < s2 should be false: s1={} s2={}",
304 s1,
305 s2b
306 );
307 
308 assert!(
309 !sna32gt(s1, s2f),
310 "s1 > s2 should be false: s1={} s2={}",
311 s1,
312 s2f
313 );
314 assert!(
315 sna32gt(s1, s2b),
316 "s1 > s2 should be true: s1={} s2={}",
317 s1,
318 s2b
319 );
320 
321 assert!(
322 sna32lte(s1, s2f),
323 "s1 <= s2 should be true: s1={} s2={}",
324 s1,
325 s2f
326 );
327 assert!(
328 !sna32lte(s1, s2b),
329 "s1 <= s2 should be false: s1={} s2={}",
330 s1,
331 s2b
332 );
333 
334 assert!(
335 !sna32gte(s1, s2f),
336 "s1 >= s2 should be fales: s1={} s2={}",
337 s1,
338 s2f
339 );
340 assert!(
341 sna32gte(s1, s2b),
342 "s1 >= s2 should be true: s1={} s2={}",
343 s1,
344 s2b
345 );
346 
347 assert!(
348 sna32eq(s2b, s2b),
349 "s2 == s2 should be true: s2={} s2={}",
350 s2b,
351 s2b
352 );
353 assert!(
354 sna32lte(s2b, s2b),
355 "s2 == s2 should be true: s2={} s2={}",
356 s2b,
357 s2b
358 );
359 assert!(
360 sna32gte(s2b, s2b),
361 "s2 == s2 should be true: s2={} s2={}",
362 s2b,
363 s2b
364 );
365 }
366 
367 if let Some(s1add1) = s1.checked_add(1) {
368 assert!(
369 !sna32eq(s1, s1add1),
370 "s1 == s1+1 should be false: s1={} s1+1={}",
371 s1,
372 s1add1
373 );
374 }
375 
376 if let Some(s1sub1) = s1.checked_sub(1) {
377 assert!(
378 !sna32eq(s1, s1sub1),
379 "s1 == s1-1 hould be false: s1={} s1-1={}",
380 s1,
381 s1sub1
382 );
383 }
384 
385 assert!(
386 sna32eq(s1, s1),
387 "s1 == s1 should be true: s1={} s2={}",
388 s1,
389 s1
390 );
391 assert!(
392 sna32lte(s1, s1),
393 "s1 == s1 should be true: s1={} s2={}",
394 s1,
395 s1
396 );
397 
398 assert!(
399 sna32gte(s1, s1),
400 "s1 == s1 should be true: s1={} s2={}",
401 s1,
402 s1
403 );
404 }
405 
406 Ok(())
407 }
408 
409 #[test]
410 fn test_serial_number_arithmetic16bit() -> Result<()> {
411 const SERIAL_BITS: u16 = 16;
412 const INTERVAL: u16 = ((1u64 << (SERIAL_BITS as u64)) / (DIV as u64)) as u16;
413 const MAX_FORWARD_DISTANCE: u16 = 1 << ((SERIAL_BITS - 1) - 1);
414 const MAX_BACKWARD_DISTANCE: u16 = 1 << (SERIAL_BITS - 1);
415 
416 for i in 0..DIV as u16 {
417 let s1 = i * INTERVAL;
418 let s2f = s1.checked_add(MAX_FORWARD_DISTANCE);
419 let s2b = s1.checked_add(MAX_BACKWARD_DISTANCE);
420 
421 if let (Some(s2f), Some(s2b)) = (s2f, s2b) {
422 assert!(
423 sna16lt(s1, s2f),
424 "s1 < s2 should be true: s1={} s2={}",
425 s1,
426 s2f
427 );
428 assert!(
429 !sna16lt(s1, s2b),
430 "s1 < s2 should be false: s1={} s2={}",
431 s1,
432 s2b
433 );
434 
435 assert!(
436 !sna16gt(s1, s2f),
437 "s1 > s2 should be fales: s1={} s2={}",
438 s1,
439 s2f
440 );
441 assert!(
442 sna16gt(s1, s2b),
443 "s1 > s2 should be true: s1={} s2={}",
444 s1,
445 s2b
446 );
447 
448 assert!(
449 sna16lte(s1, s2f),
450 "s1 <= s2 should be true: s1={} s2={}",
451 s1,
452 s2f
453 );
454 assert!(
455 !sna16lte(s1, s2b),
456 "s1 <= s2 should be false: s1={} s2={}",
457 s1,
458 s2b
459 );
460 
461 assert!(
462 !sna16gte(s1, s2f),
463 "s1 >= s2 should be fales: s1={} s2={}",
464 s1,
465 s2f
466 );
467 assert!(
468 sna16gte(s1, s2b),
469 "s1 >= s2 should be true: s1={} s2={}",
470 s1,
471 s2b
472 );
473 
474 assert!(
475 sna16eq(s2b, s2b),
476 "s2 == s2 should be true: s2={} s2={}",
477 s2b,
478 s2b
479 );
480 assert!(
481 sna16lte(s2b, s2b),
482 "s2 == s2 should be true: s2={} s2={}",
483 s2b,
484 s2b
485 );
486 assert!(
487 sna16gte(s2b, s2b),
488 "s2 == s2 should be true: s2={} s2={}",
489 s2b,
490 s2b
491 );
492 }
493 
494 assert!(
495 sna16eq(s1, s1),
496 "s1 == s1 should be true: s1={} s2={}",
497 s1,
498 s1
499 );
500 
501 if let Some(s1add1) = s1.checked_add(1) {
502 assert!(
503 !sna16eq(s1, s1add1),
504 "s1 == s1+1 should be false: s1={} s1+1={}",
505 s1,
506 s1add1
507 );
508 }
509 if let Some(s1sub1) = s1.checked_sub(1) {
510 assert!(
511 !sna16eq(s1, s1sub1),
512 "s1 == s1-1 hould be false: s1={} s1-1={}",
513 s1,
514 s1sub1
515 );
516 }
517 
518 assert!(
519 sna16lte(s1, s1),
520 "s1 == s1 should be true: s1={} s2={}",
521 s1,
522 s1
523 );
524 assert!(
525 sna16gte(s1, s1),
526 "s1 == s1 should be true: s1={} s2={}",
527 s1,
528 s1
529 );
530 }
531 
532 Ok(())
533 }
534}