I am currently working on making test scripts for regression testing of FreeBSD's TCP/IP stack using Google's packetdrill. However, there is a slight problem which I am having involving sequence numbers. This is a small segment from one of the test scripts which verifies whether Early Retransmit works properly -

// Three way handshake
0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7>
0.100 > S. 0:0(0) ack 1 <...>
0.200 < . 1:1(0) ack 1 win 257
0.200 accept(3, ..., ...) = 4

// Our application writes 2920 bytes 
0.200 write(4, ..., 2920) = 2920
0.200 > P. 1:2921(2920) ack 1
0.300 < .  1:1(0) ack 1 win 257 <sack 1461:2921,nop,nop>
0.325 > .  1:1461(1460) ack 1  // delayed Early Retransmit at RTT/4 = 25ms
0.425 < .  1:1(0) ack 2921 win 257

0.500 close(4) = 0
0.500 > F. 2921:2921(0) ack 1
0.600 < F. 1:1(0) ack 2922 win 257
0.601 > .  2922:2922(0) ack 2

Although the test is easy to understand, but what I am not able to figure out is that why along with PUSH are we again sending an acknowledgement number 1, because while in the three-way handshake, the other side already did send an ACK starting with sequence number 1. Shouldn't this be the correct line -

0.200 > P. 1:2921(2920) ack 2
0.300 < .  2:2(0) ack 1 win 257 <sack 1461:2921,nop,nop>

It can also be seen that at 0.425 seconds the other side again sends an ACK with the same sequence number of 1:1.
The full test script can be found here.
I could have posted the question in the packetdrill's mailing list, but I think this is a problem with my fundamentals.

For a quick reference ~

  • The starting decimals denote absolute timings in seconds.
  • < and > denote direction of packets, < for receiving and > for injecting.
  • S denotes SYN
  • P denotes PUSH
  • F denotes FIN
  • . denotes ACK
  • sack denotes Selective Acknowledgement.
  • accept(), close() and write() are the appropriate system calls.

1 Answer 1


Quick answer is that after the the ack number is sent the first time, it is always sent. It always reflects the next expected sequence number, so unless new data segments arrive, it will be repeated. In other words, if the stack sends a packet that acks incoming byte n, and for some reason sends a new packet before there has been more incoming data to ack, then the stack will ack byte n once again.

why along with PUSH are we again sending an acknowledgement number 1

As for the ack being 1 instead of 2, that is because the ack is data byte count instead of packet count, and while one side is sending 2920 bytes it doesn't seem that the other side is sending any data. A SYN, a PSH and a FIN will count for one byte, and hence a SYN-ACK or a FIN-ACK will count for one byte too. Since there is only one SYN at the beginning, the ACK number will correspond to the 1-based index of the next byte that is expected. In other words ack 1 means "I'm waiting for your first byte of data".

There is a good explanation over at packetlife.net.

  • +1. It may also be worth to note that (unless FreeBSD's TCP/IP stack is severely broken) the sequence numbers seen in the capture are relative numbers, i.e. in the SYN and SYN+ACK the actual initial sequence numbers are typically random values, but to make the capture easier to read, the initial value is shown as zero and so all ACK values should be interpreted as an offset rather than an absolute value (i.e. if ISN was 12345 then ack 1 really means ack 12346)
    – hertitu
    Aug 22, 2016 at 12:10
  • @hertitu FreeBSD's TCP is not severely broken, I'd sooner call it a model! Thank you for noting that the ack 1 is actually the result of a calculation done by the packet analyzer, not the real byte on the wire.
    – Law29
    Aug 22, 2016 at 13:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.