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 after the other.
140    ///
141    /// Please refer to [`SeqNum`] for the defined order.
142    pub fn after(self, other: SeqNum) -> bool {
143        self - other > 0
144    }
145}
146
147/// A witness type for TCP window size.
148///
149/// Per [RFC 7323 Section 2.3]:
150/// > ..., the above constraints imply that two times the maximum window size
151/// > must be less than 2^31, or
152/// >                    max window < 2^30
153///
154/// [RFC 7323 Section 2.3]: https://tools.ietf.org/html/rfc7323#section-2.3
155#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
156pub struct WindowSize(u32);
157
158impl WindowSize {
159    /// The largest possible window size.
160    pub const MAX: WindowSize = WindowSize(1 << 30 - 1);
161    /// The smallest possible window size.
162    pub const ZERO: WindowSize = WindowSize(0);
163
164    /// The Netstack3 default window size.
165    // TODO(https://github.com/rust-lang/rust/issues/67441): put this constant
166    // in the state module once `Option::unwrap` is stable.
167    pub const DEFAULT: WindowSize = WindowSize(65535);
168
169    /// Create a new `WindowSize` from the provided `u32`.
170    ///
171    /// If the provided window size is out of range, then `None` is returned.
172    pub const fn from_u32(wnd: u32) -> Option<Self> {
173        let WindowSize(max) = Self::MAX;
174        if wnd > max {
175            None
176        } else {
177            Some(Self(wnd))
178        }
179    }
180
181    /// Add a `u32` to this WindowSize, saturating at [`WindowSize::MAX`].
182    pub fn saturating_add(self, rhs: u32) -> Self {
183        Self::from_u32(u32::from(self).saturating_add(rhs)).unwrap_or(Self::MAX)
184    }
185
186    /// Create a new [`WindowSize`], returning `None` if the argument is out of range.
187    pub fn new(wnd: usize) -> Option<Self> {
188        u32::try_from(wnd).ok_checked::<TryFromIntError>().and_then(WindowSize::from_u32)
189    }
190
191    /// Subtract `diff` from `self`, returning `None` if the result would be negative.
192    pub fn checked_sub(self, diff: usize) -> Option<Self> {
193        // The call to Self::new will never return None.
194        //
195        // If diff is larger than self, the checked_sub will return None. Otherwise the result must
196        // be less than Self::MAX, since the value of self before subtraction must be less than or
197        // equal to Self::MAX.
198        usize::from(self).checked_sub(diff).and_then(Self::new)
199    }
200
201    /// Subtract `diff` from `self` returning [`WindowSize::ZERO`] if the result
202    /// would be negative.
203    pub fn saturating_sub(self, diff: usize) -> Self {
204        self.checked_sub(diff).unwrap_or(WindowSize::ZERO)
205    }
206
207    /// The window scale that needs to be advertised during the handshake.
208    pub fn scale(self) -> WindowScale {
209        let WindowSize(size) = self;
210        let effective_bits = u8::try_from(32 - u32::leading_zeros(size)).unwrap();
211        let scale = WindowScale(effective_bits.saturating_sub(16));
212        scale
213    }
214}
215
216impl ops::Add<WindowSize> for SeqNum {
217    type Output = SeqNum;
218
219    fn add(self, WindowSize(wnd): WindowSize) -> Self::Output {
220        self + wnd
221    }
222}
223
224impl From<WindowSize> for u32 {
225    fn from(WindowSize(wnd): WindowSize) -> Self {
226        wnd
227    }
228}
229
230#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
231impl From<WindowSize> for usize {
232    fn from(WindowSize(wnd): WindowSize) -> Self {
233        wnd as usize
234    }
235}
236
237#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
238/// This type is a witness for a valid window scale exponent value.
239///
240/// Per RFC 7323 Section 2.2, the restriction is as follows:
241///   The maximum scale exponent is limited to 14 for a maximum permissible
242///   receive window size of 1 GiB (2^(14+16)).
243pub struct WindowScale(u8);
244
245impl WindowScale {
246    /// The largest possible [`WindowScale`].
247    pub const MAX: WindowScale = WindowScale(14);
248    /// The smallest possible [`WindowScale`].
249    pub const ZERO: WindowScale = WindowScale(0);
250
251    /// Creates a new `WindowScale`.
252    ///
253    /// Returns `None` if the input exceeds the maximum possible value.
254    pub fn new(ws: u8) -> Option<Self> {
255        (ws <= Self::MAX.get()).then_some(WindowScale(ws))
256    }
257
258    /// Returns the inner value.
259    pub fn get(&self) -> u8 {
260        let Self(ws) = self;
261        *ws
262    }
263}
264
265#[derive(Debug, PartialEq, Eq, Clone, Copy)]
266/// Window size that is used in the window field of a TCP segment.
267///
268/// For connections with window scaling enabled, the receiver has to scale this
269/// value back to get the real window size advertised by the peer.
270pub struct UnscaledWindowSize(u16);
271
272impl ops::Shl<WindowScale> for UnscaledWindowSize {
273    type Output = WindowSize;
274
275    fn shl(self, WindowScale(scale): WindowScale) -> Self::Output {
276        let UnscaledWindowSize(size) = self;
277        // `scale` is guaranteed to be <= 14, so the result must fit in a u32.
278        WindowSize::from_u32(u32::from(size) << scale).unwrap()
279    }
280}
281
282impl ops::Shr<WindowScale> for WindowSize {
283    type Output = UnscaledWindowSize;
284
285    fn shr(self, WindowScale(scale): WindowScale) -> Self::Output {
286        let WindowSize(size) = self;
287        UnscaledWindowSize(u16::try_from(size >> scale).unwrap_or(u16::MAX))
288    }
289}
290
291impl From<u16> for UnscaledWindowSize {
292    fn from(value: u16) -> Self {
293        Self(value)
294    }
295}
296
297impl From<UnscaledWindowSize> for u16 {
298    fn from(UnscaledWindowSize(value): UnscaledWindowSize) -> Self {
299        value
300    }
301}
302
303#[cfg(feature = "testutils")]
304mod testutils {
305    use super::*;
306
307    impl UnscaledWindowSize {
308        /// Create a new UnscaledWindowSize.
309        ///
310        /// Panics if `size` is not in range.
311        pub fn from_usize(size: usize) -> Self {
312            UnscaledWindowSize::from(u16::try_from(size).unwrap())
313        }
314
315        /// Create a new UnscaledWindowSize.
316        ///
317        /// Panics if `size` is not in range.
318        pub fn from_u32(size: u32) -> Self {
319            UnscaledWindowSize::from(u16::try_from(size).unwrap())
320        }
321    }
322}
323
324#[cfg(test)]
325mod tests {
326    use alloc::format;
327
328    use proptest::arbitrary::any;
329    use proptest::strategy::{Just, Strategy};
330    use proptest::test_runner::Config;
331    use proptest::{prop_assert, prop_assert_eq, proptest};
332    use proptest_support::failed_seeds_no_std;
333    use test_case::test_case;
334
335    use super::super::segment::MAX_PAYLOAD_AND_CONTROL_LEN;
336    use super::*;
337
338    fn arb_seqnum() -> impl Strategy<Value = SeqNum> {
339        any::<u32>().prop_map(SeqNum::from)
340    }
341
342    // Generates a triple (a, b, c) s.t. a < b < a + 2^30 && b < c < a + 2^30.
343    // This triple is used to verify that transitivity holds.
344    fn arb_seqnum_trans_tripple() -> impl Strategy<Value = (SeqNum, SeqNum, SeqNum)> {
345        arb_seqnum().prop_flat_map(|a| {
346            (1..=MAX_PAYLOAD_AND_CONTROL_LEN).prop_flat_map(move |diff_a_b| {
347                let b = a + diff_a_b;
348                (1..=MAX_PAYLOAD_AND_CONTROL_LEN - diff_a_b).prop_flat_map(move |diff_b_c| {
349                    let c = b + diff_b_c;
350                    (Just(a), Just(b), Just(c))
351                })
352            })
353        })
354    }
355
356    #[test_case(WindowSize::new(1).unwrap() => (UnscaledWindowSize::from(1), WindowScale::default()))]
357    #[test_case(WindowSize::new(65535).unwrap() => (UnscaledWindowSize::from(65535), WindowScale::default()))]
358    #[test_case(WindowSize::new(65536).unwrap() => (UnscaledWindowSize::from(32768), WindowScale::new(1).unwrap()))]
359    #[test_case(WindowSize::new(65537).unwrap() => (UnscaledWindowSize::from(32768), WindowScale::new(1).unwrap()))]
360    fn window_scale(size: WindowSize) -> (UnscaledWindowSize, WindowScale) {
361        let scale = size.scale();
362        (size >> scale, scale)
363    }
364
365    proptest! {
366        #![proptest_config(Config {
367            // Add all failed seeds here.
368            failure_persistence: failed_seeds_no_std!(),
369            ..Config::default()
370        })]
371
372        #[test]
373        fn seqnum_ord_is_reflexive(a in arb_seqnum()) {
374            prop_assert_eq!(a, a)
375        }
376
377        #[test]
378        fn seqnum_ord_is_total(a in arb_seqnum(), b in arb_seqnum()) {
379            if a == b {
380                prop_assert!(!a.before(b) && !b.before(a))
381            } else {
382                prop_assert!(a.before(b) ^ b.before(a))
383            }
384        }
385
386        #[test]
387        fn seqnum_ord_is_transitive((a, b, c) in arb_seqnum_trans_tripple()) {
388            prop_assert!(a.before(b) && b.before(c) && a.before(c));
389        }
390
391        #[test]
392        fn seqnum_add_positive_greater(a in arb_seqnum(), b in 1..=i32::MAX) {
393            prop_assert!(a.before(a + b))
394        }
395
396        #[test]
397        fn seqnum_add_negative_smaller(a in arb_seqnum(), b in i32::MIN..=-1) {
398            prop_assert!(a.after(a + b))
399        }
400
401        #[test]
402        fn seqnum_sub_positive_smaller(a in arb_seqnum(), b in 1..=i32::MAX) {
403            prop_assert!(a.after(a - b))
404        }
405
406        #[test]
407        fn seqnum_sub_negative_greater(a in arb_seqnum(), b in i32::MIN..=-1) {
408            prop_assert!(a.before(a - b))
409        }
410
411        #[test]
412        fn seqnum_zero_identity(a in arb_seqnum()) {
413            prop_assert_eq!(a, a + 0)
414        }
415
416        #[test]
417        fn seqnum_before_after_inverse(a in arb_seqnum(), b in arb_seqnum()) {
418            prop_assert_eq!(a.after(b), b.before(a))
419        }
420
421        #[test]
422        fn seqnum_wraps_around_at_max_length(a in arb_seqnum()) {
423            prop_assert!(a.before(a + MAX_PAYLOAD_AND_CONTROL_LEN));
424            prop_assert!(a.after(a + MAX_PAYLOAD_AND_CONTROL_LEN + 1));
425        }
426
427        #[test]
428        fn window_size_less_than_or_eq_to_max(wnd in 0..=WindowSize::MAX.0) {
429            prop_assert_eq!(WindowSize::from_u32(wnd), Some(WindowSize(wnd)));
430        }
431
432        #[test]
433        fn window_size_greater_than_max(wnd in WindowSize::MAX.0+1..=u32::MAX) {
434            prop_assert_eq!(WindowSize::from_u32(wnd), None);
435        }
436    }
437}