tcp state machine specification

published: September 28, 2025

overview

the tcp finite state machine (fsm) defines all valid states and transitions for tcp connections. this specification provides the complete state machine as defined in rfc 9293, including edge cases, simultaneous operations, and error conditions.

state definitions

primary states

tl;dr

StateDescriptionTCB ExistsValid Operations
CLOSEDNo connection exists, initial stateNoOPEN (active/passive)
LISTENWaiting for connection requestPartialSEND (error), CLOSE
SYN-SENTActive open, waiting for SYN-ACKYesCLOSE, timeout
SYN-RECEIVEDSYN received and sent, waiting for ACKYesSEND, RECEIVE, CLOSE
ESTABLISHEDConnection open, data transferYesSEND, RECEIVE, CLOSE
FIN-WAIT-1FIN sent, waiting for ACK or FINYesRECEIVE, CLOSE
FIN-WAIT-2FIN acknowledged, waiting for FINYesRECEIVE, CLOSE
CLOSE-WAITFIN received, waiting for applicationYesSEND, CLOSE
CLOSINGSimultaneous close, waiting for ACKYestimeout
LAST-ACKFIN sent after receiving FINYestimeout
TIME-WAITWaiting for network to clearYestimeout (2*MSL)

tcb (transmission control block)

each tcp connection maintains a tcb containing:

struct tcb {
    // Connection identification
    uint32_t local_addr;
    uint16_t local_port;
    uint32_t remote_addr;
    uint16_t remote_port;
    
    // Send sequence variables
    uint32_t snd_una;    // oldest unacknowledged
    uint32_t snd_nxt;    // next send
    uint32_t snd_wnd;    // send window
    uint32_t snd_up;     // urgent pointer
    uint32_t snd_wl1;    // segment seq for last window update
    uint32_t snd_wl2;    // segment ack for last window update
    uint32_t iss;        // initial send sequence
    
    // Receive sequence variables  
    uint32_t rcv_nxt;    // next receive
    uint32_t rcv_wnd;    // receive window
    uint32_t rcv_up;     // urgent pointer
    uint32_t irs;        // initial receive sequence
    
    // Connection state
    enum tcp_state state;
    
    // Timers
    timer_t retransmit_timer;
    timer_t persist_timer;
    timer_t keepalive_timer;
    timer_t timewait_timer;
    
    // Options
    uint16_t mss;
    uint8_t  wscale_snd;
    uint8_t  wscale_rcv;
    bool     sack_permitted;
    bool     timestamps;
};

tcp state machine diagram

TCP Finite State Machine
Rendering diagram...

Complete TCP state transitions showing normal connection flow, simultaneous operations, and error conditions. Each state represents a specific phase in the TCP connection lifecycle.

state transition table

complete transition matrix

Current State   Event/Input        Condition           New State       Action
-------------   ---------------    ----------------    -----------     ----------------
CLOSED          passive OPEN       -                   LISTEN          create TCB
CLOSED          active OPEN        -                   SYN-SENT        send SYN
CLOSED          SEND               -                   SYN-SENT        send SYN
CLOSED          rcv SYN            -                   SYN-RECEIVED    send SYN,ACK
CLOSED          rcv other          -                   CLOSED          send RST

LISTEN          rcv SYN            -                   SYN-RECEIVED    send SYN,ACK
LISTEN          SEND               -                   SYN-SENT        send SYN
LISTEN          CLOSE              -                   CLOSED          delete TCB
LISTEN          rcv other          -                   LISTEN          ignore

SYN-SENT        rcv SYN,ACK        acceptable ACK      ESTABLISHED     send ACK
SYN-SENT        rcv SYN,ACK        !acceptable         SYN-SENT        send RST
SYN-SENT        rcv SYN            -                   SYN-RECEIVED    send SYN,ACK
SYN-SENT        timeout            -                   CLOSED          delete TCB
SYN-SENT        CLOSE              -                   CLOSED          delete TCB
SYN-SENT        rcv RST            -                   CLOSED          error to app

SYN-RECEIVED    rcv ACK            acceptable          ESTABLISHED     -
SYN-RECEIVED    rcv ACK            !acceptable         SYN-RECEIVED    send RST
SYN-RECEIVED    rcv SYN            -                   SYN-RECEIVED    send SYN,ACK
SYN-RECEIVED    rcv FIN            -                   CLOSE-WAIT      send ACK
SYN-RECEIVED    CLOSE              -                   FIN-WAIT-1      send FIN
SYN-RECEIVED    rcv RST            -                   LISTEN/CLOSED   see below

ESTABLISHED     rcv FIN            -                   CLOSE-WAIT      send ACK
ESTABLISHED     CLOSE              -                   FIN-WAIT-1      send FIN
ESTABLISHED     rcv ACK            -                   ESTABLISHED     update window
ESTABLISHED     rcv RST            -                   CLOSED          error to app
ESTABLISHED     rcv data           -                   ESTABLISHED     process data

