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.
45//! TCP sequence numbers and operations on them.
67use core::convert::TryFrom as _;
8use core::num::TryFromIntError;
9use core::ops;
1011use explicit::ResultExt as _;
1213/// 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);
2728impl ops::Add<i32> for SeqNum {
29type Output = SeqNum;
3031fn add(self, rhs: i32) -> Self::Output {
32let Self(lhs) = self;
33Self(lhs.wrapping_add_signed(rhs))
34 }
35}
3637impl ops::Sub<i32> for SeqNum {
38type Output = SeqNum;
3940fn sub(self, rhs: i32) -> Self::Output {
41let Self(lhs) = self;
42Self(lhs.wrapping_add_signed(rhs.wrapping_neg()))
43 }
44}
4546impl ops::Add<u32> for SeqNum {
47type Output = SeqNum;
4849fn add(self, rhs: u32) -> Self::Output {
50let Self(lhs) = self;
51Self(lhs.wrapping_add(rhs))
52 }
53}
5455impl ops::Sub<u32> for SeqNum {
56type Output = SeqNum;
5758fn sub(self, rhs: u32) -> Self::Output {
59let Self(lhs) = self;
60Self(lhs.wrapping_sub(rhs))
61 }
62}
6364impl ops::Sub<WindowSize> for SeqNum {
65type Output = SeqNum;
6667fn 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.
71self - i32::try_from(wnd).unwrap()
72 }
73}
7475impl ops::Add<usize> for SeqNum {
76type Output = SeqNum;
7778fn 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`.
86self + (rhs as u32)
87 }
88}
8990impl ops::Sub for SeqNum {
91// `i32` is more intuitive than `u32`, since subtraction may yield negative
92 // values.
93type Output = i32;
9495fn sub(self, rhs: Self) -> Self::Output {
96let Self(lhs) = self;
97let 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
107lhs.wrapping_sub(rhs) as i32
108 }
109}
110111impl From<u32> for SeqNum {
112fn from(x: u32) -> Self {
113Self::new(x)
114 }
115}
116117impl From<SeqNum> for u32 {
118fn from(x: SeqNum) -> Self {
119let SeqNum(x) = x;
120 x
121 }
122}
123124impl SeqNum {
125/// Creates a new sequence number.
126pub const fn new(x: u32) -> Self {
127Self(x)
128 }
129}
130131impl SeqNum {
132/// A predicate for whether a sequence number is before the other.
133 ///
134 /// Please refer to [`SeqNum`] for the defined order.
135pub fn before(self, other: SeqNum) -> bool {
136self - other < 0
137}
138139/// 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.
143pub fn before_or_eq(self, other: SeqNum) -> bool {
144self - other <= 0
145}
146147/// A predicate for whether a sequence number is after the other.
148 ///
149 /// Please refer to [`SeqNum`] for the defined order.
150pub fn after(self, other: SeqNum) -> bool {
151self - other > 0
152}
153154/// 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.
158pub fn after_or_eq(self, other: SeqNum) -> bool {
159self - other >= 0
160}
161162/// 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.
166pub fn earliest(self, other: SeqNum) -> SeqNum {
167if self.before(other) {
168self
169} else {
170 other
171 }
172 }
173174/// 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.
178pub fn latest(self, other: SeqNum) -> SeqNum {
179if self.after(other) {
180self
181} else {
182 other
183 }
184 }
185}
186187/// 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);
197198impl WindowSize {
199/// The largest possible window size.
200pub const MAX: WindowSize = WindowSize(1 << 30 - 1);
201/// The smallest possible window size.
202pub const ZERO: WindowSize = WindowSize(0);
203/// A window size of 1, the smallest nonzero window size.
204pub const ONE: WindowSize = WindowSize(1);
205206/// 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.
209pub const DEFAULT: WindowSize = WindowSize(65535);
210211/// Create a new `WindowSize` from the provided `u32`.
212 ///
213 /// If the provided window size is out of range, then `None` is returned.
214pub const fn from_u32(wnd: u32) -> Option<Self> {
215let WindowSize(max) = Self::MAX;
216if wnd > max {
217None
218} else {
219Some(Self(wnd))
220 }
221 }
222223/// Add a `u32` to this WindowSize, saturating at [`WindowSize::MAX`].
224pub fn saturating_add(self, rhs: u32) -> Self {
225Self::from_u32(u32::from(self).saturating_add(rhs)).unwrap_or(Self::MAX)
226 }
227228/// Create a new [`WindowSize`], returning `None` if the argument is out of range.
229pub fn new(wnd: usize) -> Option<Self> {
230 u32::try_from(wnd).ok_checked::<TryFromIntError>().and_then(WindowSize::from_u32)
231 }
232233/// Subtract `diff` from `self`, returning `None` if the result would be negative.
234pub 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.
240usize::from(self).checked_sub(diff).and_then(Self::new)
241 }
242243/// Subtract `diff` from `self` returning [`WindowSize::ZERO`] if the result
244 /// would be negative.
245pub fn saturating_sub(self, diff: usize) -> Self {
246self.checked_sub(diff).unwrap_or(WindowSize::ZERO)
247 }
248249/// The window scale that needs to be advertised during the handshake.
250pub fn scale(self) -> WindowScale {
251let WindowSize(size) = self;
252let effective_bits = u8::try_from(32 - u32::leading_zeros(size)).unwrap();
253let scale = WindowScale(effective_bits.saturating_sub(16));
254 scale
255 }
256257/// Returns this `WindowSize` with a halved value
258pub fn halved(self) -> WindowSize {
259let WindowSize(size) = self;
260 WindowSize(size >> 1)
261 }
262}
263264impl ops::Add<WindowSize> for SeqNum {
265type Output = SeqNum;
266267fn add(self, WindowSize(wnd): WindowSize) -> Self::Output {
268self + wnd
269 }
270}
271272impl From<WindowSize> for u32 {
273fn from(WindowSize(wnd): WindowSize) -> Self {
274 wnd
275 }
276}
277278#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
279impl From<WindowSize> for usize {
280fn from(WindowSize(wnd): WindowSize) -> Self {
281 wnd as usize
282 }
283}
284285#[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);
292293impl WindowScale {
294/// The largest possible [`WindowScale`].
295pub const MAX: WindowScale = WindowScale(14);
296/// The smallest possible [`WindowScale`].
297pub const ZERO: WindowScale = WindowScale(0);
298299/// Creates a new `WindowScale`.
300 ///
301 /// Returns `None` if the input exceeds the maximum possible value.
302pub fn new(ws: u8) -> Option<Self> {
303 (ws <= Self::MAX.get()).then_some(WindowScale(ws))
304 }
305306/// Returns the inner value.
307pub fn get(&self) -> u8 {
308let Self(ws) = self;
309*ws
310 }
311}
312313#[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);
319320impl ops::Shl<WindowScale> for UnscaledWindowSize {
321type Output = WindowSize;
322323fn shl(self, WindowScale(scale): WindowScale) -> Self::Output {
324let UnscaledWindowSize(size) = self;
325// `scale` is guaranteed to be <= 14, so the result must fit in a u32.
326WindowSize::from_u32(u32::from(size) << scale).unwrap()
327 }
328}
329330impl ops::Shr<WindowScale> for WindowSize {
331type Output = UnscaledWindowSize;
332333fn shr(self, WindowScale(scale): WindowScale) -> Self::Output {
334let WindowSize(size) = self;
335 UnscaledWindowSize(u16::try_from(size >> scale).unwrap_or(u16::MAX))
336 }
337}
338339impl From<u16> for UnscaledWindowSize {
340fn from(value: u16) -> Self {
341Self(value)
342 }
343}
344345impl From<UnscaledWindowSize> for u16 {
346fn from(UnscaledWindowSize(value): UnscaledWindowSize) -> Self {
347 value
348 }
349}
350351#[cfg(feature = "testutils")]
352mod testutils {
353use super::*;
354355impl UnscaledWindowSize {
356/// Create a new UnscaledWindowSize.
357 ///
358 /// Panics if `size` is not in range.
359pub fn from_usize(size: usize) -> Self {
360 UnscaledWindowSize::from(u16::try_from(size).unwrap())
361 }
362363/// Create a new UnscaledWindowSize.
364 ///
365 /// Panics if `size` is not in range.
366pub fn from_u32(size: u32) -> Self {
367 UnscaledWindowSize::from(u16::try_from(size).unwrap())
368 }
369 }
370}
371372#[cfg(test)]
373mod tests {
374use alloc::format;
375376use proptest::arbitrary::any;
377use proptest::strategy::{Just, Strategy};
378use proptest::test_runner::Config;
379use proptest::{prop_assert, prop_assert_eq, proptest};
380use proptest_support::failed_seeds_no_std;
381use test_case::test_case;
382383use super::super::segment::MAX_PAYLOAD_AND_CONTROL_LEN;
384use super::*;
385386fn arb_seqnum() -> impl Strategy<Value = SeqNum> {
387 any::<u32>().prop_map(SeqNum::from)
388 }
389390// 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.
392fn 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| {
395let b = a + diff_a_b;
396 (1..=MAX_PAYLOAD_AND_CONTROL_LEN - diff_a_b).prop_flat_map(move |diff_b_c| {
397let c = b + diff_b_c;
398 (Just(a), Just(b), Just(c))
399 })
400 })
401 })
402 }
403404#[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()))]
408fn window_scale(size: WindowSize) -> (UnscaledWindowSize, WindowScale) {
409let scale = size.scale();
410 (size >> scale, scale)
411 }
412413proptest! {
414#![proptest_config(Config {
415// Add all failed seeds here.
416failure_persistence: failed_seeds_no_std!(),
417 ..Config::default()
418 })]
419420 #[test]
421fn seqnum_ord_is_reflexive(a in arb_seqnum()) {
422prop_assert_eq!(a, a)
423 }
424425#[test]
426fn seqnum_ord_is_total(a in arb_seqnum(), b in arb_seqnum()) {
427if a == b {
428prop_assert!(!a.before(b) && !b.before(a))
429 } else {
430prop_assert!(a.before(b) ^ b.before(a))
431 }
432 }
433434#[test]
435fn seqnum_ord_is_transitive((a, b, c) in arb_seqnum_trans_tripple()) {
436prop_assert!(a.before(b) && b.before(c) && a.before(c));
437 }
438439#[test]
440fn seqnum_add_positive_greater(a in arb_seqnum(), b in 1..=i32::MAX) {
441prop_assert!(a.before(a + b))
442 }
443444#[test]
445fn seqnum_add_negative_smaller(a in arb_seqnum(), b in i32::MIN..=-1) {
446prop_assert!(a.after(a + b))
447 }
448449#[test]
450fn seqnum_sub_positive_smaller(a in arb_seqnum(), b in 1..=i32::MAX) {
451prop_assert!(a.after(a - b))
452 }
453454#[test]
455fn seqnum_sub_negative_greater(a in arb_seqnum(), b in i32::MIN..=-1) {
456prop_assert!(a.before(a - b))
457 }
458459#[test]
460fn seqnum_zero_identity(a in arb_seqnum()) {
461prop_assert_eq!(a, a + 0)
462 }
463464#[test]
465fn seqnum_before_after_inverse(a in arb_seqnum(), b in arb_seqnum()) {
466prop_assert_eq!(a.after(b), b.before(a))
467 }
468469#[test]
470fn seqnum_wraps_around_at_max_length(a in arb_seqnum()) {
471prop_assert!(a.before(a + MAX_PAYLOAD_AND_CONTROL_LEN));
472prop_assert!(a.after(a + MAX_PAYLOAD_AND_CONTROL_LEN + 1));
473 }
474475#[test]
476fn window_size_less_than_or_eq_to_max(wnd in 0..=WindowSize::MAX.0) {
477prop_assert_eq!(WindowSize::from_u32(wnd), Some(WindowSize(wnd)));
478 }
479480#[test]
481fn window_size_greater_than_max(wnd in WindowSize::MAX.0+1..=u32::MAX) {
482prop_assert_eq!(WindowSize::from_u32(wnd), None);
483 }
484 }
485}