From 2bb9dfff88d1282bbd5fee476945580b1b62e9e6 Mon Sep 17 00:00:00 2001 From: Jake Ginesin Date: Thu, 12 Mar 2026 17:55:57 -0400 Subject: [PATCH] moar --- tests/paper-attempt1.yaml | 216 ++++++++++++ tests/paper2.yaml | 127 ------- tests/paper3.yaml | 133 -------- tests/tcp/attempt1/tcp-phi1.pml | 143 ++++++++ tests/tcp/attempt1/tcp-phi2.pml | 143 ++++++++ tests/tcp/{ => attempt1}/tcp-phi2.pml.trail | 0 tests/tcp/attempt1/tcp-phi3.pml | 161 +++++++++ tests/tcp/{ => attempt1}/tcp-phi3.pml.trail | 0 tests/tcp/attempt1/tcp-phi4.pml | 150 +++++++++ tests/tcp/attempt1/tcp-phi4.pml.trail | 157 +++++++++ tests/tcp/attempt1/tcp-phi5.pml | 152 +++++++++ tests/tcp/{ => attempt1}/tcp-phi5.pml.trail | 0 tests/tcp/attempt1/tcp-phi6.pml | 148 +++++++++ tests/tcp/attempt1/tcp-phi6.pml.trail | 88 +++++ tests/tcp/attempt1/tcp.pml | 138 ++++++++ tests/tcp/pan | Bin 110592 -> 110664 bytes tests/tcp/props/phi7.pml | 9 + tests/tcp/props/phi8.pml | 6 + tests/tcp/props/phi9.pml | 8 + tests/tcp/tcp-phi1.pml | 214 ++++++------ tests/tcp/tcp-phi2.pml | 212 ++++++------ tests/tcp/tcp-phi3.pml | 211 ++++++------ tests/tcp/tcp-phi4.pml | 211 ++++++------ tests/tcp/tcp-phi4.pml.trail | 345 +++++++++++--------- tests/tcp/tcp-phi5.pml | 211 ++++++------ tests/tcp/tcp-phi6.pml | 211 ++++++------ tests/tcp/tcp-phi6.pml.trail | 186 ++++++----- tests/tcp/tcp-phi7.pml | 149 +++++++++ tests/tcp/tcp-phi8.pml | 146 +++++++++ tests/tcp/tcp-phi9.pml | 148 +++++++++ tests/tcp/tcp.pml | 211 ++++++------ 31 files changed, 2996 insertions(+), 1238 deletions(-) create mode 100644 tests/paper-attempt1.yaml delete mode 100644 tests/paper2.yaml delete mode 100644 tests/paper3.yaml create mode 100644 tests/tcp/attempt1/tcp-phi1.pml create mode 100644 tests/tcp/attempt1/tcp-phi2.pml rename tests/tcp/{ => attempt1}/tcp-phi2.pml.trail (100%) create mode 100644 tests/tcp/attempt1/tcp-phi3.pml rename tests/tcp/{ => attempt1}/tcp-phi3.pml.trail (100%) create mode 100644 tests/tcp/attempt1/tcp-phi4.pml create mode 100644 tests/tcp/attempt1/tcp-phi4.pml.trail create mode 100644 tests/tcp/attempt1/tcp-phi5.pml rename tests/tcp/{ => attempt1}/tcp-phi5.pml.trail (100%) create mode 100644 tests/tcp/attempt1/tcp-phi6.pml create mode 100644 tests/tcp/attempt1/tcp-phi6.pml.trail create mode 100644 tests/tcp/attempt1/tcp.pml create mode 100644 tests/tcp/props/phi7.pml create mode 100644 tests/tcp/props/phi8.pml create mode 100644 tests/tcp/props/phi9.pml create mode 100644 tests/tcp/tcp-phi7.pml create mode 100644 tests/tcp/tcp-phi8.pml create mode 100644 tests/tcp/tcp-phi9.pml diff --git a/tests/paper-attempt1.yaml b/tests/paper-attempt1.yaml new file mode 100644 index 0000000..3bc8ec1 --- /dev/null +++ b/tests/paper-attempt1.yaml @@ -0,0 +1,216 @@ +# --- PHI 1: HALF-OPEN PREVENTION --- + +tcp-phi1-drop-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: property violation + - explanation: Dropping A's FIN allows A to eventually time out to Closed while B remains stranded in Established. + +tcp-phi1-drop-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=0 + - intended: no violation + - explanation: Attacker has 0 memory budget; normal teardown prevents half-open states. + +tcp-phi1-replay-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: property violation + - explanation: Replaying a stale SYN from A forces B into an Established state while A is completely Closed. + +tcp-phi1-replay-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=replay --chan=BtoA --output=temp.pml --eval --cleanup --mem=1 + - intended: no violation + - explanation: Replaying B's final teardown ACK is idempotent and harmlessly dropped by A, maintaining state sync. + +tcp-phi1-reorder-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=2 + - intended: property violation + - explanation: Reordering A's SYN and FIN segments desynchronizes B's state machine, triggering a half-open state. + +tcp-phi1-reorder-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: no violation + - explanation: Reorder attacker requires at least mem=2 to swap messages; mem=1 is insufficient. + + +# --- PHI 3: NO DEADLOCKS --- + +tcp-phi3-drop-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=drop --chan=BtoA --output=temp.pml --eval --cleanup --mem=1 + - intended: acceptance cycle + - explanation: Dropping B's SYN-ACK stalls A in SynSent and B in SynRec indefinitely without timeout recovery. + +tcp-phi3-drop-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=0 + - intended: no violation + - explanation: Zero memory prevents dropping, allowing standard timers and handshakes to resolve without deadlocks. + +tcp-phi3-replay-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: acceptance cycle + - explanation: Replaying FIN messages traps the receiver in an infinite loop of CloseWait/LastAck processing. + +tcp-phi3-replay-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=replay --chan=BtoA --output=temp.pml --eval --cleanup --mem=1 + - intended: no violation + - explanation: Replaying an ACK during the Established state is cleanly ignored and does not halt liveness progress. + +tcp-phi3-reorder-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=reorder --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=2 + - intended: acceptance cycle + - explanation: Swapping handshake messages (ACK before SYN) deadlocks both endpoints in intermediate waiting states. + +tcp-phi3-reorder-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: no violation + - explanation: Attacker lacks the mem=2 budget required to execute a reorder attack. + + +# --- PHI 5: SYN_RECEIVED RESOLUTION --- + +tcp-phi5-drop-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: acceptance cycle + - explanation: Dropping the final ACK of the 3-way handshake prevents B from ever resolving SynRec to Established. + +tcp-phi5-drop-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=0 + - intended: no violation + - explanation: Without drop capabilities, the ACK arrives normally, resolving the SynRec state. + +tcp-phi5-replay-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: acceptance cycle + - explanation: Replaying a SYN forces B to repeatedly trigger simultaneous open logic, preventing resolution. + +tcp-phi5-replay-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: no violation + - explanation: Replaying the final ACK simply provides redundant resolution signals, which satisfies the property. + +tcp-phi5-reorder-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=2 + - intended: acceptance cycle + - explanation: Delivering A's final ACK before B has fully entered SynRec confuses the state machine, stalling resolution. + +tcp-phi5-reorder-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: no violation + - explanation: Insufficient memory to reorder packets; handshakes process chronologically. + + +# --- PHI 6: STRICT CLOSING TRANSITIONS --- + +tcp-phi6-drop-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: property violation + - explanation: Dropping the ACK to the FIN causes a timeout that bypasses the strict Closing-to-Closed state sequence. + +tcp-phi6-drop-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=0 + - intended: no violation + - explanation: Normal termination proceeds; Closing transitions accurately based on protocol rules. + +tcp-phi6-replay-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: property violation + - explanation: Replaying a FIN while in Closing forces an invalid transition to TimeWait instead of Closed. + +tcp-phi6-replay-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=0 + - intended: no violation + - explanation: 0 memory prevents injection of unexpected packets during the tear-down phase. + +tcp-phi6-reorder-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=reorder --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=2 + - intended: property violation + - explanation: Swapping FINs during a simultaneous close alters the ACK delivery timing, violating the strict sequence. + +tcp-phi6-reorder-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: no violation + - explanation: Mem=1 prevents the reordering of the close-sequence messages. + +# --- PHI 7: SIMULTANEOUS CLOSE RESOLUTION --- + +tcp-phi7-drop-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi7.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: acceptance cycle + - explanation: Dropping a FIN during a simultaneous close prevents one side from transitioning out of FinW1State. + +tcp-phi7-drop-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi7.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=0 + - intended: no violation + - explanation: Zero memory prevents message dropping; both endpoints successfully reach ClosedState. + +tcp-phi7-replay-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi7.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: acceptance cycle + - explanation: Replaying stale FINs traps the endpoint in a continuous processing loop, halting progress to ClosedState. + +tcp-phi7-replay-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi7.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=0 + - intended: no violation + - explanation: Without replay capabilities, the simultaneous close resolves chronologically. + +tcp-phi7-reorder-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi7.pml --attacker=reorder --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=2 + - intended: acceptance cycle + - explanation: Swapping FIN and ACK segments out of order desynchronizes the simultaneous close, causing a deadlock. + +tcp-phi7-reorder-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi7.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: no violation + - explanation: Mem=1 is insufficient to execute a reorder attack. + + +# --- PHI 8: ACTIVE CLOSE EVENTUALLY TERMINATES --- + +tcp-phi8-drop-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi8.pml --attacker=drop --chan=BtoA --output=temp.pml --eval --cleanup --mem=1 + - intended: acceptance cycle + - explanation: Dropping the responder's ACK leaves the active closer permanently stranded in FinW1State. + +tcp-phi8-drop-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi8.pml --attacker=drop --chan=BtoA --output=temp.pml --eval --cleanup --mem=0 + - intended: no violation + - explanation: Normal teardown ensures the active closer receives its ACK and FIN. + +tcp-phi8-replay-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi8.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: acceptance cycle + - explanation: Replaying application data or FINs delays the final transition, breaking the eventual termination guarantee. + +tcp-phi8-replay-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi8.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=0 + - intended: no violation + - explanation: Normal sequence guarantees the active closer reaches ClosedState. + +tcp-phi8-reorder-violate: + - command: python src/main.py --model=tests/tcp/tcp-phi8.pml --attacker=reorder --chan=BtoA --output=temp.pml --eval --cleanup --mem=2 + - intended: acceptance cycle + - explanation: Delivering the responder's FIN before the ACK confuses the state machine logic in FinW1State, stalling termination. + +tcp-phi8-reorder-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi8.pml --attacker=reorder --chan=BtoA --output=temp.pml --eval --cleanup --mem=1 + - intended: no violation + - explanation: Insufficient memory to alter the close sequence. + + +# --- PHI 9: HANDSHAKE CANNOT BE BYPASSED --- +# Note: This is a strict safety property guaranteed by the structure of the Promela model. +# The LISTEN state explicitly routes only to SYN_RECEIVED upon reading a SYN. +# No channel attacker (drop, replay, reorder) can force a direct jump to ESTABLISHED. + +tcp-phi9-drop-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi9.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: no violation + - explanation: Dropping messages halts progress but cannot force an illegal structural transition from Listen directly to Established. + +tcp-phi9-replay-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi9.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 + - intended: no violation + - explanation: The model's Listen state only branches on SYN (transitioning to SynRec). Replaying ACKs or FINs results in skipped messages, not illegal state jumps. + +tcp-phi9-reorder-pass: + - command: python src/main.py --model=tests/tcp/tcp-phi9.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=2 + - intended: no violation + - explanation: Regardless of message order, the Promela model restricts ListenState exits exclusively to SynRecState. This safety property is structurally immune to channel manipulation. diff --git a/tests/paper2.yaml b/tests/paper2.yaml deleted file mode 100644 index 4c46c60..0000000 --- a/tests/paper2.yaml +++ /dev/null @@ -1,127 +0,0 @@ -unidirectional-drop-abp: - - command: python src/main.py --model=tests/abp/abp.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: abp resists drop, see https://en.wikipedia.org/wiki/Alternating_bit_protocol - -bidirectional-drop-abp: - - command: python src/main.py --model=tests/abp/abp.pml --attacker=drop --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: abp resists drop, see https://en.wikipedia.org/wiki/Alternating_bit_protocol - -# ============================================================================= -# TCP tests -# -# NOTE: The TCP model uses separate send/receive channel pairs -# (AtoN[1], NtoA[0], BtoN[1], NtoB[0]) with no network forwarding process. -# A sends on AtoN but B receives on NtoB; Korg's single-channel attacker -# gadgets cannot bridge this gap. As a result, all single-channel attacks -# are ineffective: consumed/replayed/reordered messages on AtoN never -# reach B (and vice versa). Both TCP processes fall back to Closed via -# timeout transitions, so all properties hold trivially or vacuously. -# -# This demonstrates a structural limitation: Korg's channel-local attackers -# require that communicating processes share the attacked channel. A network -# forwarding process (AtoN -> NtoB, BtoN -> NtoA) would be needed for -# meaningful cross-channel attacks. -# ============================================================================= - -# phi1: safety - half-open prevention -# always (leftClosed implies !rightEstablished) - -tcp-phi1-drop-AtoN: - - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=drop --chan=AtoN --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: attacker consumes from AtoN but B reads NtoB; no messages are delivered cross-channel so neither side reaches Established, and phi1 holds trivially - -tcp-phi1-drop-bidirectional: - - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=drop --chan=AtoN,BtoN --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: dropping on both outbound channels still cannot affect the inbound rendezvous channels NtoA/NtoB; no handshake progress occurs - -tcp-phi1-replay-AtoN: - - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=replay --chan=AtoN --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: replayed messages land back on AtoN, which only A writes to; B never reads AtoN so no half-open state can be manufactured - -tcp-phi1-replay-bidirectional: - - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=replay --chan=AtoN,BtoN --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: replaying on both outbound channels cannot bridge to the rendezvous inbound channels; property holds vacuously - -tcp-phi1-reorder-AtoN: - - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=reorder --chan=AtoN --output=temp.pml --eval --cleanup --mem=2 - - intended: no violation - - explanation: reordering on AtoN is invisible to B; the channel architecture prevents any cross-channel effect - -tcp-phi1-reorder-bidirectional: - - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=reorder --chan=AtoN,BtoN --output=temp.pml --eval --cleanup --mem=2 - - intended: no violation - - explanation: reordering both outbound channels still cannot deliver messages to the inbound rendezvous channels - -# phi3: liveness - no infinite stalls/deadlocks - -tcp-phi3-drop-AtoN: - - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=drop --chan=AtoN --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: timeout transitions in LISTEN and SYN_SENT return both processes to Closed; no permanent stall occurs because no cross-channel delivery happens - -tcp-phi3-drop-bidirectional: - - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=drop --chan=AtoN,BtoN --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: same as above; both sides cycle through Closed via timeout, preventing any permanent intermediate state - -tcp-phi3-replay-AtoN: - - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=replay --chan=AtoN --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: replayed messages on AtoN do not reach B; both sides timeout-cycle through Closed, so no stall - -tcp-phi3-reorder-bidirectional: - - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=reorder --chan=AtoN,BtoN --output=temp.pml --eval --cleanup --mem=2 - - intended: no violation - - explanation: reordering cannot create stalls when messages never cross between the two TCP processes - -# phi5: liveness - SYN_RECEIVED resolution -# SynReceived implies eventually (Established or FinWait1 or Closed) - -tcp-phi5-drop-AtoN: - - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=drop --chan=AtoN --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: neither process enters SynReceived because no SYN is ever delivered cross-channel; the property holds vacuously - -tcp-phi5-drop-BtoN: - - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=drop --chan=BtoN --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: same as above; without cross-channel delivery, SynReceived is never entered - -tcp-phi5-replay-AtoN: - - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=replay --chan=AtoN --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: replaying on AtoN cannot deliver a SYN to B via NtoB; SynReceived is never reached, so the property holds vacuously - -tcp-phi5-reorder-AtoN: - - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=reorder --chan=AtoN --output=temp.pml --eval --cleanup --mem=2 - - intended: no violation - - explanation: reordering on AtoN has no cross-channel effect; property holds vacuously as SynReceived is unreachable - -# phi6: safety - strict closing transitions -# Closing implies next(Closing or Closed) - -tcp-phi6-drop-AtoN: - - command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=drop --chan=AtoN --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: Closing state is never reached without cross-channel message delivery; property holds vacuously - -tcp-phi6-replay-AtoN: - - command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=replay --chan=AtoN --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: replay on AtoN cannot drive either process into Closing; property holds vacuously - -tcp-phi6-replay-bidirectional: - - command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=replay --chan=AtoN,BtoN --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: replaying on both outbound channels still cannot bridge to inbound rendezvous channels; Closing never entered - -tcp-phi6-reorder-bidirectional: - - command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=reorder --chan=AtoN,BtoN --output=temp.pml --eval --cleanup --mem=2 - - intended: no violation - - explanation: reordering both outbound channels has no effect on the rendezvous inbound channels; Closing never entered diff --git a/tests/paper3.yaml b/tests/paper3.yaml deleted file mode 100644 index 41089d6..0000000 --- a/tests/paper3.yaml +++ /dev/null @@ -1,133 +0,0 @@ -unidirectional-drop-abp: - - command: python src/main.py --model=tests/abp/abp.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: abp resists drop, see https://en.wikipedia.org/wiki/Alternating_bit_protocol - -bidirectional-drop-abp: - - command: python src/main.py --model=tests/abp/abp.pml --attacker=drop --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: abp resists drop, see https://en.wikipedia.org/wiki/Alternating_bit_protocol - -# ============================================================================= -# TCP - shared channel model (AtoB, BtoA) -# -# A sends on AtoB, B reads AtoB. B sends on BtoA, A reads BtoA. -# Korg attackers directly interpose on the shared channel. -# ============================================================================= - -# phi1: safety - half-open prevention -# always (leftClosed implies !rightEstablished) -# Expected: holds. B reaching Established requires A's ACK, which means -# A was also in Established. A cannot reach Closed from Established -# without a full teardown that also moves B out of Established. - -tcp-phi1-drop-AtoB: - - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: dropping A's messages prevents B from reaching Established; no half-open possible - -tcp-phi1-drop-bidirectional: - - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=drop --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: dropping on both channels prevents any handshake completion; neither side reaches Established - -tcp-phi1-replay-AtoB: - - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 - - intended: property violation - - explanation: replay attacker copies A's message non-destructively, allowing normal handshake and teardown; after A returns to Closed, the replayed stale message drives B through a new handshake into Established, creating a half-open state - -tcp-phi1-replay-bidirectional: - - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=replay --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=1 - - intended: property violation - - explanation: replay on both channels injects stale handshake messages in both directions; after A tears down to Closed, replayed messages push B into Established without A's participation - -tcp-phi1-reorder-bidirectional: - - command: python src/main.py --model=tests/tcp/tcp-phi1.pml --attacker=reorder --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=2 - - intended: no violation - - explanation: reordering cannot bypass the handshake dependency; half-open prevention holds structurally - -# phi3: liveness - no infinite stalls/deadlocks -# neither side stuck forever in a non-terminal state -# Expected: drop on both channels can strand both sides post-Established -# (e.g., both in FinWait1 after FINs are dropped) - -tcp-phi3-drop-AtoB-nodeadlock: - - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=0 - - intended: no violation - - explanation: with mem=0 the drop attacker cannot consume any messages; it goes straight to BREAK, leaving the model unmodified; timeout transitions prevent permanent stalls in the base model - -tcp-phi3-drop-AtoB: - - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 - - intended: acceptance cycle - - explanation: handshake completes via nondeterministic pass; then attacker drops A's FIN, stranding both sides in post-Established states with no timeout recovery - -tcp-phi3-drop-bidirectional: - - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=drop --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=1 - - intended: acceptance cycle - - explanation: attackers let handshake through, then drop FINs on both channels; both sides stuck in FinWait1 or similar permanently - -tcp-phi3-replay-AtoB: - - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 - - intended: acceptance cycle - - explanation: replay attacker can consume A's FIN and never replay it, effectively dropping it; B stays in Established, A stuck in FinWait1 - -tcp-phi3-reorder-bidirectional: - - command: python src/main.py --model=tests/tcp/tcp-phi3.pml --attacker=reorder --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=2 - - intended: acceptance cycle - - explanation: reorder attacker consumes teardown messages and delays them indefinitely, stranding both sides - -# phi5: liveness - SYN_RECEIVED resolution -# SynReceived implies eventually (Established or FinWait1 or Closed) -# Expected: drop on AtoB traps A in SynReceived (no timeout modeled) - - -tcp-phi5-replay-BtoA: - - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=replay --chan=BtoA --output=temp.pml --eval --cleanup --mem=1 - - intended: no violation - - explanation: replaying B's messages on BtoA delivers extra SYNs to A; if A enters SynReceived, the replayed messages do not prevent ACK delivery on AtoB (which is unattacked), so SynReceived resolves normally - -tcp-phi5-drop-AtoB: - - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 - - intended: acceptance cycle - - explanation: A goes to Listen, B's SYN arrives via BtoA, A enters SynReceived and sends SYN+ACK on AtoB; attacker drops it; B never completes handshake, A stuck in SynReceived permanently (no timeout in model) - -tcp-phi5-drop-BtoA: - - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=drop --chan=BtoA --output=temp.pml --eval --cleanup --mem=1 - - intended: acceptance cycle - - explanation: B sends SYN on BtoA, attacker drops it; but A can also initiate — if A goes Listen and B goes SynSent, A needs B's SYN which is dropped; however A can enter SynReceived via simultaneous open path and get stuck - -tcp-phi5-drop-bidirectional: - - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=drop --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=1 - - intended: acceptance cycle - - explanation: dropping on both channels after SynReceived is entered prevents any ACK from arriving to resolve it - -tcp-phi5-replay-AtoB: - - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 - - intended: acceptance cycle - - explanation: replay attacker consumes A's SYN+ACK and never replays it (terminates with empty mem), effectively a drop; A stuck in SynReceived - -tcp-phi5-reorder-AtoB: - - command: python src/main.py --model=tests/tcp/tcp-phi5.pml --attacker=reorder --chan=AtoB --output=temp.pml --eval --cleanup --mem=2 - - intended: acceptance cycle - - explanation: reorder attacker consumes A's SYN+ACK during the handshake; even if replayed later, the ordering disruption can prevent SynReceived resolution - -# phi6: safety - strict closing transitions -# Closing implies next(Closing or Closed) -# Expected: violated even without attacker. Closing transitions to -# TimeWait on ACK (not Closed), and TimeWaitState is neither -# ClosingState nor ClosedState. - -tcp-phi6-drop-AtoB: - - command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=drop --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 - - intended: property violation - - explanation: base model already violates phi6; simultaneous close leads to Closing, then ACK transitions to TimeWait which is not Closing or Closed; attacker goes to BREAK, preserving the pre-existing violation - -tcp-phi6-replay-AtoB: - - command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=replay --chan=AtoB --output=temp.pml --eval --cleanup --mem=1 - - intended: property violation - - explanation: same base-model violation; Closing -> TimeWait is always reachable once simultaneous close occurs - -tcp-phi6-reorder-bidirectional: - - command: python src/main.py --model=tests/tcp/tcp-phi6.pml --attacker=reorder --chan=AtoB,BtoA --output=temp.pml --eval --cleanup --mem=2 - - intended: property violation - - explanation: same base-model violation; attacker presence does not affect the Closing -> TimeWait transition path diff --git a/tests/tcp/attempt1/tcp-phi1.pml b/tests/tcp/attempt1/tcp-phi1.pml new file mode 100644 index 0000000..a95ba99 --- /dev/null +++ b/tests/tcp/attempt1/tcp-phi1.pml @@ -0,0 +1,143 @@ +mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN } + +chan AtoB = [2] of { mtype }; +chan BtoA = [2] of { mtype }; + +int state[2]; +int pids[2]; + +#define ClosedState 0 +#define ListenState 1 +#define SynSentState 2 +#define SynRecState 3 +#define EstState 4 +#define FinW1State 5 +#define CloseWaitState 6 +#define FinW2State 7 +#define ClosingState 8 +#define LastAckState 9 +#define TimeWaitState 10 +#define EndState -1 + +#define leftConnecting (state[0] == ListenState && state[1] == SynSentState) +#define leftEstablished (state[0] == EstState) +#define rightEstablished (state[1] == EstState) +#define leftClosed (state[0] == ClosedState) + +proctype TCP(chan snd, rcv; int i) { + pids[i] = _pid; +CLOSED: + state[i] = ClosedState; + do + /* Passive open */ + :: goto LISTEN; + /* Active open */ + :: snd ! SYN; goto SYN_SENT; + /* Terminate */ + :: goto end; + od +LISTEN: + state[i] = ListenState; + do + :: rcv ? SYN -> + atomic { + snd ! SYN; + snd ! ACK; + goto SYN_RECEIVED; + } + /* Simultaneous LISTEN */ + :: rcv ? _ -> skip; + :: timeout -> goto CLOSED; + od +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? SYN; + if + /* Standard behavior */ + :: rcv ? ACK -> snd ! ACK; goto ESTABLISHED; + /* Simultaneous open */ + :: snd ! ACK; goto SYN_RECEIVED; + fi + :: rcv ? ACK; + do + :: rcv ? SYN -> + snd ! ACK; + goto ESTABLISHED; + :: rcv ? _ -> skip; + od + :: rcv ? _ -> skip; + :: timeout -> goto CLOSED; /* Timeout */ + od +SYN_RECEIVED: + state[i] = SynRecState; + do + :: rcv ? ACK -> goto ESTABLISHED; + :: rcv ? _ -> skip; + od +ESTABLISHED: + state[i] = EstState; + do + /* Close - initiator sequence */ + :: snd ! FIN; goto FIN_WAIT_1; + /* Close - responder sequence */ + :: rcv ? FIN -> + snd ! ACK; + goto CLOSE_WAIT; + :: rcv ? _ -> skip; + od +FIN_WAIT_1: + state[i] = FinW1State; + do + /* Simultaneous close */ + :: rcv ? FIN -> + snd ! ACK; + goto CLOSING; + /* Standard close */ + :: rcv ? ACK -> goto FIN_WAIT_2; + :: rcv ? _ -> skip; + od +CLOSE_WAIT: + state[i] = CloseWaitState; + do + :: snd ! FIN; goto LAST_ACK; + :: rcv ? _ -> skip; + od +FIN_WAIT_2: + state[i] = FinW2State; + do + :: rcv ? FIN -> + snd ! ACK; + goto TIME_WAIT; + :: rcv ? _ -> skip; + od +CLOSING: + state[i] = ClosingState; + do + :: rcv ? ACK -> goto TIME_WAIT; + :: rcv ? _ -> skip; + od +LAST_ACK: + state[i] = LastAckState; + do + :: rcv ? ACK -> goto CLOSED; + :: rcv ? _ -> skip; + od +TIME_WAIT: + state[i] = TimeWaitState; + goto CLOSED; +end: + state[i] = EndState; +} + +init { + state[0] = ClosedState; + state[1] = ClosedState; + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); +} + +/* safety: half-open prevention */ +ltl phi1 { + always ( leftClosed implies !rightEstablished ) +} diff --git a/tests/tcp/attempt1/tcp-phi2.pml b/tests/tcp/attempt1/tcp-phi2.pml new file mode 100644 index 0000000..620854f --- /dev/null +++ b/tests/tcp/attempt1/tcp-phi2.pml @@ -0,0 +1,143 @@ +mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN } + +chan AtoB = [2] of { mtype }; +chan BtoA = [2] of { mtype }; + +int state[2]; +int pids[2]; + +#define ClosedState 0 +#define ListenState 1 +#define SynSentState 2 +#define SynRecState 3 +#define EstState 4 +#define FinW1State 5 +#define CloseWaitState 6 +#define FinW2State 7 +#define ClosingState 8 +#define LastAckState 9 +#define TimeWaitState 10 +#define EndState -1 + +#define leftConnecting (state[0] == ListenState && state[1] == SynSentState) +#define leftEstablished (state[0] == EstState) +#define rightEstablished (state[1] == EstState) +#define leftClosed (state[0] == ClosedState) + +proctype TCP(chan snd, rcv; int i) { + pids[i] = _pid; +CLOSED: + state[i] = ClosedState; + do + /* Passive open */ + :: goto LISTEN; + /* Active open */ + :: snd ! SYN; goto SYN_SENT; + /* Terminate */ + :: goto end; + od +LISTEN: + state[i] = ListenState; + do + :: rcv ? SYN -> + atomic { + snd ! SYN; + snd ! ACK; + goto SYN_RECEIVED; + } + /* Simultaneous LISTEN */ + :: rcv ? _ -> skip; + :: timeout -> goto CLOSED; + od +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? SYN; + if + /* Standard behavior */ + :: rcv ? ACK -> snd ! ACK; goto ESTABLISHED; + /* Simultaneous open */ + :: snd ! ACK; goto SYN_RECEIVED; + fi + :: rcv ? ACK; + do + :: rcv ? SYN -> + snd ! ACK; + goto ESTABLISHED; + :: rcv ? _ -> skip; + od + :: rcv ? _ -> skip; + :: timeout -> goto CLOSED; /* Timeout */ + od +SYN_RECEIVED: + state[i] = SynRecState; + do + :: rcv ? ACK -> goto ESTABLISHED; + :: rcv ? _ -> skip; + od +ESTABLISHED: + state[i] = EstState; + do + /* Close - initiator sequence */ + :: snd ! FIN; goto FIN_WAIT_1; + /* Close - responder sequence */ + :: rcv ? FIN -> + snd ! ACK; + goto CLOSE_WAIT; + :: rcv ? _ -> skip; + od +FIN_WAIT_1: + state[i] = FinW1State; + do + /* Simultaneous close */ + :: rcv ? FIN -> + snd ! ACK; + goto CLOSING; + /* Standard close */ + :: rcv ? ACK -> goto FIN_WAIT_2; + :: rcv ? _ -> skip; + od +CLOSE_WAIT: + state[i] = CloseWaitState; + do + :: snd ! FIN; goto LAST_ACK; + :: rcv ? _ -> skip; + od +FIN_WAIT_2: + state[i] = FinW2State; + do + :: rcv ? FIN -> + snd ! ACK; + goto TIME_WAIT; + :: rcv ? _ -> skip; + od +CLOSING: + state[i] = ClosingState; + do + :: rcv ? ACK -> goto TIME_WAIT; + :: rcv ? _ -> skip; + od +LAST_ACK: + state[i] = LastAckState; + do + :: rcv ? ACK -> goto CLOSED; + :: rcv ? _ -> skip; + od +TIME_WAIT: + state[i] = TimeWaitState; + goto CLOSED; +end: + state[i] = EndState; +} + +init { + state[0] = ClosedState; + state[1] = ClosedState; + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); +} + +/* liveness: verifying connection establishment */ +ltl phi2 { + ( (always ( eventually ( state[0] == 1 && state[1] == 2 ) ) ) + implies ( eventually ( state[0] == 4 ) ) ) diff --git a/tests/tcp/tcp-phi2.pml.trail b/tests/tcp/attempt1/tcp-phi2.pml.trail similarity index 100% rename from tests/tcp/tcp-phi2.pml.trail rename to tests/tcp/attempt1/tcp-phi2.pml.trail diff --git a/tests/tcp/attempt1/tcp-phi3.pml b/tests/tcp/attempt1/tcp-phi3.pml new file mode 100644 index 0000000..45f6418 --- /dev/null +++ b/tests/tcp/attempt1/tcp-phi3.pml @@ -0,0 +1,161 @@ +mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN } + +chan AtoB = [2] of { mtype }; +chan BtoA = [2] of { mtype }; + +int state[2]; +int pids[2]; + +#define ClosedState 0 +#define ListenState 1 +#define SynSentState 2 +#define SynRecState 3 +#define EstState 4 +#define FinW1State 5 +#define CloseWaitState 6 +#define FinW2State 7 +#define ClosingState 8 +#define LastAckState 9 +#define TimeWaitState 10 +#define EndState -1 + +#define leftConnecting (state[0] == ListenState && state[1] == SynSentState) +#define leftEstablished (state[0] == EstState) +#define rightEstablished (state[1] == EstState) +#define leftClosed (state[0] == ClosedState) + +proctype TCP(chan snd, rcv; int i) { + pids[i] = _pid; +CLOSED: + state[i] = ClosedState; + do + /* Passive open */ + :: goto LISTEN; + /* Active open */ + :: snd ! SYN; goto SYN_SENT; + /* Terminate */ + :: goto end; + od +LISTEN: + state[i] = ListenState; + do + :: rcv ? SYN -> + atomic { + snd ! SYN; + snd ! ACK; + goto SYN_RECEIVED; + } + /* Simultaneous LISTEN */ + :: rcv ? _ -> skip; + :: timeout -> goto CLOSED; + od +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? SYN; + if + /* Standard behavior */ + :: rcv ? ACK -> snd ! ACK; goto ESTABLISHED; + /* Simultaneous open */ + :: snd ! ACK; goto SYN_RECEIVED; + fi + :: rcv ? ACK; + do + :: rcv ? SYN -> + snd ! ACK; + goto ESTABLISHED; + :: rcv ? _ -> skip; + od + :: rcv ? _ -> skip; + :: timeout -> goto CLOSED; /* Timeout */ + od +SYN_RECEIVED: + state[i] = SynRecState; + do + :: rcv ? ACK -> goto ESTABLISHED; + :: rcv ? _ -> skip; + od +ESTABLISHED: + state[i] = EstState; + do + /* Close - initiator sequence */ + :: snd ! FIN; goto FIN_WAIT_1; + /* Close - responder sequence */ + :: rcv ? FIN -> + snd ! ACK; + goto CLOSE_WAIT; + :: rcv ? _ -> skip; + od +FIN_WAIT_1: + state[i] = FinW1State; + do + /* Simultaneous close */ + :: rcv ? FIN -> + snd ! ACK; + goto CLOSING; + /* Standard close */ + :: rcv ? ACK -> goto FIN_WAIT_2; + :: rcv ? _ -> skip; + od +CLOSE_WAIT: + state[i] = CloseWaitState; + do + :: snd ! FIN; goto LAST_ACK; + :: rcv ? _ -> skip; + od +FIN_WAIT_2: + state[i] = FinW2State; + do + :: rcv ? FIN -> + snd ! ACK; + goto TIME_WAIT; + :: rcv ? _ -> skip; + od +CLOSING: + state[i] = ClosingState; + do + :: rcv ? ACK -> goto TIME_WAIT; + :: rcv ? _ -> skip; + od +LAST_ACK: + state[i] = LastAckState; + do + :: rcv ? ACK -> goto CLOSED; + :: rcv ? _ -> skip; + od +TIME_WAIT: + state[i] = TimeWaitState; + goto CLOSED; +end: + state[i] = EndState; +} + +init { + state[0] = ClosedState; + state[1] = ClosedState; + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); +} + +/* liveness: no infinite stalls/deadlocks */ +ltl phi3 { + !(eventually (((always (state[0] == SynSentState)) || + (always (state[0] == SynRecState)) || + (always (state[0] == EstState)) || + (always (state[0] == FinW1State)) || + (always (state[0] == CloseWaitState)) || + (always (state[0] == FinW2State)) || + (always (state[0] == ClosingState)) || + (always (state[0] == LastAckState)) || + (always (state[0] == TimeWaitState))) + && + ((always (state[1] == SynSentState)) || + (always (state[1] == SynRecState)) || + (always (state[1] == EstState)) || + (always (state[1] == FinW1State)) || + (always (state[1] == CloseWaitState)) || + (always (state[1] == FinW2State)) || + (always (state[1] == ClosingState)) || + (always (state[1] == LastAckState)) || + (always (state[1] == TimeWaitState))))) +} diff --git a/tests/tcp/tcp-phi3.pml.trail b/tests/tcp/attempt1/tcp-phi3.pml.trail similarity index 100% rename from tests/tcp/tcp-phi3.pml.trail rename to tests/tcp/attempt1/tcp-phi3.pml.trail diff --git a/tests/tcp/attempt1/tcp-phi4.pml b/tests/tcp/attempt1/tcp-phi4.pml new file mode 100644 index 0000000..b34fa36 --- /dev/null +++ b/tests/tcp/attempt1/tcp-phi4.pml @@ -0,0 +1,150 @@ +mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN } + +chan AtoB = [2] of { mtype }; +chan BtoA = [2] of { mtype }; + +int state[2]; +int pids[2]; + +#define ClosedState 0 +#define ListenState 1 +#define SynSentState 2 +#define SynRecState 3 +#define EstState 4 +#define FinW1State 5 +#define CloseWaitState 6 +#define FinW2State 7 +#define ClosingState 8 +#define LastAckState 9 +#define TimeWaitState 10 +#define EndState -1 + +#define leftConnecting (state[0] == ListenState && state[1] == SynSentState) +#define leftEstablished (state[0] == EstState) +#define rightEstablished (state[1] == EstState) +#define leftClosed (state[0] == ClosedState) + +proctype TCP(chan snd, rcv; int i) { + pids[i] = _pid; +CLOSED: + state[i] = ClosedState; + do + /* Passive open */ + :: goto LISTEN; + /* Active open */ + :: snd ! SYN; goto SYN_SENT; + /* Terminate */ + :: goto end; + od +LISTEN: + state[i] = ListenState; + do + :: rcv ? SYN -> + atomic { + snd ! SYN; + snd ! ACK; + goto SYN_RECEIVED; + } + /* Simultaneous LISTEN */ + :: rcv ? _ -> skip; + :: timeout -> goto CLOSED; + od +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? SYN; + if + /* Standard behavior */ + :: rcv ? ACK -> snd ! ACK; goto ESTABLISHED; + /* Simultaneous open */ + :: snd ! ACK; goto SYN_RECEIVED; + fi + :: rcv ? ACK; + do + :: rcv ? SYN -> + snd ! ACK; + goto ESTABLISHED; + :: rcv ? _ -> skip; + od + :: rcv ? _ -> skip; + :: timeout -> goto CLOSED; /* Timeout */ + od +SYN_RECEIVED: + state[i] = SynRecState; + do + :: rcv ? ACK -> goto ESTABLISHED; + :: rcv ? _ -> skip; + od +ESTABLISHED: + state[i] = EstState; + do + /* Close - initiator sequence */ + :: snd ! FIN; goto FIN_WAIT_1; + /* Close - responder sequence */ + :: rcv ? FIN -> + snd ! ACK; + goto CLOSE_WAIT; + :: rcv ? _ -> skip; + od +FIN_WAIT_1: + state[i] = FinW1State; + do + /* Simultaneous close */ + :: rcv ? FIN -> + snd ! ACK; + goto CLOSING; + /* Standard close */ + :: rcv ? ACK -> goto FIN_WAIT_2; + :: rcv ? _ -> skip; + od +CLOSE_WAIT: + state[i] = CloseWaitState; + do + :: snd ! FIN; goto LAST_ACK; + :: rcv ? _ -> skip; + od +FIN_WAIT_2: + state[i] = FinW2State; + do + :: rcv ? FIN -> + snd ! ACK; + goto TIME_WAIT; + :: rcv ? _ -> skip; + od +CLOSING: + state[i] = ClosingState; + do + :: rcv ? ACK -> goto TIME_WAIT; + :: rcv ? _ -> skip; + od +LAST_ACK: + state[i] = LastAckState; + do + :: rcv ? ACK -> goto CLOSED; + :: rcv ? _ -> skip; + od +TIME_WAIT: + state[i] = TimeWaitState; + goto CLOSED; +end: + state[i] = EndState; +} + +init { + state[0] = ClosedState; + state[1] = ClosedState; + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); +} + +/* liveness: simultanous open */ +ltl phi4 { + always ( + (state[0] == SynSentState && + state[1] == SynSentState) + + implies + + ((eventually state[0] == EstState) && + (eventually state[1] == EstState))) +} diff --git a/tests/tcp/attempt1/tcp-phi4.pml.trail b/tests/tcp/attempt1/tcp-phi4.pml.trail new file mode 100644 index 0000000..cf64d44 --- /dev/null +++ b/tests/tcp/attempt1/tcp-phi4.pml.trail @@ -0,0 +1,157 @@ +-2:2:-2 +-4:-4:-4 +1:0:122 +2:1:114 +3:0:122 +4:1:115 +5:0:122 +6:1:116 +7:0:122 +8:1:117 +9:0:122 +10:3:0 +11:0:122 +12:3:1 +13:0:122 +14:3:2 +15:0:122 +16:3:9 +17:0:122 +18:2:0 +19:0:122 +20:2:1 +21:0:122 +22:2:2 +23:0:122 +24:2:9 +25:0:122 +26:3:17 +27:0:122 +28:3:1 +29:0:122 +30:3:3 +31:0:122 +32:3:22 +33:0:122 +34:2:10 +35:0:122 +36:2:11 +37:2:12 +38:0:122 +39:3:23 +40:0:122 +41:3:24 +42:0:122 +43:3:25 +44:0:122 +45:3:55 +46:0:122 +47:3:56 +48:0:122 +49:3:66 +50:0:122 +51:2:47 +52:0:122 +53:2:48 +54:0:122 +55:2:55 +56:0:122 +57:2:56 +58:0:122 +59:3:67 +60:0:122 +61:3:68 +62:0:122 +63:3:94 +64:0:122 +65:2:66 +66:0:122 +67:2:67 +68:0:122 +69:2:68 +70:0:122 +71:3:95 +72:0:122 +73:3:110 +74:0:122 +75:3:1 +76:0:122 +77:3:2 +78:0:122 +79:2:94 +80:0:122 +81:2:95 +82:0:122 +83:2:110 +84:0:122 +85:2:1 +86:0:122 +87:2:3 +88:0:122 +89:3:9 +90:0:122 +91:3:10 +92:0:122 +93:3:11 +94:3:12 +95:0:122 +96:3:47 +97:0:122 +98:2:22 +99:0:122 +100:2:23 +101:0:122 +102:2:24 +103:0:122 +104:2:25 +105:0:122 +106:3:48 +107:0:122 +108:3:55 +109:0:122 +110:3:56 +111:0:122 +112:2:55 +113:0:122 +114:2:56 +115:0:122 +116:2:66 +117:0:122 +118:3:66 +119:0:122 +120:3:67 +121:0:122 +122:3:68 +123:0:122 +124:2:67 +125:0:122 +126:2:68 +127:0:122 +128:2:94 +129:0:122 +130:3:94 +131:0:122 +132:3:95 +133:0:122 +134:3:110 +135:0:122 +136:3:1 +137:0:122 +138:3:3 +139:0:122 +140:3:22 +141:0:122 +142:2:95 +143:0:122 +144:2:110 +145:0:122 +146:2:1 +147:0:122 +148:2:3 +149:0:122 +150:3:23 +151:0:122 +152:3:27 +153:0:122 +154:2:22 +155:0:119 diff --git a/tests/tcp/attempt1/tcp-phi5.pml b/tests/tcp/attempt1/tcp-phi5.pml new file mode 100644 index 0000000..3b65921 --- /dev/null +++ b/tests/tcp/attempt1/tcp-phi5.pml @@ -0,0 +1,152 @@ +mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN } + +chan AtoB = [2] of { mtype }; +chan BtoA = [2] of { mtype }; + +int state[2]; +int pids[2]; + +#define ClosedState 0 +#define ListenState 1 +#define SynSentState 2 +#define SynRecState 3 +#define EstState 4 +#define FinW1State 5 +#define CloseWaitState 6 +#define FinW2State 7 +#define ClosingState 8 +#define LastAckState 9 +#define TimeWaitState 10 +#define EndState -1 + +#define leftConnecting (state[0] == ListenState && state[1] == SynSentState) +#define leftEstablished (state[0] == EstState) +#define rightEstablished (state[1] == EstState) +#define leftClosed (state[0] == ClosedState) + +proctype TCP(chan snd, rcv; int i) { + pids[i] = _pid; +CLOSED: + state[i] = ClosedState; + do + /* Passive open */ + :: goto LISTEN; + /* Active open */ + :: snd ! SYN; goto SYN_SENT; + /* Terminate */ + :: goto end; + od +LISTEN: + state[i] = ListenState; + do + :: rcv ? SYN -> + atomic { + snd ! SYN; + snd ! ACK; + goto SYN_RECEIVED; + } + /* Simultaneous LISTEN */ + :: rcv ? _ -> skip; + :: timeout -> goto CLOSED; + od +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? SYN; + if + /* Standard behavior */ + :: rcv ? ACK -> snd ! ACK; goto ESTABLISHED; + /* Simultaneous open */ + :: snd ! ACK; goto SYN_RECEIVED; + fi + :: rcv ? ACK; + do + :: rcv ? SYN -> + snd ! ACK; + goto ESTABLISHED; + :: rcv ? _ -> skip; + od + :: rcv ? _ -> skip; + :: timeout -> goto CLOSED; /* Timeout */ + od +SYN_RECEIVED: + state[i] = SynRecState; + do + :: rcv ? ACK -> goto ESTABLISHED; + :: rcv ? _ -> skip; + od +ESTABLISHED: + state[i] = EstState; + do + /* Close - initiator sequence */ + :: snd ! FIN; goto FIN_WAIT_1; + /* Close - responder sequence */ + :: rcv ? FIN -> + snd ! ACK; + goto CLOSE_WAIT; + :: rcv ? _ -> skip; + od +FIN_WAIT_1: + state[i] = FinW1State; + do + /* Simultaneous close */ + :: rcv ? FIN -> + snd ! ACK; + goto CLOSING; + /* Standard close */ + :: rcv ? ACK -> goto FIN_WAIT_2; + :: rcv ? _ -> skip; + od +CLOSE_WAIT: + state[i] = CloseWaitState; + do + :: snd ! FIN; goto LAST_ACK; + :: rcv ? _ -> skip; + od +FIN_WAIT_2: + state[i] = FinW2State; + do + :: rcv ? FIN -> + snd ! ACK; + goto TIME_WAIT; + :: rcv ? _ -> skip; + od +CLOSING: + state[i] = ClosingState; + do + :: rcv ? ACK -> goto TIME_WAIT; + :: rcv ? _ -> skip; + od +LAST_ACK: + state[i] = LastAckState; + do + :: rcv ? ACK -> goto CLOSED; + :: rcv ? _ -> skip; + od +TIME_WAIT: + state[i] = TimeWaitState; + goto CLOSED; +end: + state[i] = EndState; +} + +init { + state[0] = ClosedState; + state[1] = ClosedState; + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); +} + +/* liveness: SYN_RECEIVED resolution*/ +ltl phi5 { + always ( + (state[0] == SynRecState) + implies ( + eventually ( + (state[0] == EstState || + state[0] == FinW1State || + state[0] == ClosedState) + ) + ) + ) +} diff --git a/tests/tcp/tcp-phi5.pml.trail b/tests/tcp/attempt1/tcp-phi5.pml.trail similarity index 100% rename from tests/tcp/tcp-phi5.pml.trail rename to tests/tcp/attempt1/tcp-phi5.pml.trail diff --git a/tests/tcp/attempt1/tcp-phi6.pml b/tests/tcp/attempt1/tcp-phi6.pml new file mode 100644 index 0000000..d0cf9a0 --- /dev/null +++ b/tests/tcp/attempt1/tcp-phi6.pml @@ -0,0 +1,148 @@ +mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN } + +chan AtoB = [2] of { mtype }; +chan BtoA = [2] of { mtype }; + +int state[2]; +int pids[2]; + +#define ClosedState 0 +#define ListenState 1 +#define SynSentState 2 +#define SynRecState 3 +#define EstState 4 +#define FinW1State 5 +#define CloseWaitState 6 +#define FinW2State 7 +#define ClosingState 8 +#define LastAckState 9 +#define TimeWaitState 10 +#define EndState -1 + +#define leftConnecting (state[0] == ListenState && state[1] == SynSentState) +#define leftEstablished (state[0] == EstState) +#define rightEstablished (state[1] == EstState) +#define leftClosed (state[0] == ClosedState) + +proctype TCP(chan snd, rcv; int i) { + pids[i] = _pid; +CLOSED: + state[i] = ClosedState; + do + /* Passive open */ + :: goto LISTEN; + /* Active open */ + :: snd ! SYN; goto SYN_SENT; + /* Terminate */ + :: goto end; + od +LISTEN: + state[i] = ListenState; + do + :: rcv ? SYN -> + atomic { + snd ! SYN; + snd ! ACK; + goto SYN_RECEIVED; + } + /* Simultaneous LISTEN */ + :: rcv ? _ -> skip; + :: timeout -> goto CLOSED; + od +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? SYN; + if + /* Standard behavior */ + :: rcv ? ACK -> snd ! ACK; goto ESTABLISHED; + /* Simultaneous open */ + :: snd ! ACK; goto SYN_RECEIVED; + fi + :: rcv ? ACK; + do + :: rcv ? SYN -> + snd ! ACK; + goto ESTABLISHED; + :: rcv ? _ -> skip; + od + :: rcv ? _ -> skip; + :: timeout -> goto CLOSED; /* Timeout */ + od +SYN_RECEIVED: + state[i] = SynRecState; + do + :: rcv ? ACK -> goto ESTABLISHED; + :: rcv ? _ -> skip; + od +ESTABLISHED: + state[i] = EstState; + do + /* Close - initiator sequence */ + :: snd ! FIN; goto FIN_WAIT_1; + /* Close - responder sequence */ + :: rcv ? FIN -> + snd ! ACK; + goto CLOSE_WAIT; + :: rcv ? _ -> skip; + od +FIN_WAIT_1: + state[i] = FinW1State; + do + /* Simultaneous close */ + :: rcv ? FIN -> + snd ! ACK; + goto CLOSING; + /* Standard close */ + :: rcv ? ACK -> goto FIN_WAIT_2; + :: rcv ? _ -> skip; + od +CLOSE_WAIT: + state[i] = CloseWaitState; + do + :: snd ! FIN; goto LAST_ACK; + :: rcv ? _ -> skip; + od +FIN_WAIT_2: + state[i] = FinW2State; + do + :: rcv ? FIN -> + snd ! ACK; + goto TIME_WAIT; + :: rcv ? _ -> skip; + od +CLOSING: + state[i] = ClosingState; + do + :: rcv ? ACK -> goto TIME_WAIT; + :: rcv ? _ -> skip; + od +LAST_ACK: + state[i] = LastAckState; + do + :: rcv ? ACK -> goto CLOSED; + :: rcv ? _ -> skip; + od +TIME_WAIT: + state[i] = TimeWaitState; + goto CLOSED; +end: + state[i] = EndState; +} + +init { + state[0] = ClosedState; + state[1] = ClosedState; + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); +} + +/* safety: strict closing transitions */ +ltl phi6 { + always ( + (state[0] == ClosingState) + implies + (next (state[0] == ClosingState || + state[0] == ClosedState)) + ) +} diff --git a/tests/tcp/attempt1/tcp-phi6.pml.trail b/tests/tcp/attempt1/tcp-phi6.pml.trail new file mode 100644 index 0000000..1840bcf --- /dev/null +++ b/tests/tcp/attempt1/tcp-phi6.pml.trail @@ -0,0 +1,88 @@ +-2:2:-2 +-4:-4:-4 +1:0:121 +2:1:114 +3:0:121 +4:1:115 +5:0:121 +6:1:116 +7:0:121 +8:1:117 +9:0:121 +10:3:0 +11:0:121 +12:3:1 +13:0:121 +14:3:2 +15:0:121 +16:3:9 +17:0:121 +18:2:0 +19:0:121 +20:2:1 +21:0:121 +22:2:2 +23:0:121 +24:2:9 +25:0:121 +26:3:17 +27:0:121 +28:3:1 +29:0:121 +30:3:3 +31:0:121 +32:3:22 +33:0:121 +34:2:10 +35:0:121 +36:2:11 +37:2:12 +38:0:121 +39:3:23 +40:0:121 +41:3:24 +42:0:121 +43:3:25 +44:0:121 +45:3:55 +46:0:121 +47:3:56 +48:0:121 +49:3:66 +50:0:121 +51:2:47 +52:0:121 +53:2:48 +54:0:121 +55:2:55 +56:0:121 +57:2:56 +58:0:121 +59:3:67 +60:0:121 +61:3:68 +62:0:121 +63:3:94 +64:0:121 +65:2:66 +66:0:121 +67:2:67 +68:0:121 +69:2:68 +70:0:121 +71:3:95 +72:0:121 +73:3:110 +74:0:121 +75:3:1 +76:0:121 +77:3:2 +78:0:121 +79:3:9 +80:0:121 +81:2:94 +82:0:121 +83:2:95 +84:0:119 +85:2:110 +86:0:126 diff --git a/tests/tcp/attempt1/tcp.pml b/tests/tcp/attempt1/tcp.pml new file mode 100644 index 0000000..1792fbe --- /dev/null +++ b/tests/tcp/attempt1/tcp.pml @@ -0,0 +1,138 @@ +mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN } + +chan AtoB = [2] of { mtype }; +chan BtoA = [2] of { mtype }; + +int state[2]; +int pids[2]; + +#define ClosedState 0 +#define ListenState 1 +#define SynSentState 2 +#define SynRecState 3 +#define EstState 4 +#define FinW1State 5 +#define CloseWaitState 6 +#define FinW2State 7 +#define ClosingState 8 +#define LastAckState 9 +#define TimeWaitState 10 +#define EndState -1 + +#define leftConnecting (state[0] == ListenState && state[1] == SynSentState) +#define leftEstablished (state[0] == EstState) +#define rightEstablished (state[1] == EstState) +#define leftClosed (state[0] == ClosedState) + +proctype TCP(chan snd, rcv; int i) { + pids[i] = _pid; +CLOSED: + state[i] = ClosedState; + do + /* Passive open */ + :: goto LISTEN; + /* Active open */ + :: snd ! SYN; goto SYN_SENT; + /* Terminate */ + :: goto end; + od +LISTEN: + state[i] = ListenState; + do + :: rcv ? SYN -> + atomic { + snd ! SYN; + snd ! ACK; + goto SYN_RECEIVED; + } + /* Simultaneous LISTEN */ + :: rcv ? _ -> skip; + :: timeout -> goto CLOSED; + od +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? SYN; + if + /* Standard behavior */ + :: rcv ? ACK -> snd ! ACK; goto ESTABLISHED; + /* Simultaneous open */ + :: snd ! ACK; goto SYN_RECEIVED; + fi + :: rcv ? ACK; + do + :: rcv ? SYN -> + snd ! ACK; + goto ESTABLISHED; + :: rcv ? _ -> skip; + od + :: rcv ? _ -> skip; + :: timeout -> goto CLOSED; /* Timeout */ + od +SYN_RECEIVED: + state[i] = SynRecState; + do + :: rcv ? ACK -> goto ESTABLISHED; + :: rcv ? _ -> skip; + od +ESTABLISHED: + state[i] = EstState; + do + /* Close - initiator sequence */ + :: snd ! FIN; goto FIN_WAIT_1; + /* Close - responder sequence */ + :: rcv ? FIN -> + snd ! ACK; + goto CLOSE_WAIT; + :: rcv ? _ -> skip; + od +FIN_WAIT_1: + state[i] = FinW1State; + do + /* Simultaneous close */ + :: rcv ? FIN -> + snd ! ACK; + goto CLOSING; + /* Standard close */ + :: rcv ? ACK -> goto FIN_WAIT_2; + :: rcv ? _ -> skip; + od +CLOSE_WAIT: + state[i] = CloseWaitState; + do + :: snd ! FIN; goto LAST_ACK; + :: rcv ? _ -> skip; + od +FIN_WAIT_2: + state[i] = FinW2State; + do + :: rcv ? FIN -> + snd ! ACK; + goto TIME_WAIT; + :: rcv ? _ -> skip; + od +CLOSING: + state[i] = ClosingState; + do + :: rcv ? ACK -> goto TIME_WAIT; + :: rcv ? _ -> skip; + od +LAST_ACK: + state[i] = LastAckState; + do + :: rcv ? ACK -> goto CLOSED; + :: rcv ? _ -> skip; + od +TIME_WAIT: + state[i] = TimeWaitState; + goto CLOSED; +end: + state[i] = EndState; +} + +init { + state[0] = ClosedState; + state[1] = ClosedState; + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); +} diff --git a/tests/tcp/pan b/tests/tcp/pan index b304ec152edf6fb9c5094342c3df7a1f1d4f051b..79a5e06ef9bd3a520a1ae7b89515240cd4a41ed6 100755 GIT binary patch literal 110664 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 ap0t*|E!g>>wgcB{)z8d{<_u) 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 literal 110592 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 Ko)^KpH2)3z-5{<2 diff --git a/tests/tcp/props/phi7.pml b/tests/tcp/props/phi7.pml new file mode 100644 index 0000000..c179125 --- /dev/null +++ b/tests/tcp/props/phi7.pml @@ -0,0 +1,9 @@ +/* liveness: simultaneous close resolution */ +ltl phi7 { + always ( + (state[0] == FinW1State && state[1] == FinW1State) + implies + (eventually (state[0] == ClosedState) && + eventually (state[1] == ClosedState)) + ) +} diff --git a/tests/tcp/props/phi8.pml b/tests/tcp/props/phi8.pml new file mode 100644 index 0000000..361d567 --- /dev/null +++ b/tests/tcp/props/phi8.pml @@ -0,0 +1,6 @@ +/* liveness: active close eventually terminates */ +ltl phi8 { + always ( + (state[0] == FinW1State) implies (eventually (state[0] == ClosedState)) + ) +} diff --git a/tests/tcp/props/phi9.pml b/tests/tcp/props/phi9.pml new file mode 100644 index 0000000..06bcd20 --- /dev/null +++ b/tests/tcp/props/phi9.pml @@ -0,0 +1,8 @@ +/* safety: handshake cannot be bypassed */ +ltl phi9 { + always ( + (state[0] == ListenState) + implies + !(next (state[0] == EstState)) + ) +} diff --git a/tests/tcp/tcp-phi1.pml b/tests/tcp/tcp-phi1.pml index a95ba99..5e8fc4f 100644 --- a/tests/tcp/tcp-phi1.pml +++ b/tests/tcp/tcp-phi1.pml @@ -1,10 +1,9 @@ -mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN } +mtype = { SYN, FIN, ACK } chan AtoB = [2] of { mtype }; chan BtoA = [2] of { mtype }; int state[2]; -int pids[2]; #define ClosedState 0 #define ListenState 1 @@ -17,127 +16,128 @@ int pids[2]; #define ClosingState 8 #define LastAckState 9 #define TimeWaitState 10 -#define EndState -1 - -#define leftConnecting (state[0] == ListenState && state[1] == SynSentState) -#define leftEstablished (state[0] == EstState) -#define rightEstablished (state[1] == EstState) -#define leftClosed (state[0] == ClosedState) proctype TCP(chan snd, rcv; int i) { - pids[i] = _pid; + mtype msg; CLOSED: - state[i] = ClosedState; - do - /* Passive open */ - :: goto LISTEN; - /* Active open */ - :: snd ! SYN; goto SYN_SENT; - /* Terminate */ - :: goto end; - od + state[i] = ClosedState; + if + :: goto LISTEN; + :: snd ! SYN; goto SYN_SENT; + fi; + LISTEN: - state[i] = ListenState; - do - :: rcv ? SYN -> - atomic { - snd ! SYN; - snd ! ACK; - goto SYN_RECEIVED; - } - /* Simultaneous LISTEN */ - :: rcv ? _ -> skip; - :: timeout -> goto CLOSED; - od -SYN_SENT: - state[i] = SynSentState; - do - :: rcv ? SYN; - if - /* Standard behavior */ - :: rcv ? ACK -> snd ! ACK; goto ESTABLISHED; - /* Simultaneous open */ - :: snd ! ACK; goto SYN_RECEIVED; - fi - :: rcv ? ACK; + state[i] = ListenState; do - :: rcv ? SYN -> - snd ! ACK; - goto ESTABLISHED; - :: rcv ? _ -> skip; - od - :: rcv ? _ -> skip; - :: timeout -> goto CLOSED; /* Timeout */ - od + :: rcv ? msg -> + if + :: msg == SYN -> snd ! SYN; snd ! ACK; goto SYN_RECEIVED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto SYN_RECEIVED; + :: msg == ACK -> + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + SYN_RECEIVED: - state[i] = SynRecState; - do - :: rcv ? ACK -> goto ESTABLISHED; - :: rcv ? _ -> skip; - od + state[i] = SynRecState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + ESTABLISHED: - state[i] = EstState; - do - /* Close - initiator sequence */ - :: snd ! FIN; goto FIN_WAIT_1; - /* Close - responder sequence */ - :: rcv ? FIN -> - snd ! ACK; - goto CLOSE_WAIT; - :: rcv ? _ -> skip; - od + state[i] = EstState; + do + :: snd ! FIN; goto FIN_WAIT_1; + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSE_WAIT; + :: else -> skip; + fi + od; + FIN_WAIT_1: - state[i] = FinW1State; - do - /* Simultaneous close */ - :: rcv ? FIN -> - snd ! ACK; - goto CLOSING; - /* Standard close */ - :: rcv ? ACK -> goto FIN_WAIT_2; - :: rcv ? _ -> skip; - od -CLOSE_WAIT: - state[i] = CloseWaitState; - do - :: snd ! FIN; goto LAST_ACK; - :: rcv ? _ -> skip; - od + state[i] = FinW1State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSING; + :: msg == ACK -> goto FIN_WAIT_2; + :: else -> skip; + fi + od; + FIN_WAIT_2: - state[i] = FinW2State; - do - :: rcv ? FIN -> - snd ! ACK; - goto TIME_WAIT; - :: rcv ? _ -> skip; - od + state[i] = FinW2State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto TIME_WAIT; + :: else -> skip; + fi + od; + CLOSING: - state[i] = ClosingState; - do - :: rcv ? ACK -> goto TIME_WAIT; - :: rcv ? _ -> skip; - od + state[i] = ClosingState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto TIME_WAIT; + :: else -> skip; + fi + od; + +CLOSE_WAIT: + state[i] = CloseWaitState; + snd ! FIN; goto LAST_ACK; + LAST_ACK: - state[i] = LastAckState; - do - :: rcv ? ACK -> goto CLOSED; - :: rcv ? _ -> skip; - od + state[i] = LastAckState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto CLOSED; + :: else -> skip; + fi + od; + TIME_WAIT: - state[i] = TimeWaitState; - goto CLOSED; -end: - state[i] = EndState; + state[i] = TimeWaitState; + goto CLOSED; } init { - state[0] = ClosedState; - state[1] = ClosedState; - run TCP(AtoB, BtoA, 0); - run TCP(BtoA, AtoB, 1); + state[0] = ClosedState; + state[1] = ClosedState; + atomic { + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); + } } -/* safety: half-open prevention */ ltl phi1 { - always ( leftClosed implies !rightEstablished ) + always ( (state[0] == ClosedState) implies !(state[1] == EstState) ) } diff --git a/tests/tcp/tcp-phi2.pml b/tests/tcp/tcp-phi2.pml index 620854f..6392dd0 100644 --- a/tests/tcp/tcp-phi2.pml +++ b/tests/tcp/tcp-phi2.pml @@ -1,10 +1,9 @@ -mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN } +mtype = { SYN, FIN, ACK } chan AtoB = [2] of { mtype }; chan BtoA = [2] of { mtype }; int state[2]; -int pids[2]; #define ClosedState 0 #define ListenState 1 @@ -17,127 +16,130 @@ int pids[2]; #define ClosingState 8 #define LastAckState 9 #define TimeWaitState 10 -#define EndState -1 - -#define leftConnecting (state[0] == ListenState && state[1] == SynSentState) -#define leftEstablished (state[0] == EstState) -#define rightEstablished (state[1] == EstState) -#define leftClosed (state[0] == ClosedState) proctype TCP(chan snd, rcv; int i) { - pids[i] = _pid; + mtype msg; CLOSED: - state[i] = ClosedState; - do - /* Passive open */ - :: goto LISTEN; - /* Active open */ - :: snd ! SYN; goto SYN_SENT; - /* Terminate */ - :: goto end; - od + state[i] = ClosedState; + if + :: goto LISTEN; + :: snd ! SYN; goto SYN_SENT; + fi; + LISTEN: - state[i] = ListenState; - do - :: rcv ? SYN -> - atomic { - snd ! SYN; - snd ! ACK; - goto SYN_RECEIVED; - } - /* Simultaneous LISTEN */ - :: rcv ? _ -> skip; - :: timeout -> goto CLOSED; - od -SYN_SENT: - state[i] = SynSentState; - do - :: rcv ? SYN; - if - /* Standard behavior */ - :: rcv ? ACK -> snd ! ACK; goto ESTABLISHED; - /* Simultaneous open */ - :: snd ! ACK; goto SYN_RECEIVED; - fi - :: rcv ? ACK; + state[i] = ListenState; do - :: rcv ? SYN -> - snd ! ACK; - goto ESTABLISHED; - :: rcv ? _ -> skip; - od - :: rcv ? _ -> skip; - :: timeout -> goto CLOSED; /* Timeout */ - od + :: rcv ? msg -> + if + :: msg == SYN -> snd ! SYN; snd ! ACK; goto SYN_RECEIVED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto SYN_RECEIVED; + :: msg == ACK -> + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + SYN_RECEIVED: - state[i] = SynRecState; - do - :: rcv ? ACK -> goto ESTABLISHED; - :: rcv ? _ -> skip; - od + state[i] = SynRecState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + ESTABLISHED: - state[i] = EstState; - do - /* Close - initiator sequence */ - :: snd ! FIN; goto FIN_WAIT_1; - /* Close - responder sequence */ - :: rcv ? FIN -> - snd ! ACK; - goto CLOSE_WAIT; - :: rcv ? _ -> skip; - od + state[i] = EstState; + do + :: snd ! FIN; goto FIN_WAIT_1; + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSE_WAIT; + :: else -> skip; + fi + od; + FIN_WAIT_1: - state[i] = FinW1State; - do - /* Simultaneous close */ - :: rcv ? FIN -> - snd ! ACK; - goto CLOSING; - /* Standard close */ - :: rcv ? ACK -> goto FIN_WAIT_2; - :: rcv ? _ -> skip; - od -CLOSE_WAIT: - state[i] = CloseWaitState; - do - :: snd ! FIN; goto LAST_ACK; - :: rcv ? _ -> skip; - od + state[i] = FinW1State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSING; + :: msg == ACK -> goto FIN_WAIT_2; + :: else -> skip; + fi + od; + FIN_WAIT_2: - state[i] = FinW2State; - do - :: rcv ? FIN -> - snd ! ACK; - goto TIME_WAIT; - :: rcv ? _ -> skip; - od + state[i] = FinW2State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto TIME_WAIT; + :: else -> skip; + fi + od; + CLOSING: - state[i] = ClosingState; - do - :: rcv ? ACK -> goto TIME_WAIT; - :: rcv ? _ -> skip; - od + state[i] = ClosingState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto TIME_WAIT; + :: else -> skip; + fi + od; + +CLOSE_WAIT: + state[i] = CloseWaitState; + snd ! FIN; goto LAST_ACK; + LAST_ACK: - state[i] = LastAckState; - do - :: rcv ? ACK -> goto CLOSED; - :: rcv ? _ -> skip; - od + state[i] = LastAckState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto CLOSED; + :: else -> skip; + fi + od; + TIME_WAIT: - state[i] = TimeWaitState; - goto CLOSED; -end: - state[i] = EndState; + state[i] = TimeWaitState; + goto CLOSED; } init { - state[0] = ClosedState; - state[1] = ClosedState; - run TCP(AtoB, BtoA, 0); - run TCP(BtoA, AtoB, 1); + state[0] = ClosedState; + state[1] = ClosedState; + atomic { + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); + } } /* liveness: verifying connection establishment */ ltl phi2 { ( (always ( eventually ( state[0] == 1 && state[1] == 2 ) ) ) implies ( eventually ( state[0] == 4 ) ) ) +} diff --git a/tests/tcp/tcp-phi3.pml b/tests/tcp/tcp-phi3.pml index 45f6418..3e11967 100644 --- a/tests/tcp/tcp-phi3.pml +++ b/tests/tcp/tcp-phi3.pml @@ -1,10 +1,9 @@ -mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN } +mtype = { SYN, FIN, ACK } chan AtoB = [2] of { mtype }; chan BtoA = [2] of { mtype }; int state[2]; -int pids[2]; #define ClosedState 0 #define ListenState 1 @@ -17,124 +16,126 @@ int pids[2]; #define ClosingState 8 #define LastAckState 9 #define TimeWaitState 10 -#define EndState -1 - -#define leftConnecting (state[0] == ListenState && state[1] == SynSentState) -#define leftEstablished (state[0] == EstState) -#define rightEstablished (state[1] == EstState) -#define leftClosed (state[0] == ClosedState) proctype TCP(chan snd, rcv; int i) { - pids[i] = _pid; + mtype msg; CLOSED: - state[i] = ClosedState; - do - /* Passive open */ - :: goto LISTEN; - /* Active open */ - :: snd ! SYN; goto SYN_SENT; - /* Terminate */ - :: goto end; - od + state[i] = ClosedState; + if + :: goto LISTEN; + :: snd ! SYN; goto SYN_SENT; + fi; + LISTEN: - state[i] = ListenState; - do - :: rcv ? SYN -> - atomic { - snd ! SYN; - snd ! ACK; - goto SYN_RECEIVED; - } - /* Simultaneous LISTEN */ - :: rcv ? _ -> skip; - :: timeout -> goto CLOSED; - od -SYN_SENT: - state[i] = SynSentState; - do - :: rcv ? SYN; - if - /* Standard behavior */ - :: rcv ? ACK -> snd ! ACK; goto ESTABLISHED; - /* Simultaneous open */ - :: snd ! ACK; goto SYN_RECEIVED; - fi - :: rcv ? ACK; + state[i] = ListenState; do - :: rcv ? SYN -> - snd ! ACK; - goto ESTABLISHED; - :: rcv ? _ -> skip; - od - :: rcv ? _ -> skip; - :: timeout -> goto CLOSED; /* Timeout */ - od + :: rcv ? msg -> + if + :: msg == SYN -> snd ! SYN; snd ! ACK; goto SYN_RECEIVED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto SYN_RECEIVED; + :: msg == ACK -> + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + SYN_RECEIVED: - state[i] = SynRecState; - do - :: rcv ? ACK -> goto ESTABLISHED; - :: rcv ? _ -> skip; - od + state[i] = SynRecState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + ESTABLISHED: - state[i] = EstState; - do - /* Close - initiator sequence */ - :: snd ! FIN; goto FIN_WAIT_1; - /* Close - responder sequence */ - :: rcv ? FIN -> - snd ! ACK; - goto CLOSE_WAIT; - :: rcv ? _ -> skip; - od + state[i] = EstState; + do + :: snd ! FIN; goto FIN_WAIT_1; + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSE_WAIT; + :: else -> skip; + fi + od; + FIN_WAIT_1: - state[i] = FinW1State; - do - /* Simultaneous close */ - :: rcv ? FIN -> - snd ! ACK; - goto CLOSING; - /* Standard close */ - :: rcv ? ACK -> goto FIN_WAIT_2; - :: rcv ? _ -> skip; - od -CLOSE_WAIT: - state[i] = CloseWaitState; - do - :: snd ! FIN; goto LAST_ACK; - :: rcv ? _ -> skip; - od + state[i] = FinW1State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSING; + :: msg == ACK -> goto FIN_WAIT_2; + :: else -> skip; + fi + od; + FIN_WAIT_2: - state[i] = FinW2State; - do - :: rcv ? FIN -> - snd ! ACK; - goto TIME_WAIT; - :: rcv ? _ -> skip; - od + state[i] = FinW2State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto TIME_WAIT; + :: else -> skip; + fi + od; + CLOSING: - state[i] = ClosingState; - do - :: rcv ? ACK -> goto TIME_WAIT; - :: rcv ? _ -> skip; - od + state[i] = ClosingState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto TIME_WAIT; + :: else -> skip; + fi + od; + +CLOSE_WAIT: + state[i] = CloseWaitState; + snd ! FIN; goto LAST_ACK; + LAST_ACK: - state[i] = LastAckState; - do - :: rcv ? ACK -> goto CLOSED; - :: rcv ? _ -> skip; - od + state[i] = LastAckState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto CLOSED; + :: else -> skip; + fi + od; + TIME_WAIT: - state[i] = TimeWaitState; - goto CLOSED; -end: - state[i] = EndState; + state[i] = TimeWaitState; + goto CLOSED; } init { - state[0] = ClosedState; - state[1] = ClosedState; - run TCP(AtoB, BtoA, 0); - run TCP(BtoA, AtoB, 1); + state[0] = ClosedState; + state[1] = ClosedState; + atomic { + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); + } } /* liveness: no infinite stalls/deadlocks */ diff --git a/tests/tcp/tcp-phi4.pml b/tests/tcp/tcp-phi4.pml index b34fa36..038c1b4 100644 --- a/tests/tcp/tcp-phi4.pml +++ b/tests/tcp/tcp-phi4.pml @@ -1,10 +1,9 @@ -mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN } +mtype = { SYN, FIN, ACK } chan AtoB = [2] of { mtype }; chan BtoA = [2] of { mtype }; int state[2]; -int pids[2]; #define ClosedState 0 #define ListenState 1 @@ -17,124 +16,126 @@ int pids[2]; #define ClosingState 8 #define LastAckState 9 #define TimeWaitState 10 -#define EndState -1 - -#define leftConnecting (state[0] == ListenState && state[1] == SynSentState) -#define leftEstablished (state[0] == EstState) -#define rightEstablished (state[1] == EstState) -#define leftClosed (state[0] == ClosedState) proctype TCP(chan snd, rcv; int i) { - pids[i] = _pid; + mtype msg; CLOSED: - state[i] = ClosedState; - do - /* Passive open */ - :: goto LISTEN; - /* Active open */ - :: snd ! SYN; goto SYN_SENT; - /* Terminate */ - :: goto end; - od + state[i] = ClosedState; + if + :: goto LISTEN; + :: snd ! SYN; goto SYN_SENT; + fi; + LISTEN: - state[i] = ListenState; - do - :: rcv ? SYN -> - atomic { - snd ! SYN; - snd ! ACK; - goto SYN_RECEIVED; - } - /* Simultaneous LISTEN */ - :: rcv ? _ -> skip; - :: timeout -> goto CLOSED; - od -SYN_SENT: - state[i] = SynSentState; - do - :: rcv ? SYN; - if - /* Standard behavior */ - :: rcv ? ACK -> snd ! ACK; goto ESTABLISHED; - /* Simultaneous open */ - :: snd ! ACK; goto SYN_RECEIVED; - fi - :: rcv ? ACK; + state[i] = ListenState; do - :: rcv ? SYN -> - snd ! ACK; - goto ESTABLISHED; - :: rcv ? _ -> skip; - od - :: rcv ? _ -> skip; - :: timeout -> goto CLOSED; /* Timeout */ - od + :: rcv ? msg -> + if + :: msg == SYN -> snd ! SYN; snd ! ACK; goto SYN_RECEIVED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto SYN_RECEIVED; + :: msg == ACK -> + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + SYN_RECEIVED: - state[i] = SynRecState; - do - :: rcv ? ACK -> goto ESTABLISHED; - :: rcv ? _ -> skip; - od + state[i] = SynRecState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + ESTABLISHED: - state[i] = EstState; - do - /* Close - initiator sequence */ - :: snd ! FIN; goto FIN_WAIT_1; - /* Close - responder sequence */ - :: rcv ? FIN -> - snd ! ACK; - goto CLOSE_WAIT; - :: rcv ? _ -> skip; - od + state[i] = EstState; + do + :: snd ! FIN; goto FIN_WAIT_1; + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSE_WAIT; + :: else -> skip; + fi + od; + FIN_WAIT_1: - state[i] = FinW1State; - do - /* Simultaneous close */ - :: rcv ? FIN -> - snd ! ACK; - goto CLOSING; - /* Standard close */ - :: rcv ? ACK -> goto FIN_WAIT_2; - :: rcv ? _ -> skip; - od -CLOSE_WAIT: - state[i] = CloseWaitState; - do - :: snd ! FIN; goto LAST_ACK; - :: rcv ? _ -> skip; - od + state[i] = FinW1State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSING; + :: msg == ACK -> goto FIN_WAIT_2; + :: else -> skip; + fi + od; + FIN_WAIT_2: - state[i] = FinW2State; - do - :: rcv ? FIN -> - snd ! ACK; - goto TIME_WAIT; - :: rcv ? _ -> skip; - od + state[i] = FinW2State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto TIME_WAIT; + :: else -> skip; + fi + od; + CLOSING: - state[i] = ClosingState; - do - :: rcv ? ACK -> goto TIME_WAIT; - :: rcv ? _ -> skip; - od + state[i] = ClosingState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto TIME_WAIT; + :: else -> skip; + fi + od; + +CLOSE_WAIT: + state[i] = CloseWaitState; + snd ! FIN; goto LAST_ACK; + LAST_ACK: - state[i] = LastAckState; - do - :: rcv ? ACK -> goto CLOSED; - :: rcv ? _ -> skip; - od + state[i] = LastAckState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto CLOSED; + :: else -> skip; + fi + od; + TIME_WAIT: - state[i] = TimeWaitState; - goto CLOSED; -end: - state[i] = EndState; + state[i] = TimeWaitState; + goto CLOSED; } init { - state[0] = ClosedState; - state[1] = ClosedState; - run TCP(AtoB, BtoA, 0); - run TCP(BtoA, AtoB, 1); + state[0] = ClosedState; + state[1] = ClosedState; + atomic { + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); + } } /* liveness: simultanous open */ diff --git a/tests/tcp/tcp-phi4.pml.trail b/tests/tcp/tcp-phi4.pml.trail index cf64d44..7ac32a2 100644 --- a/tests/tcp/tcp-phi4.pml.trail +++ b/tests/tcp/tcp-phi4.pml.trail @@ -1,157 +1,192 @@ -2:2:-2 -4:-4:-4 -1:0:122 -2:1:114 -3:0:122 -4:1:115 -5:0:122 -6:1:116 -7:0:122 -8:1:117 -9:0:122 -10:3:0 -11:0:122 -12:3:1 -13:0:122 -14:3:2 -15:0:122 -16:3:9 -17:0:122 -18:2:0 -19:0:122 -20:2:1 -21:0:122 -22:2:2 -23:0:122 -24:2:9 -25:0:122 -26:3:17 -27:0:122 -28:3:1 -29:0:122 -30:3:3 -31:0:122 -32:3:22 -33:0:122 -34:2:10 -35:0:122 -36:2:11 -37:2:12 -38:0:122 -39:3:23 -40:0:122 -41:3:24 -42:0:122 -43:3:25 -44:0:122 -45:3:55 -46:0:122 -47:3:56 -48:0:122 -49:3:66 -50:0:122 -51:2:47 -52:0:122 -53:2:48 -54:0:122 -55:2:55 -56:0:122 -57:2:56 -58:0:122 -59:3:67 -60:0:122 -61:3:68 -62:0:122 -63:3:94 -64:0:122 -65:2:66 -66:0:122 -67:2:67 -68:0:122 -69:2:68 -70:0:122 -71:3:95 -72:0:122 -73:3:110 -74:0:122 -75:3:1 -76:0:122 -77:3:2 -78:0:122 -79:2:94 -80:0:122 -81:2:95 -82:0:122 -83:2:110 -84:0:122 -85:2:1 -86:0:122 -87:2:3 -88:0:122 -89:3:9 -90:0:122 -91:3:10 -92:0:122 -93:3:11 -94:3:12 -95:0:122 -96:3:47 -97:0:122 -98:2:22 -99:0:122 -100:2:23 -101:0:122 -102:2:24 -103:0:122 -104:2:25 -105:0:122 -106:3:48 -107:0:122 -108:3:55 -109:0:122 -110:3:56 -111:0:122 -112:2:55 -113:0:122 -114:2:56 -115:0:122 -116:2:66 -117:0:122 -118:3:66 -119:0:122 -120:3:67 -121:0:122 -122:3:68 -123:0:122 -124:2:67 -125:0:122 -126:2:68 -127:0:122 -128:2:94 -129:0:122 -130:3:94 -131:0:122 -132:3:95 -133:0:122 -134:3:110 -135:0:122 -136:3:1 -137:0:122 -138:3:3 -139:0:122 -140:3:22 -141:0:122 -142:2:95 -143:0:122 -144:2:110 -145:0:122 -146:2:1 -147:0:122 -148:2:3 -149:0:122 -150:3:23 -151:0:122 -152:3:27 -153:0:122 -154:2:22 -155:0:119 +1:0:139 +2:1:130 +3:0:139 +4:1:131 +5:0:139 +6:1:132 +7:1:133 +8:0:139 +9:3:0 +10:0:139 +11:3:1 +12:0:139 +13:3:6 +14:0:139 +15:2:0 +16:0:139 +17:2:1 +18:0:139 +19:2:6 +20:0:139 +21:3:16 +22:0:139 +23:3:0 +24:0:139 +25:3:2 +26:0:139 +27:3:21 +28:0:139 +29:2:7 +30:0:139 +31:2:8 +32:0:139 +33:2:9 +34:0:139 +35:3:22 +36:0:139 +37:3:23 +38:0:139 +39:3:24 +40:0:139 +41:3:49 +42:0:139 +43:2:10 +44:0:139 +45:3:50 +46:0:139 +47:3:51 +48:0:139 +49:3:62 +50:0:139 +51:3:63 +52:0:139 +53:3:76 +54:0:139 +55:2:49 +56:0:139 +57:2:50 +58:0:139 +59:2:51 +60:0:139 +61:2:62 +62:0:139 +63:2:63 +64:0:139 +65:3:77 +66:0:139 +67:3:78 +68:0:139 +69:3:79 +70:0:139 +71:3:102 +72:0:139 +73:2:76 +74:0:139 +75:2:77 +76:0:139 +77:2:78 +78:0:139 +79:2:79 +80:0:139 +81:3:103 +82:0:139 +83:3:104 +84:0:139 +85:3:127 +86:0:139 +87:3:0 +88:0:139 +89:3:1 +90:0:139 +91:2:102 +92:0:139 +93:2:103 +94:0:139 +95:2:104 +96:0:139 +97:2:127 +98:0:139 +99:2:0 +100:0:139 +101:2:2 +102:0:139 +103:3:6 +104:0:139 +105:3:7 +106:0:139 +107:3:8 +108:0:139 +109:3:9 +110:0:139 +111:3:10 +112:0:139 +113:3:49 +114:0:139 +115:2:21 +116:0:139 +117:2:22 +118:0:139 +119:2:23 +120:0:139 +121:2:24 +122:0:139 +123:3:50 +124:0:139 +125:3:51 +126:0:139 +127:3:62 +128:0:139 +129:3:63 +130:0:139 +131:2:49 +132:0:139 +133:2:50 +134:0:139 +135:2:51 +136:0:139 +137:2:62 +138:0:139 +139:2:63 +140:0:139 +141:2:76 +142:0:139 +143:3:76 +144:0:139 +145:3:77 +146:0:139 +147:3:78 +148:0:139 +149:3:79 +150:0:139 +151:2:77 +152:0:139 +153:2:78 +154:0:139 +155:2:79 +156:0:139 +157:2:102 +158:0:139 +159:3:102 +160:0:139 +161:3:103 +162:0:139 +163:3:104 +164:0:139 +165:3:127 +166:0:139 +167:3:0 +168:0:139 +169:3:2 +170:0:139 +171:3:21 +172:0:139 +173:2:103 +174:0:139 +175:2:104 +176:0:139 +177:2:127 +178:0:139 +179:2:0 +180:0:139 +181:2:2 +182:0:139 +183:3:22 +184:0:139 +185:3:23 +186:0:139 +187:3:24 +188:0:139 +189:2:21 +190:0:136 diff --git a/tests/tcp/tcp-phi5.pml b/tests/tcp/tcp-phi5.pml index 3b65921..a2b6f11 100644 --- a/tests/tcp/tcp-phi5.pml +++ b/tests/tcp/tcp-phi5.pml @@ -1,10 +1,9 @@ -mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN } +mtype = { SYN, FIN, ACK } chan AtoB = [2] of { mtype }; chan BtoA = [2] of { mtype }; int state[2]; -int pids[2]; #define ClosedState 0 #define ListenState 1 @@ -17,124 +16,126 @@ int pids[2]; #define ClosingState 8 #define LastAckState 9 #define TimeWaitState 10 -#define EndState -1 - -#define leftConnecting (state[0] == ListenState && state[1] == SynSentState) -#define leftEstablished (state[0] == EstState) -#define rightEstablished (state[1] == EstState) -#define leftClosed (state[0] == ClosedState) proctype TCP(chan snd, rcv; int i) { - pids[i] = _pid; + mtype msg; CLOSED: - state[i] = ClosedState; - do - /* Passive open */ - :: goto LISTEN; - /* Active open */ - :: snd ! SYN; goto SYN_SENT; - /* Terminate */ - :: goto end; - od + state[i] = ClosedState; + if + :: goto LISTEN; + :: snd ! SYN; goto SYN_SENT; + fi; + LISTEN: - state[i] = ListenState; - do - :: rcv ? SYN -> - atomic { - snd ! SYN; - snd ! ACK; - goto SYN_RECEIVED; - } - /* Simultaneous LISTEN */ - :: rcv ? _ -> skip; - :: timeout -> goto CLOSED; - od -SYN_SENT: - state[i] = SynSentState; - do - :: rcv ? SYN; - if - /* Standard behavior */ - :: rcv ? ACK -> snd ! ACK; goto ESTABLISHED; - /* Simultaneous open */ - :: snd ! ACK; goto SYN_RECEIVED; - fi - :: rcv ? ACK; + state[i] = ListenState; do - :: rcv ? SYN -> - snd ! ACK; - goto ESTABLISHED; - :: rcv ? _ -> skip; - od - :: rcv ? _ -> skip; - :: timeout -> goto CLOSED; /* Timeout */ - od + :: rcv ? msg -> + if + :: msg == SYN -> snd ! SYN; snd ! ACK; goto SYN_RECEIVED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto SYN_RECEIVED; + :: msg == ACK -> + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + SYN_RECEIVED: - state[i] = SynRecState; - do - :: rcv ? ACK -> goto ESTABLISHED; - :: rcv ? _ -> skip; - od + state[i] = SynRecState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + ESTABLISHED: - state[i] = EstState; - do - /* Close - initiator sequence */ - :: snd ! FIN; goto FIN_WAIT_1; - /* Close - responder sequence */ - :: rcv ? FIN -> - snd ! ACK; - goto CLOSE_WAIT; - :: rcv ? _ -> skip; - od + state[i] = EstState; + do + :: snd ! FIN; goto FIN_WAIT_1; + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSE_WAIT; + :: else -> skip; + fi + od; + FIN_WAIT_1: - state[i] = FinW1State; - do - /* Simultaneous close */ - :: rcv ? FIN -> - snd ! ACK; - goto CLOSING; - /* Standard close */ - :: rcv ? ACK -> goto FIN_WAIT_2; - :: rcv ? _ -> skip; - od -CLOSE_WAIT: - state[i] = CloseWaitState; - do - :: snd ! FIN; goto LAST_ACK; - :: rcv ? _ -> skip; - od + state[i] = FinW1State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSING; + :: msg == ACK -> goto FIN_WAIT_2; + :: else -> skip; + fi + od; + FIN_WAIT_2: - state[i] = FinW2State; - do - :: rcv ? FIN -> - snd ! ACK; - goto TIME_WAIT; - :: rcv ? _ -> skip; - od + state[i] = FinW2State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto TIME_WAIT; + :: else -> skip; + fi + od; + CLOSING: - state[i] = ClosingState; - do - :: rcv ? ACK -> goto TIME_WAIT; - :: rcv ? _ -> skip; - od + state[i] = ClosingState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto TIME_WAIT; + :: else -> skip; + fi + od; + +CLOSE_WAIT: + state[i] = CloseWaitState; + snd ! FIN; goto LAST_ACK; + LAST_ACK: - state[i] = LastAckState; - do - :: rcv ? ACK -> goto CLOSED; - :: rcv ? _ -> skip; - od + state[i] = LastAckState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto CLOSED; + :: else -> skip; + fi + od; + TIME_WAIT: - state[i] = TimeWaitState; - goto CLOSED; -end: - state[i] = EndState; + state[i] = TimeWaitState; + goto CLOSED; } init { - state[0] = ClosedState; - state[1] = ClosedState; - run TCP(AtoB, BtoA, 0); - run TCP(BtoA, AtoB, 1); + state[0] = ClosedState; + state[1] = ClosedState; + atomic { + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); + } } /* liveness: SYN_RECEIVED resolution*/ diff --git a/tests/tcp/tcp-phi6.pml b/tests/tcp/tcp-phi6.pml index d0cf9a0..c2771fe 100644 --- a/tests/tcp/tcp-phi6.pml +++ b/tests/tcp/tcp-phi6.pml @@ -1,10 +1,9 @@ -mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN } +mtype = { SYN, FIN, ACK } chan AtoB = [2] of { mtype }; chan BtoA = [2] of { mtype }; int state[2]; -int pids[2]; #define ClosedState 0 #define ListenState 1 @@ -17,124 +16,126 @@ int pids[2]; #define ClosingState 8 #define LastAckState 9 #define TimeWaitState 10 -#define EndState -1 - -#define leftConnecting (state[0] == ListenState && state[1] == SynSentState) -#define leftEstablished (state[0] == EstState) -#define rightEstablished (state[1] == EstState) -#define leftClosed (state[0] == ClosedState) proctype TCP(chan snd, rcv; int i) { - pids[i] = _pid; + mtype msg; CLOSED: - state[i] = ClosedState; - do - /* Passive open */ - :: goto LISTEN; - /* Active open */ - :: snd ! SYN; goto SYN_SENT; - /* Terminate */ - :: goto end; - od + state[i] = ClosedState; + if + :: goto LISTEN; + :: snd ! SYN; goto SYN_SENT; + fi; + LISTEN: - state[i] = ListenState; - do - :: rcv ? SYN -> - atomic { - snd ! SYN; - snd ! ACK; - goto SYN_RECEIVED; - } - /* Simultaneous LISTEN */ - :: rcv ? _ -> skip; - :: timeout -> goto CLOSED; - od -SYN_SENT: - state[i] = SynSentState; - do - :: rcv ? SYN; - if - /* Standard behavior */ - :: rcv ? ACK -> snd ! ACK; goto ESTABLISHED; - /* Simultaneous open */ - :: snd ! ACK; goto SYN_RECEIVED; - fi - :: rcv ? ACK; + state[i] = ListenState; do - :: rcv ? SYN -> - snd ! ACK; - goto ESTABLISHED; - :: rcv ? _ -> skip; - od - :: rcv ? _ -> skip; - :: timeout -> goto CLOSED; /* Timeout */ - od + :: rcv ? msg -> + if + :: msg == SYN -> snd ! SYN; snd ! ACK; goto SYN_RECEIVED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto SYN_RECEIVED; + :: msg == ACK -> + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + SYN_RECEIVED: - state[i] = SynRecState; - do - :: rcv ? ACK -> goto ESTABLISHED; - :: rcv ? _ -> skip; - od + state[i] = SynRecState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + ESTABLISHED: - state[i] = EstState; - do - /* Close - initiator sequence */ - :: snd ! FIN; goto FIN_WAIT_1; - /* Close - responder sequence */ - :: rcv ? FIN -> - snd ! ACK; - goto CLOSE_WAIT; - :: rcv ? _ -> skip; - od + state[i] = EstState; + do + :: snd ! FIN; goto FIN_WAIT_1; + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSE_WAIT; + :: else -> skip; + fi + od; + FIN_WAIT_1: - state[i] = FinW1State; - do - /* Simultaneous close */ - :: rcv ? FIN -> - snd ! ACK; - goto CLOSING; - /* Standard close */ - :: rcv ? ACK -> goto FIN_WAIT_2; - :: rcv ? _ -> skip; - od -CLOSE_WAIT: - state[i] = CloseWaitState; - do - :: snd ! FIN; goto LAST_ACK; - :: rcv ? _ -> skip; - od + state[i] = FinW1State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSING; + :: msg == ACK -> goto FIN_WAIT_2; + :: else -> skip; + fi + od; + FIN_WAIT_2: - state[i] = FinW2State; - do - :: rcv ? FIN -> - snd ! ACK; - goto TIME_WAIT; - :: rcv ? _ -> skip; - od + state[i] = FinW2State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto TIME_WAIT; + :: else -> skip; + fi + od; + CLOSING: - state[i] = ClosingState; - do - :: rcv ? ACK -> goto TIME_WAIT; - :: rcv ? _ -> skip; - od + state[i] = ClosingState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto TIME_WAIT; + :: else -> skip; + fi + od; + +CLOSE_WAIT: + state[i] = CloseWaitState; + snd ! FIN; goto LAST_ACK; + LAST_ACK: - state[i] = LastAckState; - do - :: rcv ? ACK -> goto CLOSED; - :: rcv ? _ -> skip; - od + state[i] = LastAckState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto CLOSED; + :: else -> skip; + fi + od; + TIME_WAIT: - state[i] = TimeWaitState; - goto CLOSED; -end: - state[i] = EndState; + state[i] = TimeWaitState; + goto CLOSED; } init { - state[0] = ClosedState; - state[1] = ClosedState; - run TCP(AtoB, BtoA, 0); - run TCP(BtoA, AtoB, 1); + state[0] = ClosedState; + state[1] = ClosedState; + atomic { + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); + } } /* safety: strict closing transitions */ diff --git a/tests/tcp/tcp-phi6.pml.trail b/tests/tcp/tcp-phi6.pml.trail index 1840bcf..63146ef 100644 --- a/tests/tcp/tcp-phi6.pml.trail +++ b/tests/tcp/tcp-phi6.pml.trail @@ -1,88 +1,102 @@ -2:2:-2 -4:-4:-4 -1:0:121 -2:1:114 -3:0:121 -4:1:115 -5:0:121 -6:1:116 -7:0:121 -8:1:117 -9:0:121 -10:3:0 -11:0:121 -12:3:1 -13:0:121 -14:3:2 -15:0:121 -16:3:9 -17:0:121 -18:2:0 -19:0:121 -20:2:1 -21:0:121 -22:2:2 -23:0:121 -24:2:9 -25:0:121 -26:3:17 -27:0:121 -28:3:1 -29:0:121 -30:3:3 -31:0:121 -32:3:22 -33:0:121 -34:2:10 -35:0:121 -36:2:11 -37:2:12 -38:0:121 -39:3:23 -40:0:121 -41:3:24 -42:0:121 -43:3:25 -44:0:121 -45:3:55 -46:0:121 -47:3:56 -48:0:121 -49:3:66 -50:0:121 -51:2:47 -52:0:121 -53:2:48 -54:0:121 -55:2:55 -56:0:121 -57:2:56 -58:0:121 -59:3:67 -60:0:121 -61:3:68 -62:0:121 -63:3:94 -64:0:121 -65:2:66 -66:0:121 -67:2:67 -68:0:121 -69:2:68 -70:0:121 -71:3:95 -72:0:121 -73:3:110 -74:0:121 -75:3:1 -76:0:121 -77:3:2 -78:0:121 -79:3:9 -80:0:121 -81:2:94 -82:0:121 -83:2:95 -84:0:119 -85:2:110 -86:0:126 +1:0:138 +2:1:130 +3:0:138 +4:1:131 +5:0:138 +6:1:132 +7:1:133 +8:0:138 +9:3:0 +10:0:138 +11:3:1 +12:0:138 +13:3:6 +14:0:138 +15:2:0 +16:0:138 +17:2:1 +18:0:138 +19:2:6 +20:0:138 +21:3:16 +22:0:138 +23:3:0 +24:0:138 +25:3:2 +26:0:138 +27:3:21 +28:0:138 +29:2:7 +30:0:138 +31:2:8 +32:0:138 +33:2:9 +34:0:138 +35:3:22 +36:0:138 +37:3:23 +38:0:138 +39:3:24 +40:0:138 +41:3:49 +42:0:138 +43:2:10 +44:0:138 +45:3:50 +46:0:138 +47:3:51 +48:0:138 +49:3:62 +50:0:138 +51:3:63 +52:0:138 +53:3:76 +54:0:138 +55:2:49 +56:0:138 +57:2:50 +58:0:138 +59:2:51 +60:0:138 +61:2:62 +62:0:138 +63:2:63 +64:0:138 +65:3:77 +66:0:138 +67:3:78 +68:0:138 +69:3:79 +70:0:138 +71:3:102 +72:0:138 +73:2:76 +74:0:138 +75:2:77 +76:0:138 +77:2:78 +78:0:138 +79:2:79 +80:0:138 +81:3:103 +82:0:138 +83:3:104 +84:0:138 +85:3:127 +86:0:138 +87:3:0 +88:0:138 +89:3:1 +90:0:138 +91:3:6 +92:0:138 +93:2:102 +94:0:138 +95:2:103 +96:0:138 +97:2:104 +98:0:136 +99:2:127 +100:0:143 diff --git a/tests/tcp/tcp-phi7.pml b/tests/tcp/tcp-phi7.pml new file mode 100644 index 0000000..0c0e18d --- /dev/null +++ b/tests/tcp/tcp-phi7.pml @@ -0,0 +1,149 @@ +mtype = { SYN, FIN, ACK } + +chan AtoB = [2] of { mtype }; +chan BtoA = [2] of { mtype }; + +int state[2]; + +#define ClosedState 0 +#define ListenState 1 +#define SynSentState 2 +#define SynRecState 3 +#define EstState 4 +#define FinW1State 5 +#define CloseWaitState 6 +#define FinW2State 7 +#define ClosingState 8 +#define LastAckState 9 +#define TimeWaitState 10 + +proctype TCP(chan snd, rcv; int i) { + mtype msg; +CLOSED: + state[i] = ClosedState; + if + :: goto LISTEN; + :: snd ! SYN; goto SYN_SENT; + fi; + +LISTEN: + state[i] = ListenState; + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! SYN; snd ! ACK; goto SYN_RECEIVED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto SYN_RECEIVED; + :: msg == ACK -> + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +SYN_RECEIVED: + state[i] = SynRecState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +ESTABLISHED: + state[i] = EstState; + do + :: snd ! FIN; goto FIN_WAIT_1; + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSE_WAIT; + :: else -> skip; + fi + od; + +FIN_WAIT_1: + state[i] = FinW1State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSING; + :: msg == ACK -> goto FIN_WAIT_2; + :: else -> skip; + fi + od; + +FIN_WAIT_2: + state[i] = FinW2State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto TIME_WAIT; + :: else -> skip; + fi + od; + +CLOSING: + state[i] = ClosingState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto TIME_WAIT; + :: else -> skip; + fi + od; + +CLOSE_WAIT: + state[i] = CloseWaitState; + snd ! FIN; goto LAST_ACK; + +LAST_ACK: + state[i] = LastAckState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto CLOSED; + :: else -> skip; + fi + od; + +TIME_WAIT: + state[i] = TimeWaitState; + goto CLOSED; +} + +init { + state[0] = ClosedState; + state[1] = ClosedState; + atomic { + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); + } +} + +/* liveness: simultaneous close resolution */ +ltl phi7 { + always ( + (state[0] == FinW1State && state[1] == FinW1State) + implies + (eventually (state[0] == ClosedState) && + eventually (state[1] == ClosedState)) + ) +} diff --git a/tests/tcp/tcp-phi8.pml b/tests/tcp/tcp-phi8.pml new file mode 100644 index 0000000..14e264c --- /dev/null +++ b/tests/tcp/tcp-phi8.pml @@ -0,0 +1,146 @@ +mtype = { SYN, FIN, ACK } + +chan AtoB = [2] of { mtype }; +chan BtoA = [2] of { mtype }; + +int state[2]; + +#define ClosedState 0 +#define ListenState 1 +#define SynSentState 2 +#define SynRecState 3 +#define EstState 4 +#define FinW1State 5 +#define CloseWaitState 6 +#define FinW2State 7 +#define ClosingState 8 +#define LastAckState 9 +#define TimeWaitState 10 + +proctype TCP(chan snd, rcv; int i) { + mtype msg; +CLOSED: + state[i] = ClosedState; + if + :: goto LISTEN; + :: snd ! SYN; goto SYN_SENT; + fi; + +LISTEN: + state[i] = ListenState; + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! SYN; snd ! ACK; goto SYN_RECEIVED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto SYN_RECEIVED; + :: msg == ACK -> + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +SYN_RECEIVED: + state[i] = SynRecState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +ESTABLISHED: + state[i] = EstState; + do + :: snd ! FIN; goto FIN_WAIT_1; + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSE_WAIT; + :: else -> skip; + fi + od; + +FIN_WAIT_1: + state[i] = FinW1State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSING; + :: msg == ACK -> goto FIN_WAIT_2; + :: else -> skip; + fi + od; + +FIN_WAIT_2: + state[i] = FinW2State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto TIME_WAIT; + :: else -> skip; + fi + od; + +CLOSING: + state[i] = ClosingState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto TIME_WAIT; + :: else -> skip; + fi + od; + +CLOSE_WAIT: + state[i] = CloseWaitState; + snd ! FIN; goto LAST_ACK; + +LAST_ACK: + state[i] = LastAckState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto CLOSED; + :: else -> skip; + fi + od; + +TIME_WAIT: + state[i] = TimeWaitState; + goto CLOSED; +} + +init { + state[0] = ClosedState; + state[1] = ClosedState; + atomic { + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); + } +} + +/* liveness: active close eventually terminates */ +ltl phi8 { + always ( + (state[0] == FinW1State) implies (eventually (state[0] == ClosedState)) + ) +} diff --git a/tests/tcp/tcp-phi9.pml b/tests/tcp/tcp-phi9.pml new file mode 100644 index 0000000..a1971dd --- /dev/null +++ b/tests/tcp/tcp-phi9.pml @@ -0,0 +1,148 @@ +mtype = { SYN, FIN, ACK } + +chan AtoB = [2] of { mtype }; +chan BtoA = [2] of { mtype }; + +int state[2]; + +#define ClosedState 0 +#define ListenState 1 +#define SynSentState 2 +#define SynRecState 3 +#define EstState 4 +#define FinW1State 5 +#define CloseWaitState 6 +#define FinW2State 7 +#define ClosingState 8 +#define LastAckState 9 +#define TimeWaitState 10 + +proctype TCP(chan snd, rcv; int i) { + mtype msg; +CLOSED: + state[i] = ClosedState; + if + :: goto LISTEN; + :: snd ! SYN; goto SYN_SENT; + fi; + +LISTEN: + state[i] = ListenState; + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! SYN; snd ! ACK; goto SYN_RECEIVED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto SYN_RECEIVED; + :: msg == ACK -> + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +SYN_RECEIVED: + state[i] = SynRecState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +ESTABLISHED: + state[i] = EstState; + do + :: snd ! FIN; goto FIN_WAIT_1; + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSE_WAIT; + :: else -> skip; + fi + od; + +FIN_WAIT_1: + state[i] = FinW1State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSING; + :: msg == ACK -> goto FIN_WAIT_2; + :: else -> skip; + fi + od; + +FIN_WAIT_2: + state[i] = FinW2State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto TIME_WAIT; + :: else -> skip; + fi + od; + +CLOSING: + state[i] = ClosingState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto TIME_WAIT; + :: else -> skip; + fi + od; + +CLOSE_WAIT: + state[i] = CloseWaitState; + snd ! FIN; goto LAST_ACK; + +LAST_ACK: + state[i] = LastAckState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto CLOSED; + :: else -> skip; + fi + od; + +TIME_WAIT: + state[i] = TimeWaitState; + goto CLOSED; +} + +init { + state[0] = ClosedState; + state[1] = ClosedState; + atomic { + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); + } +} + +/* safety: handshake cannot be bypassed */ +ltl phi9 { + always ( + (state[0] == ListenState) + implies + !(next (state[0] == EstState)) + ) +} diff --git a/tests/tcp/tcp.pml b/tests/tcp/tcp.pml index 1792fbe..890107c 100644 --- a/tests/tcp/tcp.pml +++ b/tests/tcp/tcp.pml @@ -1,10 +1,9 @@ -mtype = { SYN, FIN, ACK, ABORT, CLOSE, RST, OPEN } +mtype = { SYN, FIN, ACK } chan AtoB = [2] of { mtype }; chan BtoA = [2] of { mtype }; int state[2]; -int pids[2]; #define ClosedState 0 #define ListenState 1 @@ -17,122 +16,124 @@ int pids[2]; #define ClosingState 8 #define LastAckState 9 #define TimeWaitState 10 -#define EndState -1 - -#define leftConnecting (state[0] == ListenState && state[1] == SynSentState) -#define leftEstablished (state[0] == EstState) -#define rightEstablished (state[1] == EstState) -#define leftClosed (state[0] == ClosedState) proctype TCP(chan snd, rcv; int i) { - pids[i] = _pid; + mtype msg; CLOSED: - state[i] = ClosedState; - do - /* Passive open */ - :: goto LISTEN; - /* Active open */ - :: snd ! SYN; goto SYN_SENT; - /* Terminate */ - :: goto end; - od + state[i] = ClosedState; + if + :: goto LISTEN; + :: snd ! SYN; goto SYN_SENT; + fi; + LISTEN: - state[i] = ListenState; - do - :: rcv ? SYN -> - atomic { - snd ! SYN; - snd ! ACK; - goto SYN_RECEIVED; - } - /* Simultaneous LISTEN */ - :: rcv ? _ -> skip; - :: timeout -> goto CLOSED; - od -SYN_SENT: - state[i] = SynSentState; - do - :: rcv ? SYN; - if - /* Standard behavior */ - :: rcv ? ACK -> snd ! ACK; goto ESTABLISHED; - /* Simultaneous open */ - :: snd ! ACK; goto SYN_RECEIVED; - fi - :: rcv ? ACK; + state[i] = ListenState; do - :: rcv ? SYN -> - snd ! ACK; - goto ESTABLISHED; - :: rcv ? _ -> skip; - od - :: rcv ? _ -> skip; - :: timeout -> goto CLOSED; /* Timeout */ - od + :: rcv ? msg -> + if + :: msg == SYN -> snd ! SYN; snd ! ACK; goto SYN_RECEIVED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + +SYN_SENT: + state[i] = SynSentState; + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto SYN_RECEIVED; + :: msg == ACK -> + do + :: rcv ? msg -> + if + :: msg == SYN -> snd ! ACK; goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + SYN_RECEIVED: - state[i] = SynRecState; - do - :: rcv ? ACK -> goto ESTABLISHED; - :: rcv ? _ -> skip; - od + state[i] = SynRecState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto ESTABLISHED; + :: else -> skip; + fi + :: timeout -> goto CLOSED; + od; + ESTABLISHED: - state[i] = EstState; - do - /* Close - initiator sequence */ - :: snd ! FIN; goto FIN_WAIT_1; - /* Close - responder sequence */ - :: rcv ? FIN -> - snd ! ACK; - goto CLOSE_WAIT; - :: rcv ? _ -> skip; - od + state[i] = EstState; + do + :: snd ! FIN; goto FIN_WAIT_1; + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSE_WAIT; + :: else -> skip; + fi + od; + FIN_WAIT_1: - state[i] = FinW1State; - do - /* Simultaneous close */ - :: rcv ? FIN -> - snd ! ACK; - goto CLOSING; - /* Standard close */ - :: rcv ? ACK -> goto FIN_WAIT_2; - :: rcv ? _ -> skip; - od -CLOSE_WAIT: - state[i] = CloseWaitState; - do - :: snd ! FIN; goto LAST_ACK; - :: rcv ? _ -> skip; - od + state[i] = FinW1State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto CLOSING; + :: msg == ACK -> goto FIN_WAIT_2; + :: else -> skip; + fi + od; + FIN_WAIT_2: - state[i] = FinW2State; - do - :: rcv ? FIN -> - snd ! ACK; - goto TIME_WAIT; - :: rcv ? _ -> skip; - od + state[i] = FinW2State; + do + :: rcv ? msg -> + if + :: msg == FIN -> snd ! ACK; goto TIME_WAIT; + :: else -> skip; + fi + od; + CLOSING: - state[i] = ClosingState; - do - :: rcv ? ACK -> goto TIME_WAIT; - :: rcv ? _ -> skip; - od + state[i] = ClosingState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto TIME_WAIT; + :: else -> skip; + fi + od; + +CLOSE_WAIT: + state[i] = CloseWaitState; + snd ! FIN; goto LAST_ACK; + LAST_ACK: - state[i] = LastAckState; - do - :: rcv ? ACK -> goto CLOSED; - :: rcv ? _ -> skip; - od + state[i] = LastAckState; + do + :: rcv ? msg -> + if + :: msg == ACK -> goto CLOSED; + :: else -> skip; + fi + od; + TIME_WAIT: - state[i] = TimeWaitState; - goto CLOSED; -end: - state[i] = EndState; + state[i] = TimeWaitState; + goto CLOSED; } init { - state[0] = ClosedState; - state[1] = ClosedState; - run TCP(AtoB, BtoA, 0); - run TCP(BtoA, AtoB, 1); + state[0] = ClosedState; + state[1] = ClosedState; + atomic { + run TCP(AtoB, BtoA, 0); + run TCP(BtoA, AtoB, 1); + } }