FIN-WAIT-1      rcv ACK            acks FIN            FIN-WAIT-2      -
FIN-WAIT-1      rcv FIN            -                   CLOSING         send ACK
FIN-WAIT-1      rcv FIN,ACK        -                   TIME-WAIT       send ACK
FIN-WAIT-1      rcv RST            -                   CLOSED          error to app

FIN-WAIT-2      rcv FIN            -                   TIME-WAIT       send ACK
FIN-WAIT-2      rcv RST            -                   CLOSED          error to app
FIN-WAIT-2      timeout            -                   CLOSED          delete TCB

CLOSE-WAIT      CLOSE              -                   LAST-ACK        send FIN
CLOSE-WAIT      rcv RST            -                   CLOSED          error to app

CLOSING         rcv ACK            acks FIN            TIME-WAIT       -
CLOSING         rcv RST            -                   CLOSED          ignore

LAST-ACK        rcv ACK            acks FIN            CLOSED          delete TCB
LAST-ACK        rcv RST            -                   CLOSED          delete TCB

TIME-WAIT       timeout            2*MSL               CLOSED          delete TCB
TIME-WAIT       rcv FIN            -                   TIME-WAIT       send ACK
TIME-WAIT       rcv RST            -                   CLOSED          delete TCB

state transition events

user events (api calls)

tl;dr

EventDescriptionValid States
OPEN (passive)listen() system callCLOSED
OPEN (active)connect() system callCLOSED, LISTEN
SENDsend() system callESTABLISHED, CLOSE-WAIT
RECEIVErecv() system callESTABLISHED, FIN-WAIT-1/2
CLOSEclose() system callAny except CLOSED
ABORTSO_LINGER(0) closeAny except CLOSED
STATUSgetsockopt()Any

network events (segment arrival)

tl;dr

EventFlagsDescription
rcv SYNSYN=1, ACK=0Connection request
rcv SYN,ACKSYN=1, ACK=1Connection accepted
rcv ACKSYN=0, ACK=1Acknowledgment
rcv FINFIN=1Connection closing
rcv FIN,ACKFIN=1, ACK=1Close acknowledgment
rcv RSTRST=1Connection reset
rcv dataPSH=0/1Data segment

timer events

tl;dr

TimerTrigger ConditionAction
RetransmissionNo ACK within RTORetransmit segment
TIME-WAIT2*MSL elapsedClose connection
FIN-WAIT-2Timeout waiting for FINForce close
PersistZero window probeSend 1-byte probe
Keep-AliveIdle connectionSend keep-alive probe
User TimeoutData unacked too longAbort connection

detailed state behaviors

closed state

CLOSED State Processing:

ON passive OPEN:
    create TCB
    state = LISTEN
    return

ON active OPEN:
    create TCB
    select ISS
    send SYN: <SEQ=ISS><CTL=SYN>
    state = SYN-SENT
    return

ON incoming segment:
    if RST:
        ignore
    else:
        send RST: <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
    return

listen state

LISTEN State Processing:

ON incoming SYN:
    if security/compartment mismatch:
        send RST
        return
    create new TCB for connection
    select ISS
    send SYN,ACK: <SEQ=ISS><ACK=SEG.SEQ+1><CTL=SYN,ACK>
    state = SYN-RECEIVED
    return

ON incoming segment without SYN:
    if RST:
        ignore
    else:
        send RST
    return

ON CLOSE:
    delete TCB
    state = CLOSED
    return

established state

ESTABLISHED State Processing:

ON incoming segment:
    check sequence number:
        if outside window:
            send ACK
            return
    
    if RST:
        abort connection
        state = CLOSED
        signal error to application
        return
    
    if SYN:
        send RST
        abort connection
        state = CLOSED
        return
    
    if ACK:
        update send window
        remove acknowledged data from retransmit queue
        restart retransmission timer if data outstanding
    
    process URG if present
    
    process data:
        queue for application
        send ACK if needed (delayed ACK rules)
    
    if FIN:
        signal EOF to application
        send ACK
        state = CLOSE-WAIT
        
    return

ON CLOSE:
    send FIN
    state = FIN-WAIT-1
    return

simultaneous operations

simultaneous open

rare scenario where both ends initiate active open:

Host A State        Segment Exchange         Host B State
------------        ----------------         ------------
CLOSED                                       CLOSED
  |                                            |
  v OPEN                                       v OPEN
SYN-SENT ---------> <SEQ=100><SYN> ---------> SYN-SENT
         <--------- <SEQ=300><SYN> <---------
  |                 (packets cross)           |
  v rcv SYN                                    v rcv SYN
SYN-RECEIVED -----> <SEQ=100><ACK=301> -----> SYN-RECEIVED
             <----- <SEQ=300><ACK=101> <-----
  |                                            |
  v rcv ACK                                    v rcv ACK
ESTABLISHED                                  ESTABLISHED

simultaneous close

both ends initiate close at same time:

