Before the traps, we pin down the two words that appear in almost every question below, then look at pictures of the behaviour they drive. Everything after that is testing whether you really internalised these.
The recurring characters: cwnd (congestion window, the sender's private guess of what the network can take, measured in MSS), rwnd (receive window, what the receiver's buffer can take), ssthresh (the boundary between exponential and linear growth), and the four phases — slow start, congestion avoidance, fast retransmit/recovery, and CUBIC.
The final figure shows how cwnd and rwnd interact: the sender may keep at most min(cwnd,rwnd) bytes in flight, so whichever line is lower is the one actually throttling you.
Slow start increases the window more slowly than congestion avoidance.
False — slow start doubles per RTT (exponential) while congestion avoidance adds +1 MSS per RTT (linear), so slow start is the faster-growing phase; "slow" refers only to its small starting size, not its growth rate.
cwnd is advertised to the other host so both ends agree on the sending rate.
False — only rwnd travels on the wire (inside ACK headers). cwnd is purely local to the sender and never appears in any TCP header; the sender alone enforces min(cwnd,rwnd).
A larger cwnd always means higher throughput.
False — throughput ≈cwnd/RTT only until the window exceeds the pipe's capacity; past that point extra window just fills router queues (raising delay) and eventually causes loss, which then shrinks the window. See Queueing and Router Buffers.
On any packet loss, TCP Reno resets cwnd to 1 MSS.
False — that harsh reset happens only on timeout. On 3 duplicate ACKs (fast retransmit) Reno halves cwnd and stays in congestion avoidance (fast recovery), because data is clearly still flowing.
During fast recovery, cwnd stays frozen at its halved value until the lost segment is ACKed.
False — Reno inflates cwnd by +1 MSS for each additional duplicate ACK, because every duplicate proves one more segment left the network; this keeps the pipe full during recovery, and cwnd deflates back to ssthresh when the fresh ACK finally arrives.
The "multiplicative decrease" in AIMD means multiplying cwnd by some factor less than 1.
True — MD cuts cwnd by a multiplicative factor (halving in Reno, factor (1−β) in CUBIC). This proportional back-off, paired with additive increase, is what drives convergence to fairness — see AIMD Fairness.
CUBIC's window grows as a function of the number of RTTs since the last loss.
False — CUBIC's Wcubic(t)=C(t−K)3+Wmax uses t in wall-clock seconds, not RTTs. That is exactly what gives it RTT fairness: two flows with different RTTs climb at similar real-time rates.
Fast retransmit and fast recovery are the same mechanism.
False — fast retransmit is the detection+resend rule (retransmit on 3 dup ACKs without waiting for the timer); fast recovery is the window adjustment that follows (halve, inflate per dup ACK, stay in CA rather than dropping to 1).
Congestion control and flow control solve the same problem.
False — flow control (via rwnd) protects the receiver's buffer from a fast sender; congestion control (via cwnd) protects the network's routers from all senders combined. Two different bottlenecks — see Flow Control vs Congestion Control.
ssthresh is a fixed constant chosen at connection start.
False — ssthresh is dynamic: it is set to roughly half the current cwnd on every loss event, so it tracks the network's most recent estimate of the safe operating point.
"cwnd doubles each RTT because we add 1 MSS per RTT."
The +1-per-ACK rule is what doubles it: with W segments out, W ACKs return per RTT, each adding 1, so W→2W. Adding +1 per RTT is the congestion avoidance rule, which is linear, not doubling.
"In congestion avoidance we add 1 MSS per ACK."
We add MSS2/cwnd per ACK. Summed over the ≈cwnd/MSS ACKs in one RTT, this totals exactly +1 MSS per RTT — the true additive-increase rate.
"On 3 dup ACKs we set ssthresh = cwnd and cwnd = cwnd/2."
It's the other way: ssthresh = cwnd/2 first, then cwnd is set down to ssthresh. ssthresh records the new estimated ceiling, and cwnd is the current window, so cwnd ends up at the halved value.
"CUBIC's K is the window size right after a loss."
K is a time (seconds), not a window. It is how long the cubic takes to climb back to the old peak Wmax; the window right after loss is (1−β)Wmax.
"After a timeout, ssthresh is set to 1 MSS and cwnd is halved."
Reversed. cwnd drops to 1 MSS (restart slow start) and ssthresh is set to cwnd/2 (the halved old value), so slow start knows where to stop doubling.
"Three duplicate ACKs mean three different segments were lost."
Duplicate ACKs are cumulative re-requests for the same missing byte. Three dup ACKs signal that one segment is likely lost while later segments (which triggered the duplicates) are still arriving.
"Because slow start is exponential, it never stops and will overflow the network."
It stops when cwnd reaches ssthresh (switching to linear CA) or when a loss occurs — whichever comes first. The exponential phase is deliberately short.
Why do we use 3 duplicate ACKs, not 1 or 2, as the loss signal?
One or two duplicates can simply be packet reordering in the network; three is strong statistical evidence that the missing segment is genuinely lost, keeping false retransmissions rare.
Why halve cwnd rather than subtract a fixed amount on congestion?
A multiplicative cut reacts proportionally — a huge window backs off a lot, a small one only a little — which, combined with additive increase, mathematically converges different flows toward an equal, fair share (the AIMD sawtooth).
Why does slow start grow exponentially instead of linearly?
The sender has no idea of the link's capacity at startup, so doubling homes in on the right order of magnitude in log2 of the capacity's worth of RTTs — fast probing when uncertainty is largest.
Why is fast retransmit worth the effort when a timeout would eventually resend anyway?
A retransmission timeout (RTO) is conservatively long (often hundreds of ms) to avoid spurious resends; fast retransmit resends within one RTT, keeping the pipe full and throughput high.
Why inflate cwnd by +1 MSS on each extra duplicate ACK during fast recovery?
Each duplicate proves another segment has left the network (a buffer slot freed), so temporarily bumping cwnd lets the sender clock out new data and keep the pipe full while waiting for the retransmission to be acknowledged.
Why does CUBIC grow concavely just after a loss and convexly later?
Concave growth near the old peak Wmax is cautious — it slows as it approaches the point that last caused loss. Once past the peak with no loss, convex growth accelerates to explore for newly freed bandwidth.
Why does Reno struggle on long fat networks (high bandwidth-delay product)?
Its +1-MSS-per-RTT refill is far too slow to fill a window worth of hundreds of segments after a loss, wasting most of the link's capacity. This is exactly what CUBIC and BBR Congestion Control were designed to fix — see Bandwidth Delay Product.
Why measure cwnd in units of MSS rather than bytes?
It expresses the window as a count of full segments, making the "one increment per ACK/RTT" rules and the doubling/linear behaviour clean and unit-free to reason about.
What happens in slow start if cwnd = 1 and a timeout occurs?
ssthresh becomes cwnd/2 (which may round to 1), cwnd stays at 1, and we remain in slow start — the connection is already at its minimum, so it just keeps retrying from the floor.
If rwnd = 2 MSS but cwnd has grown to 50 MSS, how much can the sender send?
Only min(50,2)=2 MSS — the receiver's buffer is the binding limit here, so all the congestion-window growth is idle until rwnd opens up.
What does CUBIC do exactly at t=K?
Wcubic(K)=C(K−K)3+Wmax=Wmax — it plateaus precisely at the old pre-loss window, gently re-testing the ceiling that previously broke.
If two CUBIC flows share a link but one has half the RTT of the other, do they get equal shares?
Roughly yes — because CUBIC's growth is a function of wall-clock time, not RTTs, both climb at similar real-time rates, unlike Reno where the short-RTT flow would grab far more.
What if ssthresh is set higher than cwnd will ever reach before a loss?
The connection simply stays in slow start (exponential) the whole time, since it never crosses ssthresh into congestion avoidance before congestion forces a reset.
At the very first segment of a brand-new connection, which phase are we in and what is cwnd?
Slow start — and modern TCP (RFC 6928) starts cwnd at an initial window of about 10 MSS, not 1, so short transfers finish in fewer round trips; it still doubles from there.
Why is the initial window 10 MSS rather than 1 MSS as older textbooks say?
Starting at 1 MSS wasted many RFC-era RTTs ramping up for tiny web transfers; RFC 6928 raised the default initial cwnd to ~10 MSS (about 14600 bytes) so most short flows complete before ever needing slow start's later doublings, while still being cautious enough to avoid overload.
Recall One-line self-test
Match the reaction to the signal.
Timeout ⇒ ? ::: cwnd = 1 MSS, ssthresh = cwnd/2, back to slow start (severe signal).
3 dup ACKs ⇒ ? ::: ssthresh = cwnd/2, cwnd = ssthresh then inflate +1 per extra dup ACK, stay in congestion avoidance (mild signal).