1use 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#[derive(Debug, Clone)]
19pub(crate) struct Connection {
20 state: State,
22}
23
24impl Connection {
25 pub fn new(segment: &SegmentHeader, payload_len: usize, self_connected: bool) -> Option<Self> {
26 Some(Self {
27 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#[derive(Debug, Clone, PartialEq, Eq)]
72pub(crate) enum State {
73 Untracked(Untracked),
78
79 Closed(Closed),
84
85 SynSent(SynSent),
93
94 WaitingOnOpeningAck(WaitingOnOpeningAck),
101
102 Established(Established),
109
110 Closing(Closing),
120}
121
122impl State {
123 fn new(segment: &SegmentHeader, payload_len: usize) -> Option<Self> {
124 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 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 match self {
156 State::Untracked(_) => {
157 match establishment_lifecycle {
158 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 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 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#[derive(Debug, Clone, PartialEq, Eq)]
239struct Peer {
240 window_scale: WindowScale,
242
243 max_wnd: WindowSize,
248
249 max_wnd_seq: SeqNum,
255
256 max_next_seq: SeqNum,
262
263 unacked_data: bool,
270
271 fin_state: FinState,
273}
274
275impl Peer {
276 fn ack_segment_valid(
278 sender: &Self,
279 receiver: &Self,
280 seq: SeqNum,
281 len: u32,
282 ack: SeqNum,
283 ) -> bool {
284 if seq.after(receiver.max_wnd_seq) {
289 return false;
290 }
291
292 if (seq + len).before(sender.max_next_seq - receiver.max_wnd) {
294 return false;
295 }
296
297 if ack.after(receiver.max_next_seq) {
299 return false;
300 }
301
302 if ack.before(receiver.max_next_seq - receiver.max_ack_window()) {
304 return false;
305 }
306
307 true
308 }
309
310 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 let window_size = {
327 let window_size = wnd << window_scale;
328 core::cmp::max(window_size, WindowSize::from_u32(1).unwrap())
331 };
332
333 let wnd_seq = ack + window_size;
335 let end = seq + len;
337 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 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 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 66000u32 << (self.window_scale.get() as u32)
377 }
378}
379
380#[derive(Debug, Clone, PartialEq, Eq)]
382enum FinState {
383 NotSent,
385
386 Sent(SeqNum),
390
391 Acked,
393}
394
395impl FinState {
396 fn update_fin_sent(self, seq: SeqNum) -> Self {
401 match self {
402 FinState::NotSent => FinState::Sent(seq),
403 FinState::Sent(s) => {
404 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 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 fn acked(&self) -> bool {
435 match self {
436 FinState::NotSent => false,
437 FinState::Sent(_) => false,
438 FinState::Acked => true,
439 }
440 }
441}
442
443#[derive(Debug, PartialEq, Eq)]
445enum EstablishedUpdateResult {
446 Success { new_original: Peer, new_reply: Peer, fin_seen: bool },
451
452 Reset,
454
455 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
468struct UpdatePeers {
471 original: Peer,
472 reply: Peer,
473}
474
475fn 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 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#[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#[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#[derive(Debug, Clone, PartialEq, Eq)]
576pub(crate) struct SynSent {
577 iss: SeqNum,
579
580 logical_len: u32,
582
583 advertised_window_scale: Option<WindowScale>,
585
586 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 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 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 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 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 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 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 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 unacked_data: true,
725 fin_state: FinState::NotSent,
726 },
727 }
728 .into(),
729 true,
730 )
731 }
732 }
733 }
734 }
735 }
736}
737
738#[derive(Debug, Clone, PartialEq, Eq)]
754pub(crate) struct WaitingOnOpeningAck {
755 original: Peer,
758
759 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 ConnectionDirection::Original => Established { original, reply }.into(),
796 ConnectionDirection::Reply => WaitingOnOpeningAck { original, reply }.into(),
797 }
798 };
799
800 (new_state, true)
801 }
802}
803
804#[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#[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 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 (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 seq: ORIGINAL_ISS + 1,
992 wnd: UnscaledWindowSize::from(ORIGINAL_WND),
993 control: Some(Control::SYN),
994 options: HandshakeOptions {
995 window_scale: WindowScale::new(ORIGINAL_WS),
997 ..Default::default()
998 }.into(),
999 ..Default::default()
1000 }; "different ISS")]
1001 #[test_case(SegmentHeader {
1002 seq: ORIGINAL_ISS,
1004 wnd: UnscaledWindowSize::from(ORIGINAL_WND),
1005 control: Some(Control::SYN),
1006 options: HandshakeOptions {
1007 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: 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, 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, 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 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 #[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 max_wnd: WindowSize::new(40).unwrap(),
1434 max_wnd_seq: SeqNum::new(70_000),
1435 max_next_seq: SeqNum::new(1424),
1437 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 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 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 payload_len: 24,
1510 dir: ConnectionDirection::Original,
1511 expected: EstablishedUpdateTestResult::Invalid,
1512 }; "missing ack"
1513 )]
1514 #[test_case(
1515 EstablishedUpdateTestArgs {
1516 segment: SegmentHeader {
1517 seq: SeqNum::new(0),
1519 wnd: UnscaledWindowSize::from(10),
1520 ..Default::default()
1521 },
1522 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 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 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 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 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 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, 0, ConnectionDirection::Reply),
1972 (State::Closed(_), true)
1973 );
1974 }
1975}