Host A State        Segment Exchange         Host B State
------------        ----------------         ------------
ESTABLISHED                                  ESTABLISHED
  |                                            |
  v CLOSE                                      v CLOSE
FIN-WAIT-1 -------> <SEQ=100><FIN,ACK> -----> FIN-WAIT-1
           <------- <SEQ=300><FIN,ACK> <------
  |                 (packets cross)           |
  v rcv FIN                                    v rcv FIN
CLOSING ----------> <SEQ=101><ACK=301> ------> CLOSING
        <---------- <SEQ=301><ACK=101> <------
  |                                            |
  v rcv ACK                                    v rcv ACK
TIME-WAIT                                    TIME-WAIT
  |                                            |
  v timeout                                    v timeout
CLOSED                                       CLOSED

reset processing

when to send rst

Send RST Conditions:

1. No TCB exists (CLOSED state):
   - Incoming segment except RST
   - Format: <SEQ=0><ACK=SEG.SEQ+SEG.LEN><RST,ACK>

2. Half-synchronized (SYN-SENT/SYN-RECEIVED):
   - Unacceptable ACK received
   - Format: <SEQ=SEG.ACK><RST>

3. Synchronized states:
   - Security level mismatch
   - Unacceptable SYN received
   - Format: <SEQ=SND.NXT><RST>

4. Aborting connection:
   - User ABORT command
   - Format: <SEQ=SND.NXT><RST>

when to accept rst

RST Acceptance Rules:

1. Check sequence:
   - Must be in receive window
   - If SEG.SEQ = RCV.NXT: exact match
   - If in window: acceptable

2. State-specific handling:
   SYN-SENT:
     - If ACK matches: abort, return error
     - Otherwise: ignore
   
   SYN-RECEIVED:
     - If passive open: return to LISTEN
     - If active open: return to CLOSED
   
   ESTABLISHED, FIN-WAIT-1/2, CLOSE-WAIT:
     - Abort connection
     - Signal error to application
     - Return to CLOSED
   
   CLOSING, LAST-ACK:
     - Return to CLOSED
   
   TIME-WAIT:
     - Return to CLOSED

edge cases and error conditions

half-open connections

detection and recovery:

Scenario: Host A thinks connection open, Host B thinks closed

Host A                              Host B
------                              ------
ESTABLISHED                         CLOSED
  |
  sends data ------------------>    
                                    (no TCB)
                <-- RST ----------  sends RST
  |
CLOSED (abort)

old duplicate syn

protection using initial sequence numbers:

ISN Selection Algorithm:
ISN = M + F(localip, localport, remoteip, remoteport, secretkey)

Where:
- M = 4 microsecond timer (increases ISN over time)
- F = cryptographic hash function
- Prevents: sequence number prediction attacks
- Ensures: old duplicates have stale sequence numbers

connection hijacking prevention

sequence number validation:

Acceptable Segment Check:
RCV.NXT <= SEG.SEQ < RCV.NXT + RCV.WND
or
RCV.NXT <= SEG.SEQ + SEG.LEN - 1 < RCV.NXT + RCV.WND

If outside window:
- Send ACK: <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
- Drop segment
- Prevents blind injection attacks

implementation considerations

state storage optimization

Key Highlights

  • closed - no storage required
  • listen - minimal tcb (just port binding)
  • syn-received - may use syn cookies to avoid state
  • time-wait - can use compressed state
  • established - full tcb required

performance optimizations

tl;dr

OptimizationState ImpactBenefit
SYN cookiesNo SYN-RECEIVED stateSYN flood protection
TIME-WAIT assassinationEarly TIME-WAIT exitPort reuse
Fast retransmitESTABLISHED behaviorQuicker loss recovery
Header predictionESTABLISHED fast pathReduced CPU usage

debugging state machines

observing states

# linux - show states
ss -tan state established
ss -tan state time-wait
ss -tan state syn-sent

# count by state
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c

# watch state changes
tcpdump -i any -nn 'tcp[tcpflags] & (tcp-syn|tcp-fin|tcp-rst) != 0'

# kernel state counters
netstat -st | grep -i state
nstat -az | grep -i tcp.*state

common state issues

tl;dr

SymptomLikely StateInvestigation
Connection hangsSYN-SENTCheck routing, firewall
Port exhaustionTIME-WAITCheck close patterns
Memory leakCLOSE-WAITApplication not closing
SYN floodSYN-RECEIVEDEnable SYN cookies
Half-openESTABLISHEDEnable keepalive

references

  • rfc 793 - original tcp specification (1981)
  • rfc 9293 - tcp specification (2022, current)
  • rfc 5961 - improving tcp’s robustness
  • rfc 7323 - tcp extensions for high performance

key takeaways

  • tcp state machine ensures reliable, ordered delivery
  • eleven states manage connection lifecycle
  • transitions triggered by user events, network events, and timers
  • edge cases handled through sequence validation and timers
  • implementation optimizations possible while maintaining correctness
  • understanding states critical for debugging network issues

next steps

on this page