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 after the other.
140 ///
141 /// Please refer to [`SeqNum`] for the defined order.
142pub fn after(self, other: SeqNum) -> bool {
143self - other > 0
144}
145}
146147/// 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);
157158impl WindowSize {
159/// The largest possible window size.
160pub const MAX: WindowSize = WindowSize(1 << 30 - 1);
161/// The smallest possible window size.
162pub const ZERO: WindowSize = WindowSize(0);
163164/// 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.
167pub const DEFAULT: WindowSize = WindowSize(65535);
168169/// Create a new `WindowSize` from the provided `u32`.
170 ///
171 /// If the provided window size is out of range, then `None` is returned.
172pub const fn from_u32(wnd: u32) -> Option<Self> {
173let WindowSize(max) = Self::MAX;
174if wnd > max {
175None
176} else {
177Some(Self(wnd))
178 }
179 }
180181/// Add a `u32` to this WindowSize, saturating at [`WindowSize::MAX`].
182pub fn saturating_add(self, rhs: u32) -> Self {
183Self::from_u32(u32::from(self).saturating_add(rhs)).unwrap_or(Self::MAX)
184 }
185186/// Create a new [`WindowSize`], returning `None` if the argument is out of range.
187pub fn new(wnd: usize) -> Option<Self> {
188 u32::try_from(wnd).ok_checked::<TryFromIntError>().and_then(WindowSize::from_u32)
189 }
190191/// Subtract `diff` from `self`, returning `None` if the result would be negative.
192pub 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.
198usize::from(self).checked_sub(diff).and_then(Self::new)
199 }
200201/// Subtract `diff` from `self` returning [`WindowSize::ZERO`] if the result
202 /// would be negative.
203pub fn saturating_sub(self, diff: usize) -> Self {
204self.checked_sub(diff).unwrap_or(WindowSize::ZERO)
205 }
206207/// The window scale that needs to be advertised during the handshake.
208pub fn scale(self) -> WindowScale {
209let WindowSize(size) = self;
210let effective_bits = u8::try_from(32 - u32::leading_zeros(size)).unwrap();
211let scale = WindowScale(effective_bits.saturating_sub(16));
212 scale
213 }
214}
215216impl ops::Add<WindowSize> for SeqNum {
217type Output = SeqNum;
218219fn add(self, WindowSize(wnd): WindowSize) -> Self::Output {
220self + wnd
221 }
222}
223224impl From<WindowSize> for u32 {
225fn from(WindowSize(wnd): WindowSize) -> Self {
226 wnd
227 }
228}
229230#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
231impl From<WindowSize> for usize {
232fn from(WindowSize(wnd): WindowSize) -> Self {
233 wnd as usize
234 }
235}
236237#[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);
244245impl WindowScale {
246/// The largest possible [`WindowScale`].
247pub const MAX: WindowScale = WindowScale(14);
248/// The smallest possible [`WindowScale`].
249pub const ZERO: WindowScale = WindowScale(0);
250251/// Creates a new `WindowScale`.
252 ///
253 /// Returns `None` if the input exceeds the maximum possible value.
254pub fn new(ws: u8) -> Option<Self> {
255 (ws <= Self::MAX.get()).then_some(WindowScale(ws))
256 }
257258/// Returns the inner value.
259pub fn get(&self) -> u8 {
260let Self(ws) = self;
261*ws
262 }
263}
264265#[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);
271272impl ops::Shl<WindowScale> for UnscaledWindowSize {
273type Output = WindowSize;
274275fn shl(self, WindowScale(scale): WindowScale) -> Self::Output {
276let UnscaledWindowSize(size) = self;
277// `scale` is guaranteed to be <= 14, so the result must fit in a u32.
278WindowSize::from_u32(u32::from(size) << scale).unwrap()
279 }
280}
281282impl ops::Shr<WindowScale> for WindowSize {
283type Output = UnscaledWindowSize;
284285fn shr(self, WindowScale(scale): WindowScale) -> Self::Output {
286let WindowSize(size) = self;
287 UnscaledWindowSize(u16::try_from(size >> scale).unwrap_or(u16::MAX))
288 }
289}
290291impl From<u16> for UnscaledWindowSize {
292fn from(value: u16) -> Self {
293Self(value)
294 }
295}
296297impl From<UnscaledWindowSize> for u16 {
298fn from(UnscaledWindowSize(value): UnscaledWindowSize) -> Self {
299 value
300 }
301}
302303#[cfg(feature = "testutils")]
304mod testutils {
305use super::*;
306307impl UnscaledWindowSize {
308/// Create a new UnscaledWindowSize.
309 ///
310 /// Panics if `size` is not in range.
311pub fn from_usize(size: usize) -> Self {
312 UnscaledWindowSize::from(u16::try_from(size).unwrap())
313 }
314315/// Create a new UnscaledWindowSize.
316 ///
317 /// Panics if `size` is not in range.
318pub fn from_u32(size: u32) -> Self {
319 UnscaledWindowSize::from(u16::try_from(size).unwrap())
320 }
321 }
322}
323324#[cfg(test)]
325mod tests {
326use alloc::format;
327328use proptest::arbitrary::any;
329use proptest::strategy::{Just, Strategy};
330use proptest::test_runner::Config;
331use proptest::{prop_assert, prop_assert_eq, proptest};
332use proptest_support::failed_seeds_no_std;
333use test_case::test_case;
334335use super::super::segment::MAX_PAYLOAD_AND_CONTROL_LEN;
336use super::*;
337338fn arb_seqnum() -> impl Strategy<Value = SeqNum> {
339 any::<u32>().prop_map(SeqNum::from)
340 }
341342// 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.
344fn 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| {
347let b = a + diff_a_b;
348 (1..=MAX_PAYLOAD_AND_CONTROL_LEN - diff_a_b).prop_flat_map(move |diff_b_c| {
349let c = b + diff_b_c;
350 (Just(a), Just(b), Just(c))
351 })
352 })
353 })
354 }
355356#[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()))]
360fn window_scale(size: WindowSize) -> (UnscaledWindowSize, WindowScale) {
361let scale = size.scale();
362 (size >> scale, scale)
363 }
364365proptest! {
366#![proptest_config(Config {
367// Add all failed seeds here.
368failure_persistence: failed_seeds_no_std!(),
369 ..Config::default()
370 })]
371372 #[test]
373fn seqnum_ord_is_reflexive(a in arb_seqnum()) {
374prop_assert_eq!(a, a)
375 }
376377#[test]
378fn seqnum_ord_is_total(a in arb_seqnum(), b in arb_seqnum()) {
379if a == b {
380prop_assert!(!a.before(b) && !b.before(a))
381 } else {
382prop_assert!(a.before(b) ^ b.before(a))
383 }
384 }
385386#[test]
387fn seqnum_ord_is_transitive((a, b, c) in arb_seqnum_trans_tripple()) {
388prop_assert!(a.before(b) && b.before(c) && a.before(c));
389 }
390391#[test]
392fn seqnum_add_positive_greater(a in arb_seqnum(), b in 1..=i32::MAX) {
393prop_assert!(a.before(a + b))
394 }
395396#[test]
397fn seqnum_add_negative_smaller(a in arb_seqnum(), b in i32::MIN..=-1) {
398prop_assert!(a.after(a + b))
399 }
400401#[test]
402fn seqnum_sub_positive_smaller(a in arb_seqnum(), b in 1..=i32::MAX) {
403prop_assert!(a.after(a - b))
404 }
405406#[test]
407fn seqnum_sub_negative_greater(a in arb_seqnum(), b in i32::MIN..=-1) {
408prop_assert!(a.before(a - b))
409 }
410411#[test]
412fn seqnum_zero_identity(a in arb_seqnum()) {
413prop_assert_eq!(a, a + 0)
414 }
415416#[test]
417fn seqnum_before_after_inverse(a in arb_seqnum(), b in arb_seqnum()) {
418prop_assert_eq!(a.after(b), b.before(a))
419 }
420421#[test]
422fn seqnum_wraps_around_at_max_length(a in arb_seqnum()) {
423prop_assert!(a.before(a + MAX_PAYLOAD_AND_CONTROL_LEN));
424prop_assert!(a.after(a + MAX_PAYLOAD_AND_CONTROL_LEN + 1));
425 }
426427#[test]
428fn window_size_less_than_or_eq_to_max(wnd in 0..=WindowSize::MAX.0) {
429prop_assert_eq!(WindowSize::from_u32(wnd), Some(WindowSize(wnd)));
430 }
431432#[test]
433fn window_size_greater_than_max(wnd in WindowSize::MAX.0+1..=u32::MAX) {
434prop_assert_eq!(WindowSize::from_u32(wnd), None);
435 }
436 }
437}