In the first article we discussed how the TCP connection initiation and termination is performed and how we can see this in Wireshark. In this article, we will discuss the actual TCP data transmission procedure.
TCP is using the cumulative acknowledgement approach, in which the TCP receiver is normally sending an ACK that represents the amount of contiguous data it got. The procedure of TCP transmission is as follows
- At the connection start, each side of the connection picks some random number called initial sequence number ISN. This number represents the number of the first byte this side will send to the other side. To make analysis easier, Wireshark will show this field starting from
0but you can get the actual sequence number from the raw sequence number field on the Wireshark expert view.
- For each byte sent, the transmitting side will increase the sequence number by one. The next sequence number field of each packet represents the sequence number that you should find in this side next packets if no drops or out of order packets happened.
- The receiver sends the total number of bytes it got from the transmitter as an acknowledgement to tell the transmitter that everything is correct, so the transmitter can continue sending the remaining packets. Wireshark also displays the ACk starting from
0to make analysis easier but you can get the actual ACK value from the raw ACK field.
This is the 3-way handshaking procedure we saw before
And you can see from it that
- In the first packet, the
seq=0indicates that this side didn't transmit anything before and this is the first byte to be transmitted. This packet is the first on this connection, so no ack as there is no previous data to be ACKed.
- In the second packet the
seq=0as in the previous one and for the same reason. Note that in both packets the real sequence number is some random value and those zeros are only Wireshark contribution to make our analysis easier.
- In the second packet, the
Ack=1indicates that this side correctly received one sequence number from the other side. The correctly received sequence number is for the
SYNsent from the other side on the first packet.
- The third message contains only an
ACKfrom the side that initiated the connection that it correctly received one sequence from the other side - received the other side
In real-world scenarios packets drops and out of order packets can happen for many reasons. In this case, the TCP receiver will get a different sequence number than the one it waits. This will trigger the following effects
- The receiver should send an ACK represents the last correctly received sequence number. As this sequence number was ACKed before, this is a duplicate ACK. The receiver should continue to send duplicate ACKs till it gets the correct sequence number from the transmitter.
- If the condition of retransmission - will be discussed shortly - are met, the TCP transmitter will start retransmitting the packets that it didn't get ACKs for to the receiver
This is how the duplicate ACK appear in Wireshark
And you can note the sequence in this capture
- In the first packet the TCP transmitter
IP 172.31.136.85is sending
ACK=1, which means that it received only one byte from the other host
- In packet #2 the TCP
IP 220.127.116.11sends data starting from the
seq=10945. This isn't the expected sequence number by the
IP 172.31.136.85host as it expects
- TCP host
IP 172.31.136.85will send a duplicate ACK in the third packet to inform the other host
IP 18.104.22.168that a portion of the data is missing.
- The TCP host
IP 22.214.171.124will not respond immediately with the missing packets. It will continue transmitting some new packets before performing the desired packets retransmission in packet #8.
When a TCP host sends data, it will set a timer with a period called retransmission time-out RTO, and wait for the other host to ACK the sent data. If the timer timed-out before the other host ACKing the data, then the data will be retransmitted. This is called a time-out retransmission.
Each time retransmission fails, the RTO value will be doubled. This RTO value doubling is called exponential backoff and doubling continues till an acknowledgement is received for a packet that was not ACKed before.
There is another type of retransmission called Fast retransmission, in which if the host received a certain number of consecutive duplicate ACKs called the duplicate ACK threshold or dupthresh - and is usually 3 duplicate ACKs, it will assume that the data was lost and do retransmission without waiting for the time-out based retransmission. This type of retransmission can increase TCP throughput but may not be supported by all hosts. In the previous capture, the TCP host
IP 126.96.36.199 performed fast retransmission in packet #8 after receiving 3 duplicate ACKs from the other host.
The RFC2018 describes an enhancement to the traditional TCP cumulative ACKs by implementing selective ACKs. The main problem with cumulative ACKs is that if a packet was dropped or delayed all the other packets will be neglected even if they reached their destination correctly. This means that after doing the retransmission for the dropped packet, TCP needs to retransmit all the packets that followed which is a waste for bandwidth.
Selective ACK is an optional feature of the TCP, and each host should announce if it supports this option on its SYN packet options. Both hosts need to support the selective ACK feature to make it usable in a TCP connection. Selective ACK is the process of the receiving host giving the transmitting host information about the non-consecutive parts it managed to receive correctly. The sending host needs to do selective retransmissions to fill the gaps between the selective ACKed packets. In the 3-way handshake capture above you can see the
SACK_PERM=1 that indicates that SACK is enabled by both hosts.
Note that the cumulative ack will continue to work as normal and will always ack the last received continuous block and the selective ACK will be in the TCP options part and will ACK the non-contiguous ranges.
Every TCP receiver has a window size that represents the maximum number of bytes it can receive. When a TCP host transmits a packet it will announce it's remaining window size, so the other host can know how much it can send to avoid packets loss. The maximum window size for each host is announced in the 3-way handshaking, and it consists of 2 parts
- Window size: This is a 16-bit field representing the maximum window size. Being limited to 16 bits only is not suitable for the high speeds available today as the maximum window size that can be represented by this field is 64K.
- Window scale: A TCP option added by RFC1323 to expand the window size. The window size is left-shifted by the value of this field to get the actual window size. Note that this field is only sent on the SYN packet, so you need to get the SYN packet in your capture to get the correct value of this field.
Here is the window size parameter in the Wireshark expert view
And this is the window scale in the TCP options