netstack3_filter/conntrack/
tcp.rs

1// Copyright 2024 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 state tracking.
6
7use core::time::Duration;
8
9use netstack3_base::{Control, SegmentHeader, SeqNum, UnscaledWindowSize, WindowScale, WindowSize};
10use replace_with::replace_with_and;
11
12use super::{
13    ConnectionDirection, ConnectionUpdateAction, ConnectionUpdateError, EstablishmentLifecycle,
14};
15
16/// A struct that completely encapsulates tracking a bidirectional TCP
17/// connection.
18#[derive(Debug, Clone)]
19pub(crate) struct Connection {
20    /// The current state of the TCP connection.
21    state: State,
22}
23
24impl Connection {
25    pub fn new(segment: &SegmentHeader, payload_len: usize, self_connected: bool) -> Option<Self> {
26        Some(Self {
27            // TODO(https://fxbug.dev/355699182): Properly support self-connected
28            // connections.
29            state: if self_connected {
30                Untracked {}.into()
31            } else {
32                State::new(segment, payload_len)?
33            },
34        })
35    }
36
37    pub fn expiry_duration(&self, establishment_lifecycle: EstablishmentLifecycle) -> Duration {
38        self.state.expiry_duration(establishment_lifecycle)
39    }
40
41    pub fn update(
42        &mut self,
43        segment: &SegmentHeader,
44        payload_len: usize,
45        dir: ConnectionDirection,
46    ) -> Result<ConnectionUpdateAction, ConnectionUpdateError> {
47        let valid =
48            replace_with_and(&mut self.state, |state| state.update(segment, payload_len, dir));
49
50        if !valid {
51            return Err(ConnectionUpdateError::InvalidPacket);
52        }
53
54        match self.state {
55            State::Closed(_) => Ok(ConnectionUpdateAction::RemoveEntry),
56            State::Untracked(_)
57            | State::SynSent(_)
58            | State::WaitingOnOpeningAck(_)
59            | State::Closing(_)
60            | State::Established(_) => Ok(ConnectionUpdateAction::NoAction),
61        }
62    }
63}
64
65/// States for a TCP connection as a whole.
66///
67/// These vaguely correspond to states from RFC 9293, but since they apply to
68/// the whole connection, and we're just snooping in the middle, they can't line
69/// up perfectly 1:1. See the doc comments on each state for the expected state
70/// of each of the peers assuming that all packets are received and are valid.
71#[derive(Debug, Clone, PartialEq, Eq)]
72pub(crate) enum State {
73    /// The connection has properties that break standard state tracking. This
74    /// state does a good-enough job tracking the connection.
75    ///
76    /// This is a short-circuit state that can never be left.
77    Untracked(Untracked),
78
79    /// The connection has been closed, either by the FIN handshake or valid
80    /// RST.
81    ///
82    /// This is a short-circuit state that can never be left.
83    Closed(Closed),
84
85    /// The initial SYN for this connection has been sent. State contained
86    /// within is everything that can be gleaned from the initial SYN packet
87    /// sent in the original direction.
88    ///
89    /// Expected peer states:
90    /// - Original: `SYN_SENT`
91    /// - Reply: `SYN_RECEIVED` (upon receipt)
92    SynSent(SynSent),
93
94    /// The reply peer has sent a valid SYN/ACK segment. All that remains is for
95    /// the original peer to ACK.
96    ///
97    /// Expected peer states.
98    /// - Original: ESTABLISHED
99    /// - Reply: SYN_RECEIVED
100    WaitingOnOpeningAck(WaitingOnOpeningAck),
101
102    /// The handshake has completed and data may begin flowing at any time. This
103    /// is where most connections will spend the vast majority of their time.
104    ///
105    /// Expected peer states:
106    /// - Original: ESTABLISHED
107    /// - Reply: ESTABLISHED
108    Established(Established),
109
110    /// The process of closing down a connection starting from when the first
111    /// FIN is seen and until FINs from both peers have been ACKed.
112    ///
113    /// Expected peer states are any of:
114    /// - FIN_WAIT_1
115    /// - FIN_WAIT_2
116    /// - CLOSING
117    /// - CLOSE_WAIT
118    /// - LAST_ACK
119    Closing(Closing),
120}
121
122impl State {
123    fn new(segment: &SegmentHeader, payload_len: usize) -> Option<Self> {
124        // We explicitly don't want to track any connections that we haven't
125        // seen from the beginning because:
126        //
127        // a) This shouldn't happen, since we run from boot
128        // b) Window scale is only negotiated during the initial handshake.
129        match segment.control {
130            Some(Control::SYN) => {}
131            None | Some(Control::FIN) | Some(Control::RST) => return None,
132        }
133
134        Some(
135            SynSent {
136                iss: segment.seq,
137                logical_len: segment.len(payload_len),
138                advertised_window_scale: segment.options.window_scale(),
139                // This unwrap cannot fail because WindowSize::MAX is 2^30-1,
140                // which is larger than the largest possible unscaled window
141                // size (2^16).
142                window_size: WindowSize::from_u32(u16::from(segment.wnd).into()).unwrap(),
143            }
144            .into(),
145        )
146    }
147
148    fn expiry_duration(&self, establishment_lifecycle: EstablishmentLifecycle) -> Duration {
149        const MAXIMUM_SEGMENT_LIFETIME: Duration = Duration::from_secs(120);
150
151        // These are all picked to optimize purging connections from the table
152        // as soon as is reasonable. Unlike Linux, we are choosing to be more
153        // conservative with our timeouts and setting the most aggressive one to
154        // the standard MSL of 120 seconds.
155        match self {
156            State::Untracked(_) => {
157                match establishment_lifecycle {
158                    // This is small because it's just meant to be the time for
159                    // the initial handshake.
160                    EstablishmentLifecycle::SeenOriginal | EstablishmentLifecycle::SeenReply => {
161                        MAXIMUM_SEGMENT_LIFETIME
162                    }
163                    EstablishmentLifecycle::Established => Duration::from_secs(6 * 60 * 60),
164                }
165            }
166            State::Closed(_) => Duration::ZERO,
167            State::SynSent(_) => MAXIMUM_SEGMENT_LIFETIME,
168            State::WaitingOnOpeningAck(_) => MAXIMUM_SEGMENT_LIFETIME,
169            State::Established(Established { original, reply }) => {
170                // If there is no data outstanding, make the timeout large, and
171                // otherwise small so we can purge the connection quickly if one
172                // of the endpoints disappears.
173                if original.unacked_data || reply.unacked_data {
174                    MAXIMUM_SEGMENT_LIFETIME
175                } else {
176                    Duration::from_secs(5 * 60 * 60 * 24)
177                }
178            }
179            State::Closing(_) => MAXIMUM_SEGMENT_LIFETIME,
180        }
181    }
182
183    /// Returns a new state that unconditionally replaces the previous one. The
184    /// boolean represents whether the segment was valid or not.
185    ///
186    /// In the case where the segment was invalid, the returned state will be
187    /// equivalent to the one that `update` was called on.
188    fn update(
189        self,
190        segment: &SegmentHeader,
191        payload_len: usize,
192        dir: ConnectionDirection,
193    ) -> (State, bool) {
194        match self {
195            State::Untracked(s) => s.update(segment, payload_len, dir),
196            State::Closed(s) => s.update(segment, payload_len, dir),
197            State::SynSent(s) => s.update(segment, payload_len, dir),
198            State::WaitingOnOpeningAck(s) => s.update(segment, payload_len, dir),
199            State::Established(s) => s.update(segment, payload_len, dir),
200            State::Closing(s) => s.update(segment, payload_len, dir),
201        }
202    }
203}
204
205macro_rules! state_from_state_struct {
206    ($struct:ident) => {
207        impl From<$struct> for State {
208            fn from(value: $struct) -> Self {
209                Self::$struct(value)
210            }
211        }
212    };
213}
214
215/// Contains all of the information required for a single peer in an established
216/// TCP connection.
217///
218/// Packets are valid with the following equations (taken from ["Real Stateful
219/// TCP Packet Filtering in IP Filter"][paper] and updated to allow for segments
220/// intersecting the valid ranges, rather than needing to be entirely contained
221/// within them).
222///
223/// Definitions:
224/// - s: The sequence number of the first octet of the segment
225/// - n: The (virtual) length of the segment in octets
226/// - a: The ACK number of the segment
227///
228/// I:   Data upper bound: s   <= receiver.max_wnd_seq
229/// II:  Data lower bound: s+n >= sender.max_next_seq - receiver.max_wnd
230/// III: ACK  upper bound: a   <= receiver.max_next_seq
231/// IV:  ACK  lower bound: a   >= receiver.max_next_seq - MAXACKWINDOW
232///
233/// MAXACKWINDOW is defined in the paper to be 66000, which is larger than
234/// the largest possible window (without scaling). We scale by
235/// sender.window_scale to ensure this property remains true.
236///
237/// [paper]: https://www.usenix.org/legacy/events/sec01/invitedtalks/rooij.pdf
238#[derive(Debug, Clone, PartialEq, Eq)]
239struct Peer {
240    /// How much to scale window updates from this peer.
241    window_scale: WindowScale,
242
243    /// The maximum window size ever sent by this peer.
244    ///
245    /// On every packet sent by this peer, the larger of itself and the
246    /// (scaled) window from the packet is taken.
247    max_wnd: WindowSize,
248
249    /// The maximum sequence number that is in the window for this peer.
250    ///
251    /// On every packet sent by this peer, this is updated to be the larger of
252    /// itself or the current advertised window (scaled) plus the ACK number in
253    /// the packet.
254    max_wnd_seq: SeqNum,
255
256    /// The largest "next octet" ever sent by this peer. This is equivalent to
257    /// one more than the largest sequence number ever sent by this peer.
258    ///
259    /// On every packet sent by this peer, this is updated to be the larger of
260    /// itself or the sequence number plus the length of the packet.
261    max_next_seq: SeqNum,
262
263    /// Has this peer sent data that has yet to be ACKed?
264    ///
265    /// Set when max_next_seq is increased.
266    ///
267    /// Unset when a reply segment is seen that has an ACK number equal to
268    /// `max_next_seq` (larger would mean an invalid packet).
269    unacked_data: bool,
270
271    /// The state of the first FIN segment sent by this peer.
272    fin_state: FinState,
273}
274
275impl Peer {
276    /// Checks that an ACK segment is within the windows defined in the comment on [`Peer`].
277    fn ack_segment_valid(
278        sender: &Self,
279        receiver: &Self,
280        seq: SeqNum,
281        len: u32,
282        ack: SeqNum,
283    ) -> bool {
284        // All checks below are for the negation of the equation referenced in
285        // the associated comment.
286
287        // I: Segment sequence numbers upper bound.
288        if seq.after(receiver.max_wnd_seq) {
289            return false;
290        }
291
292        // II: Segment sequence numbers lower bound.
293        if (seq + len).before(sender.max_next_seq - receiver.max_wnd) {
294            return false;
295        }
296
297        // III: ACK upper bound.
298        if ack.after(receiver.max_next_seq) {
299            return false;
300        }
301
302        // IV: ACK lower bound.
303        if ack.before(receiver.max_next_seq - receiver.max_ack_window()) {
304            return false;
305        }
306
307        true
308    }
309
310    /// Returns a new `Peer` updated using the provided information from a
311    /// segment which it has sent.
312    fn update_sender(
313        self,
314        seq: SeqNum,
315        len: u32,
316        ack: SeqNum,
317        wnd: UnscaledWindowSize,
318        fin_seen: bool,
319    ) -> Self {
320        let Self { window_scale, max_wnd, max_wnd_seq, max_next_seq, unacked_data, fin_state } =
321            self;
322
323        // The minimum window size is assumed to be 1. From the paper:
324        //   On BSD systems, a window probing is always done with a packet
325        //   containing one octet of data.
326        let window_size = {
327            let window_size = wnd << window_scale;
328            // The unwrap below won't fail because 1 is less than
329            // WindowSize::MAX.
330            core::cmp::max(window_size, WindowSize::from_u32(1).unwrap())
331        };
332
333        // The largest sequence number allowed by the current window.
334        let wnd_seq = ack + window_size;
335        // The octet one past the last one in the segment.
336        let end = seq + len;
337        // The largest `end` value sent by this peer.
338        let sender_max_next_seq = if max_next_seq.before(end) { end } else { max_next_seq };
339
340        Peer {
341            window_scale,
342            max_wnd: core::cmp::max(max_wnd, window_size),
343            max_wnd_seq: if max_wnd_seq.before(wnd_seq) { wnd_seq } else { max_wnd_seq },
344            max_next_seq: sender_max_next_seq,
345            unacked_data: if sender_max_next_seq.after(max_next_seq) { true } else { unacked_data },
346            fin_state: if fin_seen { fin_state.update_fin_sent(end - 1) } else { fin_state },
347        }
348    }
349
350    /// Returns a new `Peer` updated using the provided information from a
351    /// segment which it received.
352    fn update_receiver(self, ack: SeqNum) -> Self {
353        let Self { window_scale, max_wnd, max_wnd_seq, max_next_seq, unacked_data, fin_state } =
354            self;
355
356        Peer {
357            window_scale,
358            max_wnd,
359            max_wnd_seq,
360            max_next_seq,
361            // It's not possible for ack to be > self.max_next_seq due to
362            // equation III, which is checked on every segment.
363            unacked_data: if ack == max_next_seq { false } else { unacked_data },
364            fin_state: fin_state.update_ack_received(ack),
365        }
366    }
367
368    fn max_ack_window(&self) -> u32 {
369        // The paper gives 66000 as the MAXACKWINDOW constant because it's a
370        // little larger than the largest possible TCP window. With winow
371        // scaling in effect, this constant is no longer valid, so we scale it
372        // up by that scaling factor.
373        //
374        // This shift is guaranteed to never overflow because the maximum value
375        // for self.window_scale is 14 and 66000 << 14 < u32::MAX.
376        66000u32 << (self.window_scale.get() as u32)
377    }
378}
379
380/// Tracks the state of the FIN process for a peer.
381#[derive(Debug, Clone, PartialEq, Eq)]
382enum FinState {
383    /// This peer has not sent a FIN yet.
384    NotSent,
385
386    /// This peer has sent a FIN with the provided sequence number.
387    ///
388    /// Updated to ensure it is the sequence number of the first FIN sent.
389    Sent(SeqNum),
390
391    /// The FIN sent by this peer has been ACKed.
392    Acked,
393}
394
395impl FinState {
396    /// To be called when the peer has sent a FIN segment with the sequence
397    /// number of the FIN.
398    ///
399    /// Returns an updated `FinState`.
400    fn update_fin_sent(self, seq: SeqNum) -> Self {
401        match self {
402            FinState::NotSent => FinState::Sent(seq),
403            FinState::Sent(s) => {
404                // NOTE: We want to track the first FIN in the sequence
405                // space, not the first one we saw.
406                if s.before(seq) {
407                    FinState::Sent(s)
408                } else {
409                    FinState::Sent(seq)
410                }
411            }
412            FinState::Acked => FinState::Acked,
413        }
414    }
415
416    /// To be called when the peer has received an ACK.
417    ///
418    /// Returns an updated `FinState`.
419    fn update_ack_received(self, ack: SeqNum) -> Self {
420        match self {
421            FinState::NotSent => FinState::NotSent,
422            FinState::Sent(seq) => {
423                if ack.after(seq) {
424                    FinState::Acked
425                } else {
426                    FinState::Sent(seq)
427                }
428            }
429            FinState::Acked => FinState::Acked,
430        }
431    }
432
433    /// Has this FIN been acked?
434    fn acked(&self) -> bool {
435        match self {
436            FinState::NotSent => false,
437            FinState::Sent(_) => false,
438            FinState::Acked => true,
439        }
440    }
441}
442
443/// The return value from [`do_established_update`] indicating further action.
444#[derive(Debug, PartialEq, Eq)]
445enum EstablishedUpdateResult {
446    /// The update was successful.
447    ///
448    /// `new_original` and `new_reply` are the updated versions of the original
449    /// and reply peers that were provided to the function.
450    Success { new_original: Peer, new_reply: Peer, fin_seen: bool },
451
452    /// A valid RST was seen.
453    Reset,
454
455    /// The segment was invalid.
456    ///
457    /// Includes the non-updated peers so the state can be reset.
458    Invalid { original: Peer, reply: Peer },
459}
460
461fn swap_peers(original: Peer, reply: Peer, dir: ConnectionDirection) -> (Peer, Peer) {
462    match dir {
463        ConnectionDirection::Original => (original, reply),
464        ConnectionDirection::Reply => (reply, original),
465    }
466}
467
468/// Holds and names the peers passed into [`do_established_update`] to avoid
469/// ambiguous argument order.
470struct UpdatePeers {
471    original: Peer,
472    reply: Peer,
473}
474
475/// The core functionality for handling segments once the handshake is complete.
476///
477/// Validates that segments fall within the bounds described in the comment on
478/// [`Peer`].
479fn do_established_update(
480    UpdatePeers { original, reply }: UpdatePeers,
481    segment: &SegmentHeader,
482    payload_len: usize,
483    dir: ConnectionDirection,
484) -> EstablishedUpdateResult {
485    let logical_len = segment.len(payload_len);
486    let SegmentHeader { seq, ack, wnd, control, options: _, push: _ } = segment;
487
488    let (sender, receiver) = swap_peers(original, reply, dir);
489
490    // From RFC 9293:
491    //   If the ACK control bit is set, this field contains the value of the
492    //   next sequence number the sender of the segment is expecting to receive.
493    //   Once a connection is established, this is always sent.
494    let ack = match ack {
495        Some(ack) => ack,
496        None => {
497            let (original, reply) = swap_peers(sender, receiver, dir);
498            return EstablishedUpdateResult::Invalid { original, reply };
499        }
500    };
501
502    if !Peer::ack_segment_valid(&sender, &receiver, *seq, logical_len, *ack) {
503        let (original, reply) = swap_peers(sender, receiver, dir);
504        return EstablishedUpdateResult::Invalid { original, reply };
505    }
506
507    let fin_seen = match control {
508        Some(Control::SYN) => {
509            let (original, reply) = swap_peers(sender, receiver, dir);
510            return EstablishedUpdateResult::Invalid { original, reply };
511        }
512        Some(Control::RST) => return EstablishedUpdateResult::Reset,
513        Some(Control::FIN) => true,
514        None => false,
515    };
516
517    let new_sender = sender.update_sender(*seq, logical_len, *ack, *wnd, fin_seen);
518    let new_receiver = receiver.update_receiver(*ack);
519
520    let (new_original, new_reply) = swap_peers(new_sender, new_receiver, dir);
521    EstablishedUpdateResult::Success { new_original, new_reply, fin_seen }
522}
523
524/// State for the Untracked state.
525///
526/// This state never transitions to another state.
527#[derive(Debug, Clone, PartialEq, Eq)]
528pub(crate) struct Untracked {}
529state_from_state_struct!(Untracked);
530
531impl Untracked {
532    fn update(
533        self,
534        _segment: &SegmentHeader,
535        _payload_len: usize,
536        _dir: ConnectionDirection,
537    ) -> (State, bool) {
538        (Self {}.into(), true)
539    }
540}
541
542/// State for the Closed state.
543///
544/// This state never transitions to another state.
545#[derive(Debug, Clone, PartialEq, Eq)]
546pub(crate) struct Closed {}
547state_from_state_struct!(Closed);
548
549impl Closed {
550    fn update(
551        self,
552        _segment: &SegmentHeader,
553        _payload_len: usize,
554        _dir: ConnectionDirection,
555    ) -> (State, bool) {
556        (self.into(), true)
557    }
558}
559
560/// State for the SynSent state.
561///
562/// State transitions for in-range segments by direction:
563/// - Original
564///   - SYN: Update data, stay in SynSent
565///   - SYN/ACK: Invalid
566///   - RST: Invalid
567///   - FIN: Invalid
568///   - ACK: Invalid
569/// - Reply
570///   - SYN: Untracked, until we support simultaneous open.
571///   - SYN/ACK: WaitingOnOpeningAck
572///   - RST: Delete connection
573///   - FIN: Invalid
574///   - ACK: Invalid
575#[derive(Debug, Clone, PartialEq, Eq)]
576pub(crate) struct SynSent {
577    /// The ISS (initial send sequence number) for the original TCP stack.
578    iss: SeqNum,
579
580    /// The logical length of the segment sent by the original TCP stack.
581    logical_len: u32,
582
583    /// The window scale (if set in the initial SYN) for the original TCP stack.
584    advertised_window_scale: Option<WindowScale>,
585
586    /// The window size of the original TCP stack. Will be converted into a
587    /// sequence number once we know what the reply stack's ISN is.
588    ///
589    /// RFC 1323 2.2:
590    ///   The Window field in a SYN (i.e., a <SYN> or <SYN,ACK>) segment itself
591    ///   is never scaled.
592    window_size: WindowSize,
593}
594state_from_state_struct!(SynSent);
595
596impl SynSent {
597    fn update(
598        self,
599        segment: &SegmentHeader,
600        payload_len: usize,
601        dir: ConnectionDirection,
602    ) -> (State, bool) {
603        let Self { iss, logical_len, advertised_window_scale, window_size } = self;
604
605        match dir {
606            // This is another packet in the same direction as the first one.
607            // Update existing parameters for initial SYN, but only for packets
608            // that look to be valid retransmits of the initial SYN. This
609            // behavior is copied over from gVisor.
610            ConnectionDirection::Original => {
611                if let Some(_) = segment.ack {
612                    return (self.into(), false);
613                }
614
615                match segment.control {
616                    None | Some(Control::FIN) | Some(Control::RST) => {
617                        return (self.into(), false);
618                    }
619                    Some(Control::SYN) => {}
620                };
621
622                if segment.seq != iss || segment.options.window_scale() != advertised_window_scale {
623                    return (self.into(), false);
624                }
625
626                // If it's a valid retransmit of the original SYN, update
627                // any state that changed and let it through.
628                let seg_window_size = WindowSize::from_u32(u16::from(segment.wnd).into()).unwrap();
629
630                (
631                    SynSent {
632                        iss: iss,
633                        logical_len: u32::max(segment.len(payload_len), logical_len),
634                        advertised_window_scale: advertised_window_scale,
635                        window_size: core::cmp::max(seg_window_size, window_size),
636                    }
637                    .into(),
638                    true,
639                )
640            }
641
642            ConnectionDirection::Reply => {
643                // RFC 9293 3.10.7.3:
644                //   If SND.UNA < SEG.ACK =< SND.NXT, then the ACK is
645                //   acceptable.
646                match segment.ack {
647                    None => {}
648                    Some(ack) => {
649                        if !(ack.after(iss) && ack.before(iss + logical_len + 1)) {
650                            return (self.into(), false);
651                        }
652                    }
653                };
654
655                match segment.control {
656                    None | Some(Control::FIN) => (self.into(), false),
657                    // RFC 9293 3.10.7.3:
658                    //   If the RST bit is set,
659                    //   If the ACK was acceptable, then signal to the user
660                    //   "error: connection reset", drop the segment, enter
661                    //   CLOSED state, delete TCB, and return. Otherwise (no
662                    //   ACK), drop the segment and return.
663                    //
664                    // For our purposes, we delete the connection because we
665                    // know the receiver will tear down the connection.
666                    Some(Control::RST) => match segment.ack {
667                        None => (self.into(), false),
668                        Some(_) => (Closed {}.into(), true),
669                    },
670
671                    Some(Control::SYN) => {
672                        let Some(ack) = segment.ack else {
673                            // TODO(https://fxbug.dev/355200767): Support
674                            // simultaneous open.
675                            log::warn!(
676                                "Unsupported TCP simultaneous open. Giving up on detailed tracking"
677                            );
678
679                            return (Untracked {}.into(), true);
680                        };
681
682                        let reply_window_scale = segment.options.window_scale();
683                        let reply_window_size =
684                            WindowSize::from_u32(u16::from(segment.wnd).into()).unwrap();
685
686                        // RFC 1323 2.2:
687                        //   This option is an offer, not a promise; both sides
688                        //   must send Window Scale options in their SYN
689                        //   segments to enable window scaling in either
690                        //   direction.
691                        let (original_window_scale, reply_window_scale) =
692                            match (advertised_window_scale, reply_window_scale) {
693                                (Some(original), Some(reply)) => (original, reply),
694                                _ => (WindowScale::ZERO, WindowScale::ZERO),
695                            };
696
697                        let original_max_next_seq = iss + logical_len;
698
699                        (
700                            WaitingOnOpeningAck {
701                                original: Peer {
702                                    window_scale: original_window_scale,
703                                    max_wnd: window_size,
704                                    // We're still waiting on an ACK from
705                                    // the original stack, so this is
706                                    // slightly different from the normal
707                                    // calculation. It's still valid because
708                                    // we can assume that the implicit ACK
709                                    // number is the reply ISS (no data
710                                    // ACKed).
711                                    max_wnd_seq: segment.seq + window_size,
712                                    max_next_seq: original_max_next_seq,
713                                    unacked_data: ack.before(original_max_next_seq),
714                                    fin_state: FinState::NotSent,
715                                },
716                                reply: Peer {
717                                    window_scale: reply_window_scale,
718                                    max_wnd: reply_window_size,
719                                    max_wnd_seq: ack + reply_window_size,
720                                    max_next_seq: segment.seq + segment.len(payload_len),
721                                    // The reply peer will always have
722                                    // unacked data here because the SYN we
723                                    // just saw sent needs to be acked.
724                                    unacked_data: true,
725                                    fin_state: FinState::NotSent,
726                                },
727                            }
728                            .into(),
729                            true,
730                        )
731                    }
732                }
733            }
734        }
735    }
736}
737
738/// State for the WaitingOnOpeningAck state.
739///
740/// Note this expects the ACK to come from the original direction.
741///
742/// State transitions for in-range segments by direction:
743/// - Original
744///   - SYN: Invalid
745///   - RST: Delete connection
746///   - FIN: Closing
747///   - ACK: Established
748/// - Reply
749///   - SYN: Invalid
750///   - RST: Delete connection
751///   - FIN: Closing
752///   - ACK: WaitingOnOpeningAck
753#[derive(Debug, Clone, PartialEq, Eq)]
754pub(crate) struct WaitingOnOpeningAck {
755    /// State for the "original" TCP stack (the one that we first saw a packet
756    /// for).
757    original: Peer,
758
759    /// State for the "reply" TCP stack.
760    reply: Peer,
761}
762state_from_state_struct!(WaitingOnOpeningAck);
763
764impl WaitingOnOpeningAck {
765    fn update(
766        self,
767        segment: &SegmentHeader,
768        payload_len: usize,
769        dir: ConnectionDirection,
770    ) -> (State, bool) {
771        let Self { original, reply } = self;
772
773        let (original, reply, fin_seen) = match do_established_update(
774            UpdatePeers { original, reply },
775            segment,
776            payload_len,
777            dir.clone(),
778        ) {
779            EstablishedUpdateResult::Success { new_original, new_reply, fin_seen } => {
780                (new_original, new_reply, fin_seen)
781            }
782            EstablishedUpdateResult::Invalid { original, reply } => {
783                return (Self { original, reply }.into(), false)
784            }
785            EstablishedUpdateResult::Reset => return (Closed {}.into(), true),
786        };
787
788        let new_state = if fin_seen {
789            Closing { original, reply }.into()
790        } else {
791            match dir {
792                // We move to Established because we know that if the ACK was
793                // valid (checked by do_established_update), the ACK must
794                // include the SYN, which is the first possible octet.
795                ConnectionDirection::Original => Established { original, reply }.into(),
796                ConnectionDirection::Reply => WaitingOnOpeningAck { original, reply }.into(),
797            }
798        };
799
800        (new_state, true)
801    }
802}
803
804/// State for the Established state.
805///
806/// State transitions for in-range segments, regardless of direction:
807/// - SYN: Invalid
808/// - RST: Delete connection
809/// - FIN: Closing
810/// - ACK: Established
811#[derive(Debug, Clone, PartialEq, Eq)]
812pub(crate) struct Established {
813    original: Peer,
814    reply: Peer,
815}
816state_from_state_struct!(Established);
817
818impl Established {
819    fn update(
820        self,
821        segment: &SegmentHeader,
822        payload_len: usize,
823        dir: ConnectionDirection,
824    ) -> (State, bool) {
825        let Self { original, reply } = self;
826
827        let (original, reply, fin_seen) = match do_established_update(
828            UpdatePeers { original, reply },
829            segment,
830            payload_len,
831            dir.clone(),
832        ) {
833            EstablishedUpdateResult::Success { new_original, new_reply, fin_seen } => {
834                (new_original, new_reply, fin_seen)
835            }
836            EstablishedUpdateResult::Invalid { original, reply } => {
837                return (Self { original, reply }.into(), false)
838            }
839            EstablishedUpdateResult::Reset => return (Closed {}.into(), true),
840        };
841
842        let new_state = if fin_seen {
843            Closing { original, reply }.into()
844        } else {
845            Established { original, reply }.into()
846        };
847
848        (new_state, true)
849    }
850}
851
852/// State for the Closing state.
853///
854/// State transitions for in-range segments regardless of direction:
855/// - SYN: Invalid
856/// - RST: Delete connection
857/// - FIN: Closing
858/// - ACK: Closing
859///
860/// The Closing state deletes the connection once FINs from both peers have been
861/// ACKed.
862#[derive(Debug, Clone, PartialEq, Eq)]
863pub(crate) struct Closing {
864    original: Peer,
865    reply: Peer,
866}
867state_from_state_struct!(Closing);
868
869impl Closing {
870    fn update(
871        self,
872        segment: &SegmentHeader,
873        payload_len: usize,
874        dir: ConnectionDirection,
875    ) -> (State, bool) {
876        let Self { original, reply } = self;
877
878        // NOTE: Segments after a FIN are somewhat invalid, but we do not
879        // attempt to handle them specially. Per RFC 9293 3.10.7.4:
880        //
881        //   Seventh, process the segment text. [After FIN,] this should not
882        //   occur since a FIN has been received from the remote side. Ignore
883        //   the segment text.
884        //
885        // Because these segments aren't completely invalid, handling them
886        // properly (and consistently with the endpoints) is difficult. It is
887        // not needed for correctness, since the connection will be torn down as
888        // soon as there's an ACK for both FINs anyway. This extra invalid data
889        // does not change that.
890        //
891        // Neither Linux nor gVisor do anything special for these segments.
892
893        let (original, reply) = match do_established_update(
894            UpdatePeers { original, reply },
895            segment,
896            payload_len,
897            dir.clone(),
898        ) {
899            EstablishedUpdateResult::Success { new_original, new_reply, fin_seen: _ } => {
900                (new_original, new_reply)
901            }
902            EstablishedUpdateResult::Invalid { original, reply } => {
903                return (Self { original, reply }.into(), false)
904            }
905            EstablishedUpdateResult::Reset => return (Closed {}.into(), true),
906        };
907
908        if original.fin_state.acked() && reply.fin_state.acked() {
909            // Removing the entry immediately is not expected to break any
910            // use-cases. The endpoints are ultimately responsible for
911            // respecting the TIME_WAIT state.
912            //
913            // The NAT entry will be removed as a consequence, but this is only
914            // a problem if a server wanted to reopen the connection with the
915            // client (but only during TIME_WAIT).
916            //
917            // TODO(https://fxbug.dev/355200767): Add TimeWait and reopening
918            // connections once simultaneous open is supported.
919            (Closed {}.into(), true)
920        } else {
921            (Closing { original, reply }.into(), true)
922        }
923    }
924}
925
926#[cfg(test)]
927mod tests {
928    use super::{
929        do_established_update, Closed, Closing, Established, EstablishedUpdateResult, FinState,
930        Peer, State, SynSent, Untracked, UpdatePeers, WaitingOnOpeningAck,
931    };
932
933    use assert_matches::assert_matches;
934    use netstack3_base::{
935        Control, HandshakeOptions, SegmentHeader, SeqNum, UnscaledWindowSize, WindowScale,
936        WindowSize,
937    };
938    use test_case::test_case;
939
940    use crate::conntrack::ConnectionDirection;
941
942    const ORIGINAL_ISS: SeqNum = SeqNum::new(0);
943    const REPLY_ISS: SeqNum = SeqNum::new(8192);
944    const ORIGINAL_WND: u16 = 16;
945    const REPLY_WND: u16 = 17;
946    const ORIGINAL_WS: u8 = 3;
947    const REPLY_WS: u8 = 4;
948    const ORIGINAL_PAYLOAD_LEN: usize = 12;
949    const REPLY_PAYLOAD_LEN: usize = 13;
950
951    impl Peer {
952        pub fn arbitrary() -> Peer {
953            Peer {
954                max_next_seq: SeqNum::new(0),
955                window_scale: WindowScale::new(0).unwrap(),
956                max_wnd_seq: SeqNum::new(0),
957                unacked_data: false,
958                max_wnd: WindowSize::new(0).unwrap(),
959                fin_state: FinState::NotSent,
960            }
961        }
962    }
963
964    #[test_case(None)]
965    #[test_case(Some(Control::FIN))]
966    #[test_case(Some(Control::RST))]
967    fn syn_sent_original_non_syn_segment(control: Option<Control>) {
968        let state = SynSent {
969            iss: ORIGINAL_ISS,
970            logical_len: 3,
971            advertised_window_scale: None,
972            window_size: WindowSize::from_u32(ORIGINAL_WND as u32).unwrap(),
973        };
974
975        let segment = SegmentHeader {
976            seq: ORIGINAL_ISS,
977            wnd: UnscaledWindowSize::from(ORIGINAL_WND),
978            control,
979            ..Default::default()
980        };
981
982        let expected_state = state.clone().into();
983        assert_eq!(
984            state.update(&segment, ORIGINAL_PAYLOAD_LEN, ConnectionDirection::Original),
985            (expected_state, false)
986        );
987    }
988
989    #[test_case(SegmentHeader {
990        // Different from existing.
991        seq: ORIGINAL_ISS + 1,
992        wnd: UnscaledWindowSize::from(ORIGINAL_WND),
993        control: Some(Control::SYN),
994        options: HandshakeOptions {
995            // Same as existing.
996            window_scale: WindowScale::new(ORIGINAL_WS),
997            ..Default::default()
998        }.into(),
999        ..Default::default()
1000    }; "different ISS")]
1001    #[test_case(SegmentHeader {
1002        // Same as existing.
1003        seq: ORIGINAL_ISS,
1004        wnd: UnscaledWindowSize::from(ORIGINAL_WND),
1005        control: Some(Control::SYN),
1006        options: HandshakeOptions {
1007            // Different from existing.
1008            window_scale: WindowScale::new(ORIGINAL_WS + 1),
1009            ..Default::default()
1010        }.into(),
1011        ..Default::default()
1012    }; "different window scale")]
1013    #[test_case(SegmentHeader {
1014        seq: ORIGINAL_ISS,
1015        // ACK here is invalid.
1016        ack: Some(SeqNum::new(10)),
1017        wnd: UnscaledWindowSize::from(ORIGINAL_WND),
1018        control: Some(Control::SYN),
1019        options: HandshakeOptions {
1020            window_scale: WindowScale::new(2),
1021            ..Default::default()
1022        }.into(),
1023        ..Default::default()
1024    }; "ack not allowed")]
1025    fn syn_sent_original_syn_not_retransmit(segment: SegmentHeader) {
1026        let state = SynSent {
1027            iss: ORIGINAL_ISS,
1028            logical_len: ORIGINAL_PAYLOAD_LEN as u32 + 1,
1029            advertised_window_scale: WindowScale::new(ORIGINAL_WS),
1030            window_size: WindowSize::from_u32(ORIGINAL_WND as u32).unwrap(),
1031        };
1032
1033        let expected_state = state.clone().into();
1034        assert_eq!(
1035            state.update(&segment, ORIGINAL_PAYLOAD_LEN, ConnectionDirection::Original),
1036            (expected_state, false)
1037        );
1038    }
1039
1040    #[test]
1041    fn syn_sent_original_syn_retransmit() {
1042        let state = SynSent {
1043            iss: ORIGINAL_ISS,
1044            logical_len: ORIGINAL_PAYLOAD_LEN as u32 + 1,
1045            advertised_window_scale: WindowScale::new(ORIGINAL_WS),
1046            window_size: WindowSize::from_u32(ORIGINAL_WND as u32).unwrap(),
1047        };
1048
1049        let segment = SegmentHeader {
1050            seq: ORIGINAL_ISS,
1051            wnd: UnscaledWindowSize::from(ORIGINAL_WND + 10),
1052            control: Some(Control::SYN),
1053            options: HandshakeOptions {
1054                window_scale: WindowScale::new(ORIGINAL_WS),
1055                ..Default::default()
1056            }
1057            .into(),
1058            ..Default::default()
1059        };
1060
1061        let result = assert_matches!(
1062            state.update(
1063                &segment,
1064                ORIGINAL_PAYLOAD_LEN + 10,
1065                ConnectionDirection::Original
1066            ),
1067            (State::SynSent(s), true) => s
1068        );
1069
1070        assert_eq!(
1071            result,
1072            SynSent {
1073                iss: ORIGINAL_ISS,
1074                logical_len: ORIGINAL_PAYLOAD_LEN as u32 + 10 + 1,
1075                advertised_window_scale: WindowScale::new(ORIGINAL_WS),
1076                window_size: WindowSize::from_u32(ORIGINAL_WND as u32 + 10).unwrap(),
1077            }
1078        )
1079    }
1080
1081    #[test_case(None)]
1082    #[test_case(Some(Control::FIN))]
1083    fn syn_sent_reply_non_syn_segment(control: Option<Control>) {
1084        let state = SynSent {
1085            iss: ORIGINAL_ISS,
1086            logical_len: ORIGINAL_PAYLOAD_LEN as u32 + 1,
1087            advertised_window_scale: None,
1088            window_size: WindowSize::from_u32(ORIGINAL_WND as u32).unwrap(),
1089        };
1090
1091        let segment = SegmentHeader {
1092            seq: ORIGINAL_ISS,
1093            wnd: UnscaledWindowSize::from(ORIGINAL_WND),
1094            control,
1095            ..Default::default()
1096        };
1097
1098        let expected_state = state.clone().into();
1099        assert_eq!(
1100            state.update(&segment, REPLY_PAYLOAD_LEN, ConnectionDirection::Reply),
1101            (expected_state, false)
1102        );
1103    }
1104
1105    #[test_case(ORIGINAL_ISS, None; "small invalid")]
1106    #[test_case(
1107        ORIGINAL_ISS + 1, Some(Closed {}.into());
1108        "smallest valid"
1109    )]
1110    #[test_case(
1111        ORIGINAL_ISS + ORIGINAL_PAYLOAD_LEN as u32 + 1,
1112        Some(Closed {}.into());
1113        "largest valid"
1114    )]
1115    #[test_case(
1116        ORIGINAL_ISS + ORIGINAL_PAYLOAD_LEN as u32 + 2,
1117        None;
1118        "large invalid"
1119    )]
1120    fn syn_sent_reply_rst_segment(ack: SeqNum, new_state: Option<State>) {
1121        let state = SynSent {
1122            iss: ORIGINAL_ISS,
1123            logical_len: ORIGINAL_PAYLOAD_LEN as u32 + 1,
1124            advertised_window_scale: None,
1125            window_size: WindowSize::from_u32(ORIGINAL_WND as u32).unwrap(),
1126        };
1127
1128        let segment = SegmentHeader {
1129            seq: ORIGINAL_ISS,
1130            ack: Some(ack),
1131            wnd: UnscaledWindowSize::from(ORIGINAL_WND),
1132            control: Some(Control::RST),
1133            ..Default::default()
1134        };
1135
1136        let (expected_state, valid) = match new_state {
1137            Some(state) => (state, true),
1138            None => (state.clone().into(), false),
1139        };
1140
1141        assert_eq!(
1142            state.update(&segment, /*payload_len*/ 0, ConnectionDirection::Reply),
1143            (expected_state, valid)
1144        );
1145    }
1146
1147    #[test]
1148    fn syn_sent_reply_simultaneous_open() {
1149        let state = SynSent {
1150            iss: ORIGINAL_ISS,
1151            logical_len: ORIGINAL_PAYLOAD_LEN as u32 + 1,
1152            advertised_window_scale: WindowScale::new(ORIGINAL_WS),
1153            window_size: WindowSize::from_u32(ORIGINAL_WND as u32).unwrap(),
1154        };
1155
1156        let segment = SegmentHeader {
1157            seq: ORIGINAL_ISS,
1158            wnd: UnscaledWindowSize::from(ORIGINAL_WND + 10),
1159            control: Some(Control::SYN),
1160            ..Default::default()
1161        };
1162
1163        assert_eq!(
1164            state.update(&segment, /*payload_len*/ 0, ConnectionDirection::Reply),
1165            (Untracked {}.into(), true)
1166        );
1167    }
1168
1169    #[test_case(ORIGINAL_ISS; "too low")]
1170    #[test_case(ORIGINAL_ISS + ORIGINAL_PAYLOAD_LEN + 2; "too high")]
1171    fn syn_sent_reply_syn_ack_not_in_range(ack: SeqNum) {
1172        let state = SynSent {
1173            iss: ORIGINAL_ISS,
1174            logical_len: ORIGINAL_PAYLOAD_LEN as u32 + 1,
1175            advertised_window_scale: None,
1176            window_size: WindowSize::from_u32(ORIGINAL_WND as u32).unwrap(),
1177        };
1178
1179        let segment = SegmentHeader {
1180            seq: REPLY_ISS,
1181            ack: Some(ack),
1182            wnd: UnscaledWindowSize::from(REPLY_WND),
1183            control: Some(Control::SYN),
1184            ..Default::default()
1185        };
1186
1187        let expected_state = state.clone().into();
1188        assert_eq!(
1189            state.update(&segment, REPLY_PAYLOAD_LEN, ConnectionDirection::Reply),
1190            (expected_state, false)
1191        );
1192    }
1193
1194    #[test_case(None)]
1195    #[test_case(Some(WindowScale::new(REPLY_WS).unwrap()))]
1196    fn syn_sent_reply_syn_ack(reply_window_scale: Option<WindowScale>) {
1197        let state = SynSent {
1198            iss: ORIGINAL_ISS,
1199            logical_len: ORIGINAL_PAYLOAD_LEN as u32 + 1,
1200            advertised_window_scale: WindowScale::new(ORIGINAL_WS),
1201            window_size: WindowSize::from_u32(ORIGINAL_WND as u32).unwrap(),
1202        };
1203
1204        let segment = SegmentHeader {
1205            seq: REPLY_ISS,
1206            ack: Some(ORIGINAL_ISS + 1),
1207            wnd: UnscaledWindowSize::from(REPLY_WND),
1208            control: Some(Control::SYN),
1209            options: HandshakeOptions { window_scale: reply_window_scale, ..Default::default() }
1210                .into(),
1211            ..Default::default()
1212        };
1213
1214        let new_state = assert_matches!(
1215            state.update(
1216                &segment,
1217                REPLY_PAYLOAD_LEN,
1218                ConnectionDirection::Reply
1219            ),
1220            (State::WaitingOnOpeningAck(s), true) => s
1221        );
1222
1223        let (original_window_scale, reply_window_scale) = match reply_window_scale {
1224            Some(s) => (WindowScale::new(ORIGINAL_WS).unwrap(), s),
1225            None => (WindowScale::ZERO, WindowScale::ZERO),
1226        };
1227
1228        assert_eq!(
1229            new_state,
1230            WaitingOnOpeningAck {
1231                original: Peer {
1232                    window_scale: original_window_scale,
1233                    max_wnd: WindowSize::from_u32(ORIGINAL_WND as u32).unwrap(),
1234                    max_wnd_seq: REPLY_ISS + ORIGINAL_WND as u32,
1235                    max_next_seq: ORIGINAL_ISS + ORIGINAL_PAYLOAD_LEN + 1,
1236                    unacked_data: true,
1237                    fin_state: FinState::NotSent,
1238                },
1239                reply: Peer {
1240                    window_scale: reply_window_scale,
1241                    max_wnd: WindowSize::from_u32(REPLY_WND as u32).unwrap(),
1242                    max_wnd_seq: ORIGINAL_ISS + 1 + REPLY_WND as u32,
1243                    max_next_seq: REPLY_ISS + REPLY_PAYLOAD_LEN + 1,
1244                    unacked_data: true,
1245                    fin_state: FinState::NotSent,
1246                }
1247            }
1248        );
1249    }
1250
1251    #[test_case(FinState::NotSent, SeqNum::new(9) => FinState::Sent(SeqNum::new(9)))]
1252    #[test_case(FinState::Sent(SeqNum::new(9)), SeqNum::new(8) => FinState::Sent(SeqNum::new(8)))]
1253    #[test_case(FinState::Sent(SeqNum::new(9)), SeqNum::new(9) => FinState::Sent(SeqNum::new(9)))]
1254    #[test_case(FinState::Sent(SeqNum::new(9)), SeqNum::new(10) => FinState::Sent(SeqNum::new(9)))]
1255    #[test_case(FinState::Acked, SeqNum::new(9) => FinState::Acked)]
1256    fn fin_state_update_fin_sent(fin_state: FinState, seq: SeqNum) -> FinState {
1257        fin_state.update_fin_sent(seq)
1258    }
1259
1260    #[test_case(FinState::NotSent, SeqNum::new(10) => FinState::NotSent)]
1261    #[test_case(FinState::Sent(SeqNum::new(9)), SeqNum::new(9) => FinState::Sent(SeqNum::new(9)))]
1262    #[test_case(FinState::Sent(SeqNum::new(9)), SeqNum::new(10) => FinState::Acked)]
1263    #[test_case(FinState::Acked, SeqNum::new(10) => FinState::Acked)]
1264    fn fin_state_update_ack_received(fin_state: FinState, ack: SeqNum) -> FinState {
1265        fin_state.update_ack_received(ack)
1266    }
1267
1268    const RECV_MAX_NEXT_SEQ: SeqNum = SeqNum::new(66_001);
1269    const RECV_MAX_WND_SEQ: SeqNum = SeqNum::new(1424);
1270
1271    #[test_case(SeqNum::new(424), 200, SeqNum::new(1) => true; "success low seq/ack")]
1272    #[test_case(RECV_MAX_WND_SEQ, 0, RECV_MAX_NEXT_SEQ => true; "success high seq/ack")]
1273    #[test_case(RECV_MAX_WND_SEQ + 1, 0, SeqNum::new(1) => false; "bad equation I")]
1274    #[test_case(SeqNum::new(424), 199, SeqNum::new(1) => false; "bad equation II")]
1275    #[test_case(SeqNum::new(424), 200, RECV_MAX_NEXT_SEQ + 1 => false; "bad equation III")]
1276    #[test_case(SeqNum::new(424), 200, SeqNum::new(0) => false; "bad equation IV")]
1277    fn ack_segment_valid_test(seq: SeqNum, len: u32, ack: SeqNum) -> bool {
1278        let sender = Peer { max_next_seq: SeqNum::new(1024), ..Peer::arbitrary() };
1279
1280        // MAXACKWINDOW is going to be 66000 due to window shift of 0.
1281        let receiver = Peer {
1282            window_scale: WindowScale::new(0).unwrap(),
1283            max_wnd: WindowSize::new(400).unwrap(),
1284            max_next_seq: RECV_MAX_NEXT_SEQ,
1285            max_wnd_seq: RECV_MAX_WND_SEQ,
1286            ..Peer::arbitrary()
1287        };
1288
1289        Peer::ack_segment_valid(&sender, &receiver, seq, len, ack)
1290    }
1291
1292    struct PeerUpdateSenderArgs {
1293        seq: SeqNum,
1294        len: u32,
1295        ack: SeqNum,
1296        wnd: UnscaledWindowSize,
1297        fin_seen: bool,
1298    }
1299
1300    #[test_case(
1301        Peer {
1302            window_scale: WindowScale::new(3).unwrap(),
1303            max_wnd: WindowSize::new(16).unwrap(),
1304            max_wnd_seq: SeqNum::new(127),
1305            max_next_seq: SeqNum::new(1024),
1306            unacked_data: false,
1307            fin_state: FinState::NotSent,
1308        },
1309        PeerUpdateSenderArgs {
1310            seq: SeqNum::new(1025),
1311            len: 10,
1312            ack: SeqNum::new(100),
1313            wnd: UnscaledWindowSize::from_u32(4),
1314            fin_seen: false
1315        } => Peer {
1316            window_scale: WindowScale::new(3).unwrap(),
1317            max_wnd: WindowSize::new(32).unwrap(),
1318            max_wnd_seq: SeqNum::new(132),
1319            max_next_seq: SeqNum::new(1035),
1320            unacked_data: true,
1321            fin_state: FinState::NotSent,
1322        }; "packet larger"
1323    )]
1324    #[test_case(
1325        Peer {
1326            window_scale: WindowScale::new(3).unwrap(),
1327            max_wnd: WindowSize::new(16).unwrap(),
1328            max_wnd_seq: SeqNum::new(127),
1329            max_next_seq: SeqNum::new(1024),
1330            unacked_data: false,
1331            fin_state: FinState::NotSent,
1332        },
1333        PeerUpdateSenderArgs {
1334            seq: SeqNum::new(1000),
1335            len: 10,
1336            ack: SeqNum::new(0),
1337            wnd: UnscaledWindowSize::from_u32(0),
1338            fin_seen: false
1339        } => Peer {
1340            window_scale: WindowScale::new(3).unwrap(),
1341            max_wnd: WindowSize::new(16).unwrap(),
1342            max_wnd_seq: SeqNum::new(127),
1343            max_next_seq: SeqNum::new(1024),
1344            unacked_data: false,
1345            fin_state: FinState::NotSent,
1346        }; "packet smaller"
1347    )]
1348    #[test_case(
1349        Peer {
1350            window_scale: WindowScale::new(3).unwrap(),
1351            max_wnd: WindowSize::new(16).unwrap(),
1352            max_wnd_seq: SeqNum::new(127),
1353            max_next_seq: SeqNum::new(1024),
1354            unacked_data: false,
1355            fin_state: FinState::NotSent,
1356        },
1357        PeerUpdateSenderArgs {
1358            seq: SeqNum::new(1000),
1359            len: 10,
1360            ack: SeqNum::new(0),
1361            wnd: UnscaledWindowSize::from_u32(0),
1362            fin_seen: true
1363        } => Peer {
1364            window_scale: WindowScale::new(3).unwrap(),
1365            max_wnd: WindowSize::new(16).unwrap(),
1366            max_wnd_seq: SeqNum::new(127),
1367            max_next_seq: SeqNum::new(1024),
1368            unacked_data: false,
1369            fin_state: FinState::Sent(SeqNum::new(1000 + 9)),
1370        }; "fin sent"
1371    )]
1372    fn peer_update_sender_test(peer: Peer, args: PeerUpdateSenderArgs) -> Peer {
1373        peer.update_sender(args.seq, args.len, args.ack, args.wnd, args.fin_seen)
1374    }
1375
1376    #[test_case(
1377        Peer { max_next_seq: SeqNum::new(1024), ..Peer::arbitrary() },
1378        SeqNum::new(1024) => Peer { max_next_seq: SeqNum::new(1024), ..Peer::arbitrary() };
1379        "unset unacked data"
1380    )]
1381    #[test_case(
1382        Peer { max_next_seq: SeqNum::new(1024), ..Peer::arbitrary() },
1383        SeqNum::new(1023) => Peer { max_next_seq: SeqNum::new(1024), ..Peer::arbitrary() };
1384        "don't unset unacked data"
1385    )]
1386    #[test_case(
1387        Peer { fin_state: FinState::Sent(SeqNum::new(9)), ..Peer::arbitrary() },
1388        SeqNum::new(10) => Peer { fin_state: FinState::Acked, ..Peer::arbitrary() };
1389        "update fin state"
1390    )]
1391    fn peer_update_receiver_test(peer: Peer, ack: SeqNum) -> Peer {
1392        peer.update_receiver(ack)
1393    }
1394
1395    // This is mostly to ensure that we don't accidentally overflow a u32, since
1396    // it's such a basic calculation.
1397    #[test]
1398    fn peer_max_ack_window() {
1399        let max_peer = Peer { window_scale: WindowScale::MAX, ..Peer::arbitrary() };
1400        let min_peer = Peer { window_scale: WindowScale::new(0).unwrap(), ..Peer::arbitrary() };
1401
1402        assert_eq!(max_peer.max_ack_window(), 1_081_344_000u32);
1403        assert_eq!(min_peer.max_ack_window(), 66_000u32);
1404    }
1405
1406    enum EstablishedUpdateTestResult {
1407        Success { new_original: Peer, new_reply: Peer, fin_seen: bool },
1408        Invalid,
1409        Reset,
1410    }
1411
1412    struct EstablishedUpdateTestArgs {
1413        segment: SegmentHeader,
1414        payload_len: usize,
1415        dir: ConnectionDirection,
1416        expected: EstablishedUpdateTestResult,
1417    }
1418
1419    #[test_case(
1420        EstablishedUpdateTestArgs {
1421            segment: SegmentHeader {
1422                seq: SeqNum::new(1400),
1423                ack: Some(SeqNum::new(66_001)),
1424                wnd: UnscaledWindowSize::from(10),
1425                ..Default::default()
1426            },
1427            payload_len: 24,
1428            dir: ConnectionDirection::Original,
1429            expected: EstablishedUpdateTestResult::Success {
1430                new_original: Peer {
1431                    window_scale: WindowScale::new(2).unwrap(),
1432                    // Changed.
1433                    max_wnd: WindowSize::new(40).unwrap(),
1434                    max_wnd_seq: SeqNum::new(70_000),
1435                    // Changed.
1436                    max_next_seq: SeqNum::new(1424),
1437                    // Changed.
1438                    unacked_data: true,
1439                    fin_state: FinState::NotSent,
1440                },
1441                new_reply: Peer {
1442                    window_scale: WindowScale::new(0).unwrap(),
1443                    max_wnd: WindowSize::new(400).unwrap(),
1444                    max_wnd_seq: SeqNum::new(1424),
1445                    max_next_seq: SeqNum::new(66_001),
1446                    // Changed.
1447                    unacked_data: false,
1448                    fin_state: FinState::NotSent,
1449                },
1450                fin_seen: false,
1451            }
1452        }; "success original"
1453    )]
1454    #[test_case(
1455        EstablishedUpdateTestArgs {
1456            segment: SegmentHeader {
1457                seq: SeqNum::new(66_100),
1458                ack: Some(SeqNum::new(1024)),
1459                wnd: UnscaledWindowSize::from(10),
1460                control: Some(Control::FIN),
1461                ..Default::default()
1462            },
1463            payload_len: 0,
1464            dir: ConnectionDirection::Reply,
1465            expected: EstablishedUpdateTestResult::Success {
1466              // No changes in new_original.
1467              new_original: Peer {
1468                  window_scale: WindowScale::new(2).unwrap(),
1469                  max_wnd: WindowSize::new(0).unwrap(),
1470                  max_wnd_seq: SeqNum::new(70_000),
1471                  max_next_seq: SeqNum::new(1024),
1472                  unacked_data: false,
1473                  fin_state: FinState::NotSent,
1474              },
1475              new_reply: Peer {
1476                  window_scale: WindowScale::new(0).unwrap(),
1477                  max_wnd: WindowSize::new(400).unwrap(),
1478                  max_wnd_seq: SeqNum::new(1424),
1479                  max_next_seq: SeqNum::new(66_101),
1480                  unacked_data: true,
1481                  fin_state: FinState::Sent(SeqNum::new(66_100)),
1482              },
1483              fin_seen: true,
1484            }
1485        }; "success reply"
1486    )]
1487    #[test_case(
1488        EstablishedUpdateTestArgs {
1489            segment: SegmentHeader {
1490                seq: SeqNum::new(1400),
1491                ack: Some(SeqNum::new(66_001)),
1492                wnd: UnscaledWindowSize::from(10),
1493                control: Some(Control::RST),
1494                ..Default::default()
1495            },
1496            payload_len: 24,
1497            dir: ConnectionDirection::Original,
1498            expected: EstablishedUpdateTestResult::Reset,
1499        }; "RST"
1500    )]
1501    #[test_case(
1502        EstablishedUpdateTestArgs {
1503            segment: SegmentHeader {
1504                seq: SeqNum::new(1400),
1505                wnd: UnscaledWindowSize::from(10),
1506                ..Default::default()
1507            },
1508            // These don't matter for the test
1509            payload_len: 24,
1510            dir: ConnectionDirection::Original,
1511            expected: EstablishedUpdateTestResult::Invalid,
1512        }; "missing ack"
1513    )]
1514    #[test_case(
1515        EstablishedUpdateTestArgs {
1516            segment: SegmentHeader {
1517                // Too low. Doesn't meet equation II.
1518                seq: SeqNum::new(0),
1519                wnd: UnscaledWindowSize::from(10),
1520                ..Default::default()
1521            },
1522            // These don't matter for the test
1523            payload_len: 24,
1524            dir: ConnectionDirection::Original,
1525            expected: EstablishedUpdateTestResult::Invalid,
1526        }; "invalid equation bounds"
1527    )]
1528    #[test_case(
1529        EstablishedUpdateTestArgs {
1530            segment: SegmentHeader {
1531                seq: SeqNum::new(1400),
1532                ack: Some(SeqNum::new(66_001)),
1533                wnd: UnscaledWindowSize::from(10),
1534                control: Some(Control::SYN),
1535                ..Default::default()
1536            },
1537            payload_len: 24,
1538            dir: ConnectionDirection::Original,
1539            expected: EstablishedUpdateTestResult::Invalid,
1540        }; "SYN not allowed"
1541    )]
1542    fn do_established_update_test(args: EstablishedUpdateTestArgs) {
1543        let original = Peer {
1544            window_scale: WindowScale::new(2).unwrap(),
1545            max_wnd: WindowSize::new(0).unwrap(),
1546            max_wnd_seq: SeqNum::new(70_000),
1547            max_next_seq: SeqNum::new(1024),
1548            unacked_data: false,
1549            fin_state: FinState::NotSent,
1550        };
1551
1552        let reply = Peer {
1553            window_scale: WindowScale::new(0).unwrap(),
1554            max_wnd: WindowSize::new(400).unwrap(),
1555            max_wnd_seq: SeqNum::new(1424),
1556            max_next_seq: SeqNum::new(66_001),
1557            unacked_data: true,
1558            fin_state: FinState::NotSent,
1559        };
1560
1561        let expected_result = match args.expected {
1562            EstablishedUpdateTestResult::Success { new_original, new_reply, fin_seen } => {
1563                EstablishedUpdateResult::Success { new_original, new_reply, fin_seen }
1564            }
1565            EstablishedUpdateTestResult::Invalid => EstablishedUpdateResult::Invalid {
1566                original: original.clone(),
1567                reply: reply.clone(),
1568            },
1569            EstablishedUpdateTestResult::Reset => EstablishedUpdateResult::Reset,
1570        };
1571
1572        assert_eq!(
1573            do_established_update(
1574                UpdatePeers { original: original, reply: reply },
1575                &args.segment,
1576                args.payload_len,
1577                args.dir,
1578            ),
1579            expected_result
1580        );
1581    }
1582
1583    struct StateUpdateTestArgs {
1584        segment: SegmentHeader,
1585        payload_len: usize,
1586        dir: ConnectionDirection,
1587        expected: Option<State>,
1588    }
1589
1590    #[test_case(
1591        StateUpdateTestArgs {
1592            segment: SegmentHeader {
1593                seq: SeqNum::new(1400),
1594                ack: Some(SeqNum::new(66_001)),
1595                wnd: UnscaledWindowSize::from(10),
1596                ..Default::default()
1597            },
1598            payload_len: 24,
1599            dir: ConnectionDirection::Original,
1600            expected: Some(Established {
1601                original: Peer {
1602                    window_scale: WindowScale::new(2).unwrap(),
1603                    max_wnd: WindowSize::new(40).unwrap(),
1604                    max_wnd_seq: SeqNum::new(70_000),
1605                    max_next_seq: SeqNum::new(1424),
1606                    unacked_data: true,
1607                    fin_state: FinState::NotSent,
1608                },
1609                reply: Peer {
1610                    window_scale: WindowScale::new(0).unwrap(),
1611                    max_wnd: WindowSize::new(400).unwrap(),
1612                    max_wnd_seq: SeqNum::new(1424),
1613                    max_next_seq: SeqNum::new(66_001),
1614                    unacked_data: false,
1615                    fin_state: FinState::NotSent,
1616                },
1617            }.into()),
1618        }; "established"
1619    )]
1620    #[test_case(
1621        StateUpdateTestArgs {
1622            segment: SegmentHeader {
1623                seq: SeqNum::new(66_100),
1624                ack: Some(SeqNum::new(1024)),
1625                wnd: UnscaledWindowSize::from(10),
1626                control: Some(Control::FIN),
1627                ..Default::default()
1628            },
1629            payload_len: 0,
1630            dir: ConnectionDirection::Reply,
1631            expected: Some(Closing {
1632                original: Peer {
1633                    window_scale: WindowScale::new(2).unwrap(),
1634                    max_wnd: WindowSize::new(0).unwrap(),
1635                    max_wnd_seq: SeqNum::new(70_000),
1636                    max_next_seq: SeqNum::new(1024),
1637                    unacked_data: false,
1638                    fin_state: FinState::NotSent,
1639                },
1640                reply: Peer {
1641                    window_scale: WindowScale::new(0).unwrap(),
1642                    max_wnd: WindowSize::new(400).unwrap(),
1643                    max_wnd_seq: SeqNum::new(1424),
1644                    max_next_seq: SeqNum::new(66_101),
1645                    unacked_data: true,
1646                    fin_state: FinState::Sent(SeqNum::new(66_100)),
1647                },
1648            }.into()),
1649        }; "closing"
1650    )]
1651    #[test_case(
1652        StateUpdateTestArgs {
1653            segment: SegmentHeader {
1654                seq: SeqNum::new(66_100),
1655                ack: Some(SeqNum::new(1024)),
1656                wnd: UnscaledWindowSize::from(10),
1657                ..Default::default()
1658            },
1659            payload_len: 0,
1660            dir: ConnectionDirection::Reply,
1661            expected: Some(WaitingOnOpeningAck {
1662                original: Peer {
1663                    window_scale: WindowScale::new(2).unwrap(),
1664                    max_wnd: WindowSize::new(0).unwrap(),
1665                    max_wnd_seq: SeqNum::new(70_000),
1666                    max_next_seq: SeqNum::new(1024),
1667                    unacked_data: false,
1668                    fin_state: FinState::NotSent,
1669                },
1670                reply: Peer {
1671                    window_scale: WindowScale::new(0).unwrap(),
1672                    max_wnd: WindowSize::new(400).unwrap(),
1673                    max_wnd_seq: SeqNum::new(1424),
1674                    max_next_seq: SeqNum::new(66_100),
1675                    unacked_data: true,
1676                    fin_state: FinState::NotSent,
1677                },
1678            }.into())
1679        }; "update in place"
1680    )]
1681    #[test_case(
1682        StateUpdateTestArgs {
1683            segment: SegmentHeader {
1684                // Fails equation I.
1685                seq: SeqNum::new(100_000),
1686                ack: Some(SeqNum::new(1024)),
1687                wnd: UnscaledWindowSize::from(10),
1688                ..Default::default()
1689            },
1690            payload_len: 0,
1691            dir: ConnectionDirection::Reply,
1692            expected: None
1693        }; "invalid"
1694    )]
1695    #[test_case(
1696        StateUpdateTestArgs {
1697            segment: SegmentHeader {
1698                seq: SeqNum::new(1400),
1699                ack: Some(SeqNum::new(66_001)),
1700                wnd: UnscaledWindowSize::from(10),
1701                control: Some(Control::RST),
1702                ..Default::default()
1703            },
1704            payload_len: 24,
1705            dir: ConnectionDirection::Original,
1706            expected: Some(Closed {}.into()),
1707        }; "rst"
1708    )]
1709    fn waiting_on_opening_ack_test(args: StateUpdateTestArgs) {
1710        let state = WaitingOnOpeningAck {
1711            original: Peer {
1712                window_scale: WindowScale::new(2).unwrap(),
1713                max_wnd: WindowSize::new(0).unwrap(),
1714                max_wnd_seq: SeqNum::new(70_000),
1715                max_next_seq: SeqNum::new(1024),
1716                unacked_data: false,
1717                fin_state: FinState::NotSent,
1718            },
1719            reply: Peer {
1720                window_scale: WindowScale::new(0).unwrap(),
1721                max_wnd: WindowSize::new(400).unwrap(),
1722                max_wnd_seq: SeqNum::new(1424),
1723                max_next_seq: SeqNum::new(66_001),
1724                unacked_data: true,
1725                fin_state: FinState::NotSent,
1726            },
1727        };
1728
1729        let (new_state, valid) = match args.expected {
1730            Some(new_state) => (new_state, true),
1731            None => (state.clone().into(), false),
1732        };
1733
1734        assert_eq!(state.update(&args.segment, args.payload_len, args.dir), (new_state, valid));
1735    }
1736
1737    #[test_case(
1738        StateUpdateTestArgs {
1739            segment: SegmentHeader {
1740                seq: SeqNum::new(1400),
1741                ack: Some(SeqNum::new(66_001)),
1742                wnd: UnscaledWindowSize::from(10),
1743                ..Default::default()
1744            },
1745            payload_len: 24,
1746            dir: ConnectionDirection::Original,
1747            expected: Some(Established {
1748                original: Peer {
1749                    window_scale: WindowScale::new(2).unwrap(),
1750                    max_wnd: WindowSize::new(40).unwrap(),
1751                    max_wnd_seq: SeqNum::new(70_000),
1752                    max_next_seq: SeqNum::new(1424),
1753                    // This is becoming true because `segment.seq > original.max_next_seq`.
1754                    unacked_data: true,
1755                    fin_state: FinState::NotSent,
1756                },
1757                reply: Peer {
1758                    window_scale: WindowScale::new(0).unwrap(),
1759                    max_wnd: WindowSize::new(400).unwrap(),
1760                    max_wnd_seq: SeqNum::new(1424),
1761                    max_next_seq: SeqNum::new(66_001),
1762                    // This is becoming true because `segment.ack == reply.max_next_seq`.
1763                    unacked_data: false,
1764                    fin_state: FinState::NotSent,
1765                },
1766            }.into()),
1767        }; "update original"
1768    )]
1769    #[test_case(
1770        StateUpdateTestArgs {
1771            segment: SegmentHeader {
1772                seq: SeqNum::new(66_100),
1773                ack: Some(SeqNum::new(1024)),
1774                wnd: UnscaledWindowSize::from(10),
1775                control: Some(Control::FIN),
1776                ..Default::default()
1777            },
1778            payload_len: 0,
1779            dir: ConnectionDirection::Reply,
1780            expected: Some(Closing {
1781                original: Peer {
1782                    window_scale: WindowScale::new(2).unwrap(),
1783                    max_wnd: WindowSize::new(0).unwrap(),
1784                    max_wnd_seq: SeqNum::new(70_000),
1785                    max_next_seq: SeqNum::new(1024),
1786                    unacked_data: false,
1787                    fin_state: FinState::NotSent,
1788                },
1789                reply: Peer {
1790                    window_scale: WindowScale::new(0).unwrap(),
1791                    max_wnd: WindowSize::new(400).unwrap(),
1792                    max_wnd_seq: SeqNum::new(1424),
1793                    max_next_seq: SeqNum::new(66_101),
1794                    unacked_data: true,
1795                    fin_state: FinState::Sent(SeqNum::new(66_100)),
1796                },
1797            }.into()),
1798        }; "closing"
1799    )]
1800    #[test_case(
1801        StateUpdateTestArgs {
1802            segment: SegmentHeader {
1803                seq: SeqNum::new(1400),
1804                // Fails equation III.
1805                ack: Some(SeqNum::new(100_000)),
1806                wnd: UnscaledWindowSize::from(10),
1807                ..Default::default()
1808            },
1809            payload_len: 24,
1810            dir: ConnectionDirection::Original,
1811            expected: None,
1812        }; "invalid"
1813    )]
1814    #[test_case(
1815        StateUpdateTestArgs {
1816            segment: SegmentHeader {
1817                seq: SeqNum::new(1400),
1818                ack: Some(SeqNum::new(66_001)),
1819                wnd: UnscaledWindowSize::from(10),
1820                control: Some(Control::RST),
1821                ..Default::default()
1822            },
1823            payload_len: 24,
1824            dir: ConnectionDirection::Original,
1825            expected: Some(Closed {}.into()),
1826        }; "rst"
1827    )]
1828    fn established_test(args: StateUpdateTestArgs) {
1829        let state = Established {
1830            original: Peer {
1831                window_scale: WindowScale::new(2).unwrap(),
1832                max_wnd: WindowSize::new(0).unwrap(),
1833                max_wnd_seq: SeqNum::new(70_000),
1834                max_next_seq: SeqNum::new(1024),
1835                unacked_data: false,
1836                fin_state: FinState::NotSent,
1837            },
1838            reply: Peer {
1839                window_scale: WindowScale::new(0).unwrap(),
1840                max_wnd: WindowSize::new(400).unwrap(),
1841                max_wnd_seq: SeqNum::new(1424),
1842                max_next_seq: SeqNum::new(66_001),
1843                unacked_data: true,
1844                fin_state: FinState::NotSent,
1845            },
1846        };
1847
1848        let (new_state, valid) = match args.expected {
1849            Some(new_state) => (new_state, true),
1850            None => (state.clone().into(), false),
1851        };
1852
1853        assert_eq!(state.update(&args.segment, args.payload_len, args.dir), (new_state, valid));
1854    }
1855
1856    #[test_case(
1857        StateUpdateTestArgs {
1858            segment: SegmentHeader {
1859                seq: SeqNum::new(1400),
1860                ack: Some(SeqNum::new(66_001)),
1861                wnd: UnscaledWindowSize::from(10),
1862                ..Default::default()
1863            },
1864            payload_len: 24,
1865            dir: ConnectionDirection::Original,
1866            expected: Some(Closing {
1867                original: Peer {
1868                    window_scale: WindowScale::new(2).unwrap(),
1869                    max_wnd: WindowSize::new(40).unwrap(),
1870                    max_wnd_seq: SeqNum::new(70_000),
1871                    max_next_seq: SeqNum::new(1424),
1872                    unacked_data: true,
1873                    fin_state: FinState::NotSent,
1874                },
1875                reply: Peer {
1876                    window_scale: WindowScale::new(0).unwrap(),
1877                    max_wnd: WindowSize::new(400).unwrap(),
1878                    max_wnd_seq: SeqNum::new(1424),
1879                    max_next_seq: SeqNum::new(66_001),
1880                    unacked_data: false,
1881                    fin_state: FinState::Acked,
1882                },
1883            }.into()),
1884        }; "update original"
1885    )]
1886    #[test_case(
1887        StateUpdateTestArgs {
1888            segment: SegmentHeader {
1889                seq: SeqNum::new(1400),
1890                // Fails equation III.
1891                ack: Some(SeqNum::new(100_000)),
1892                wnd: UnscaledWindowSize::from(10),
1893                ..Default::default()
1894            },
1895            payload_len: 24,
1896            dir: ConnectionDirection::Original,
1897            expected: None,
1898        }; "invalid"
1899    )]
1900    #[test_case(
1901        StateUpdateTestArgs {
1902            segment: SegmentHeader {
1903                seq: SeqNum::new(1400),
1904                ack: Some(SeqNum::new(66_001)),
1905                wnd: UnscaledWindowSize::from(10),
1906                control: Some(Control::RST),
1907                ..Default::default()
1908            },
1909            payload_len: 0,
1910            dir: ConnectionDirection::Original,
1911            expected: Some (Closed {}.into())
1912        }; "rst"
1913    )]
1914    fn closing_test(args: StateUpdateTestArgs) {
1915        let state = Closing {
1916            original: Peer {
1917                window_scale: WindowScale::new(2).unwrap(),
1918                max_wnd: WindowSize::new(0).unwrap(),
1919                max_wnd_seq: SeqNum::new(70_000),
1920                max_next_seq: SeqNum::new(1024),
1921                unacked_data: true,
1922                fin_state: FinState::NotSent,
1923            },
1924            reply: Peer {
1925                window_scale: WindowScale::new(0).unwrap(),
1926                max_wnd: WindowSize::new(400).unwrap(),
1927                max_wnd_seq: SeqNum::new(1424),
1928                max_next_seq: SeqNum::new(66_001),
1929                unacked_data: false,
1930                fin_state: FinState::Acked,
1931            },
1932        };
1933
1934        let (new_state, valid) = match args.expected {
1935            Some(new_state) => (new_state, true),
1936            None => (state.clone().into(), false),
1937        };
1938
1939        assert_eq!(state.update(&args.segment, args.payload_len, args.dir), (new_state, valid));
1940    }
1941
1942    #[test]
1943    fn closing_complete_test() {
1944        let state = Closing {
1945            original: Peer {
1946                window_scale: WindowScale::new(2).unwrap(),
1947                max_wnd: WindowSize::new(0).unwrap(),
1948                max_wnd_seq: SeqNum::new(70_000),
1949                max_next_seq: SeqNum::new(1024),
1950                unacked_data: true,
1951                fin_state: FinState::Sent(SeqNum::new(1023)),
1952            },
1953            reply: Peer {
1954                window_scale: WindowScale::new(0).unwrap(),
1955                max_wnd: WindowSize::new(400).unwrap(),
1956                max_wnd_seq: SeqNum::new(1424),
1957                max_next_seq: SeqNum::new(66_001),
1958                unacked_data: false,
1959                fin_state: FinState::Acked,
1960            },
1961        };
1962
1963        let segment = SegmentHeader {
1964            seq: SeqNum::new(66_100),
1965            ack: Some(SeqNum::new(1024)),
1966            wnd: UnscaledWindowSize::from(10),
1967            ..Default::default()
1968        };
1969
1970        assert_matches!(
1971            state.update(&segment, /* payload_len */ 0, ConnectionDirection::Reply),
1972            (State::Closed(_), true)
1973        );
1974    }
1975}