netstack3_base/tcp/
seqnum.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! TCP sequence numbers and operations on them.
6
7use core::convert::TryFrom as _;
8use core::num::TryFromIntError;
9use core::ops;
10
11use explicit::ResultExt as _;
12
13/// Sequence number of a transferred TCP segment.
14///
15/// Per https://tools.ietf.org/html/rfc793#section-3.3:
16///   This space ranges from 0 to 2**32 - 1. Since the space is finite, all
17///   arithmetic dealing with sequence numbers must be performed modulo 2**32.
18///   This unsigned arithmetic preserves the relationship of sequence numbers
19///   as they cycle from 2**32 - 1 to 0 again.  There are some subtleties to
20///   computer modulo arithmetic, so great care should be taken in programming
21///   the comparison of such values.
22///
23/// For any sequence number, there are 2**31 numbers after it and 2**31 - 1
24/// numbers before it.
25#[derive(Debug, PartialEq, Eq, Clone, Copy)]
26pub struct SeqNum(u32);
27
28impl ops::Add<i32> for SeqNum {
29    type Output = SeqNum;
30
31    fn add(self, rhs: i32) -> Self::Output {
32        let Self(lhs) = self;
33        Self(lhs.wrapping_add_signed(rhs))
34    }
35}
36
37impl ops::Sub<i32> for SeqNum {
38    type Output = SeqNum;
39
40    fn sub(self, rhs: i32) -> Self::Output {
41        let Self(lhs) = self;
42        Self(lhs.wrapping_add_signed(rhs.wrapping_neg()))
43    }
44}
45
46impl ops::Add<u32> for SeqNum {
47    type Output = SeqNum;
48
49    fn add(self, rhs: u32) -> Self::Output {
50        let Self(lhs) = self;
51        Self(lhs.wrapping_add(rhs))
52    }
53}
54
55impl ops::Sub<u32> for SeqNum {
56    type Output = SeqNum;
57
58    fn sub(self, rhs: u32) -> Self::Output {
59        let Self(lhs) = self;
60        Self(lhs.wrapping_sub(rhs))
61    }
62}
63
64impl ops::Sub<WindowSize> for SeqNum {
65    type Output = SeqNum;
66
67    fn sub(self, WindowSize(wnd): WindowSize) -> Self::Output {
68        // The conversion from u32 to i32 will never truncate because the
69        // maximum window size is less than 2^30, which will comfortably fit
70        // into an i32.
71        self - i32::try_from(wnd).unwrap()
72    }
73}
74
75impl ops::Add<usize> for SeqNum {
76    type Output = SeqNum;
77
78    fn add(self, rhs: usize) -> Self::Output {
79        // The following `as` coercion is sound because:
80        // 1. if `u32` is wider than `usize`, the unsigned extension will
81        //    result in the same number.
82        // 2. if `usize` is wider than `u32`, then `rhs` can be written as
83        //    `A * 2 ^ 32 + B`. Because of the wrapping nature of sequnce
84        //    numbers, the effect of adding `rhs` is the same as adding `B`
85        //    which is the number after the truncation, i.e., `rhs as u32`.
86        self + (rhs as u32)
87    }
88}
89
90impl ops::Sub for SeqNum {
91    // `i32` is more intuitive than `u32`, since subtraction may yield negative
92    // values.
93    type Output = i32;
94
95    fn sub(self, rhs: Self) -> Self::Output {
96        let Self(lhs) = self;
97        let Self(rhs) = rhs;
98        // The following `as` coercion is sound because:
99        // Rust uses 2's complement for signed integers [1], meaning when cast
100        // to an `i32, an `u32` >= 1<<32 becomes negative and an `u32` < 1<<32
101        // becomes positive. `wrapping_sub` ensures that if `rhs` is a `SeqNum`
102        // after `lhs`, the result will wrap into the `u32` space > 1<<32.
103        // Recall that `SeqNums` are only valid for a `WindowSize` < 1<<31; this
104        // prevents the difference of `wrapping_sub` from being so large that it
105        // wraps into the `u32` space < 1<<32.
106        // [1]: https://doc.rust-lang.org/reference/types/numeric.html
107        lhs.wrapping_sub(rhs) as i32
108    }
109}
110
111impl From<u32> for SeqNum {
112    fn from(x: u32) -> Self {
113        Self::new(x)
114    }
115}
116
117impl From<SeqNum> for u32 {
118    fn from(x: SeqNum) -> Self {
119        let SeqNum(x) = x;
120        x
121    }
122}
123
124impl SeqNum {
125    /// Creates a new sequence number.
126    pub const fn new(x: u32) -> Self {
127        Self(x)
128    }
129}
130
131impl SeqNum {
132    /// A predicate for whether a sequence number is before the other.
133    ///
134    /// Please refer to [`SeqNum`] for the defined order.
135    pub fn before(self, other: SeqNum) -> bool {
136        self - other < 0
137    }
138
139    /// A predicate for whether a sequence number is equal to or before the
140    /// other.
141    ///
142    /// Please refer to [`SeqNum`] for the defined order.
143    pub fn before_or_eq(self, other: SeqNum) -> bool {
144        self - other <= 0
145    }
146
147    /// A predicate for whether a sequence number is after the other.
148    ///
149    /// Please refer to [`SeqNum`] for the defined order.
150    pub fn after(self, other: SeqNum) -> bool {
151        self - other > 0
152    }
153
154    /// A predicate for whether a sequence number is equal to or after the
155    /// other.
156    ///
157    /// Please refer to [`SeqNum`] for the defined order.
158    pub fn after_or_eq(self, other: SeqNum) -> bool {
159        self - other >= 0
160    }
161
162    /// Returns the earliest sequence number between `self` and `other`.
163    ///
164    /// This is equivalent to [`Ord::min`], but keeps within the temporal
165    /// instead of numeric semantics.
166    pub fn earliest(self, other: SeqNum) -> SeqNum {
167        if self.before(other) {
168            self
169        } else {
170            other
171        }
172    }
173
174    /// Returns the latest sequence number between `self` and `other`.
175    ///
176    /// This is equivalent to [`Ord::max`], but keeps within the temporal
177    /// instead of numeric semantics.
178    pub fn latest(self, other: SeqNum) -> SeqNum {
179        if self.after(other) {
180            self
181        } else {
182            other
183        }
184    }
185}
186
187/// A witness type for TCP window size.
188///
189/// Per [RFC 7323 Section 2.3]:
190/// > ..., the above constraints imply that two times the maximum window size
191/// > must be less than 2^31, or
192/// >                    max window < 2^30
193///
194/// [RFC 7323 Section 2.3]: https://tools.ietf.org/html/rfc7323#section-2.3
195#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
196pub struct WindowSize(u32);
197
198impl WindowSize {
199    /// The largest possible window size.
200    pub const MAX: WindowSize = WindowSize(1 << 30 - 1);
201    /// The smallest possible window size.
202    pub const ZERO: WindowSize = WindowSize(0);
203    /// A window size of 1, the smallest nonzero window size.
204    pub const ONE: WindowSize = WindowSize(1);
205
206    /// The Netstack3 default window size.
207    // TODO(https://github.com/rust-lang/rust/issues/67441): put this constant
208    // in the state module once `Option::unwrap` is stable.
209    pub const DEFAULT: WindowSize = WindowSize(65535);
210
211    /// Create a new `WindowSize` from the provided `u32`.
212    ///
213    /// If the provided window size is out of range, then `None` is returned.
214    pub const fn from_u32(wnd: u32) -> Option<Self> {
215        let WindowSize(max) = Self::MAX;
216        if wnd > max {
217            None
218        } else {
219            Some(Self(wnd))
220        }
221    }
222
223    /// Add a `u32` to this WindowSize, saturating at [`WindowSize::MAX`].
224    pub fn saturating_add(self, rhs: u32) -> Self {
225        Self::from_u32(u32::from(self).saturating_add(rhs)).unwrap_or(Self::MAX)
226    }
227
228    /// Create a new [`WindowSize`], returning `None` if the argument is out of range.
229    pub fn new(wnd: usize) -> Option<Self> {
230        u32::try_from(wnd).ok_checked::<TryFromIntError>().and_then(WindowSize::from_u32)
231    }
232
233    /// Subtract `diff` from `self`, returning `None` if the result would be negative.
234    pub fn checked_sub(self, diff: usize) -> Option<Self> {
235        // The call to Self::new will never return None.
236        //
237        // If diff is larger than self, the checked_sub will return None. Otherwise the result must
238        // be less than Self::MAX, since the value of self before subtraction must be less than or
239        // equal to Self::MAX.
240        usize::from(self).checked_sub(diff).and_then(Self::new)
241    }
242
243    /// Subtract `diff` from `self` returning [`WindowSize::ZERO`] if the result
244    /// would be negative.
245    pub fn saturating_sub(self, diff: usize) -> Self {
246        self.checked_sub(diff).unwrap_or(WindowSize::ZERO)
247    }
248
249    /// The window scale that needs to be advertised during the handshake.
250    pub fn scale(self) -> WindowScale {
251        let WindowSize(size) = self;
252        let effective_bits = u8::try_from(32 - u32::leading_zeros(size)).unwrap();
253        let scale = WindowScale(effective_bits.saturating_sub(16));
254        scale
255    }
256
257    /// Returns this `WindowSize` with a halved value
258    pub fn halved(self) -> WindowSize {
259        let WindowSize(size) = self;
260        WindowSize(size >> 1)
261    }
262}
263
264impl ops::Add<WindowSize> for SeqNum {
265    type Output = SeqNum;
266
267    fn add(self, WindowSize(wnd): WindowSize) -> Self::Output {
268        self + wnd
269    }
270}
271
272impl From<WindowSize> for u32 {
273    fn from(WindowSize(wnd): WindowSize) -> Self {
274        wnd
275    }
276}
277
278#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
279impl From<WindowSize> for usize {
280    fn from(WindowSize(wnd): WindowSize) -> Self {
281        wnd as usize
282    }
283}
284
285#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
286/// This type is a witness for a valid window scale exponent value.
287///
288/// Per RFC 7323 Section 2.2, the restriction is as follows:
289///   The maximum scale exponent is limited to 14 for a maximum permissible
290///   receive window size of 1 GiB (2^(14+16)).
291pub struct WindowScale(u8);
292
293impl WindowScale {
294    /// The largest possible [`WindowScale`].
295    pub const MAX: WindowScale = WindowScale(14);
296    /// The smallest possible [`WindowScale`].
297    pub const ZERO: WindowScale = WindowScale(0);
298
299    /// Creates a new `WindowScale`.
300    ///
301    /// Returns `None` if the input exceeds the maximum possible value.
302    pub fn new(ws: u8) -> Option<Self> {
303        (ws <= Self::MAX.get()).then_some(WindowScale(ws))
304    }
305
306    /// Returns the inner value.
307    pub fn get(&self) -> u8 {
308        let Self(ws) = self;
309        *ws
310    }
311}
312
313#[derive(Debug, PartialEq, Eq, Clone, Copy)]
314/// Window size that is used in the window field of a TCP segment.
315///
316/// For connections with window scaling enabled, the receiver has to scale this
317/// value back to get the real window size advertised by the peer.
318pub struct UnscaledWindowSize(u16);
319
320impl ops::Shl<WindowScale> for UnscaledWindowSize {
321    type Output = WindowSize;
322
323    fn shl(self, WindowScale(scale): WindowScale) -> Self::Output {
324        let UnscaledWindowSize(size) = self;
325        // `scale` is guaranteed to be <= 14, so the result must fit in a u32.
326        WindowSize::from_u32(u32::from(size) << scale).unwrap()
327    }
328}
329
330impl ops::Shr<WindowScale> for WindowSize {
331    type Output = UnscaledWindowSize;
332
333    fn shr(self, WindowScale(scale): WindowScale) -> Self::Output {
334        let WindowSize(size) = self;
335        UnscaledWindowSize(u16::try_from(size >> scale).unwrap_or(u16::MAX))
336    }
337}
338
339impl From<u16> for UnscaledWindowSize {
340    fn from(value: u16) -> Self {
341        Self(value)
342    }
343}
344
345impl From<UnscaledWindowSize> for u16 {
346    fn from(UnscaledWindowSize(value): UnscaledWindowSize) -> Self {
347        value
348    }
349}
350
351#[cfg(feature = "testutils")]
352mod testutils {
353    use super::*;
354
355    impl UnscaledWindowSize {
356        /// Create a new UnscaledWindowSize.
357        ///
358        /// Panics if `size` is not in range.
359        pub fn from_usize(size: usize) -> Self {
360            UnscaledWindowSize::from(u16::try_from(size).unwrap())
361        }
362
363        /// Create a new UnscaledWindowSize.
364        ///
365        /// Panics if `size` is not in range.
366        pub fn from_u32(size: u32) -> Self {
367            UnscaledWindowSize::from(u16::try_from(size).unwrap())
368        }
369    }
370}
371
372#[cfg(test)]
373mod tests {
374    use alloc::format;
375
376    use proptest::arbitrary::any;
377    use proptest::strategy::{Just, Strategy};
378    use proptest::test_runner::Config;
379    use proptest::{prop_assert, prop_assert_eq, proptest};
380    use proptest_support::failed_seeds_no_std;
381    use test_case::test_case;
382
383    use super::super::segment::MAX_PAYLOAD_AND_CONTROL_LEN;
384    use super::*;
385
386    fn arb_seqnum() -> impl Strategy<Value = SeqNum> {
387        any::<u32>().prop_map(SeqNum::from)
388    }
389
390    // Generates a triple (a, b, c) s.t. a < b < a + 2^30 && b < c < a + 2^30.
391    // This triple is used to verify that transitivity holds.
392    fn arb_seqnum_trans_tripple() -> impl Strategy<Value = (SeqNum, SeqNum, SeqNum)> {
393        arb_seqnum().prop_flat_map(|a| {
394            (1..=MAX_PAYLOAD_AND_CONTROL_LEN).prop_flat_map(move |diff_a_b| {
395                let b = a + diff_a_b;
396                (1..=MAX_PAYLOAD_AND_CONTROL_LEN - diff_a_b).prop_flat_map(move |diff_b_c| {
397                    let c = b + diff_b_c;
398                    (Just(a), Just(b), Just(c))
399                })
400            })
401        })
402    }
403
404    #[test_case(WindowSize::new(1).unwrap() => (UnscaledWindowSize::from(1), WindowScale::default()))]
405    #[test_case(WindowSize::new(65535).unwrap() => (UnscaledWindowSize::from(65535), WindowScale::default()))]
406    #[test_case(WindowSize::new(65536).unwrap() => (UnscaledWindowSize::from(32768), WindowScale::new(1).unwrap()))]
407    #[test_case(WindowSize::new(65537).unwrap() => (UnscaledWindowSize::from(32768), WindowScale::new(1).unwrap()))]
408    fn window_scale(size: WindowSize) -> (UnscaledWindowSize, WindowScale) {
409        let scale = size.scale();
410        (size >> scale, scale)
411    }
412
413    proptest! {
414        #![proptest_config(Config {
415            // Add all failed seeds here.
416            failure_persistence: failed_seeds_no_std!(),
417            ..Config::default()
418        })]
419
420        #[test]
421        fn seqnum_ord_is_reflexive(a in arb_seqnum()) {
422            prop_assert_eq!(a, a)
423        }
424
425        #[test]
426        fn seqnum_ord_is_total(a in arb_seqnum(), b in arb_seqnum()) {
427            if a == b {
428                prop_assert!(!a.before(b) && !b.before(a))
429            } else {
430                prop_assert!(a.before(b) ^ b.before(a))
431            }
432        }
433
434        #[test]
435        fn seqnum_ord_is_transitive((a, b, c) in arb_seqnum_trans_tripple()) {
436            prop_assert!(a.before(b) && b.before(c) && a.before(c));
437        }
438
439        #[test]
440        fn seqnum_add_positive_greater(a in arb_seqnum(), b in 1..=i32::MAX) {
441            prop_assert!(a.before(a + b))
442        }
443
444        #[test]
445        fn seqnum_add_negative_smaller(a in arb_seqnum(), b in i32::MIN..=-1) {
446            prop_assert!(a.after(a + b))
447        }
448
449        #[test]
450        fn seqnum_sub_positive_smaller(a in arb_seqnum(), b in 1..=i32::MAX) {
451            prop_assert!(a.after(a - b))
452        }
453
454        #[test]
455        fn seqnum_sub_negative_greater(a in arb_seqnum(), b in i32::MIN..=-1) {
456            prop_assert!(a.before(a - b))
457        }
458
459        #[test]
460        fn seqnum_zero_identity(a in arb_seqnum()) {
461            prop_assert_eq!(a, a + 0)
462        }
463
464        #[test]
465        fn seqnum_before_after_inverse(a in arb_seqnum(), b in arb_seqnum()) {
466            prop_assert_eq!(a.after(b), b.before(a))
467        }
468
469        #[test]
470        fn seqnum_wraps_around_at_max_length(a in arb_seqnum()) {
471            prop_assert!(a.before(a + MAX_PAYLOAD_AND_CONTROL_LEN));
472            prop_assert!(a.after(a + MAX_PAYLOAD_AND_CONTROL_LEN + 1));
473        }
474
475        #[test]
476        fn window_size_less_than_or_eq_to_max(wnd in 0..=WindowSize::MAX.0) {
477            prop_assert_eq!(WindowSize::from_u32(wnd), Some(WindowSize(wnd)));
478        }
479
480        #[test]
481        fn window_size_greater_than_max(wnd in WindowSize::MAX.0+1..=u32::MAX) {
482            prop_assert_eq!(WindowSize::from_u32(wnd), None);
483        }
484    }
485}