The following packetdrill shows different result of last read between Linux and FreeBSD ``` 0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 +0 bind(3, ..., ...) = 0 +0 listen(3, 1) = 0 +0 < S 0:0(0) win 1000 <TS val 100 ecr 0,eol,eol> +.5 > S. 0:0(0) ack 1 <...> +.1 < . 1:1(0) ack 1 win 1000 +0.1 accept(3, ..., ...) = 4 +0 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0 +0 < . 1:1001(1000) ack 1 win 1000 <TS val 100 ecr 0,eol,eol> +0.1 read(4, ..., 1000) = 1000 // Linux accept this packet, while FreeBSD reject. // But if we set the TS val to 50, they both reject it. +0 < . 1001:2001(1000) ack 1 win 1000 <TS val 99 ecr 0,eol,eol> +0.1 read(4, ..., 1000) = 1000 ```
I modified the test to run on FreeBSD head and think it works as it should according to https://tools.ietf.org/html/rfc7323#section-5.3 The rule R1 specifies to drop a segment with SEG.TSval < TS.Recent and send an ACK. Since TS.Recent is 100, the segment with SEG.TSval = 99 should be dropped. The same applies to a segment with SEG.TSval = 50. I'm closing this issues as 'Works as intended'. If you disagree, please re-open. Here is the updated script, which runs on FreeBSD head: --tolerance_usecs=25000 // This script runs against FreeBSD head. 0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0.000 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0 +0.000 bind(3, ..., ...) = 0 +0.000 listen(3, 1) = 0 +0.000 < S 0:0(0) win 65535 <mss 1400,sackOK,TS val 100 ecr 0> +0.000 > S. 0:0(0) ack 1 win 65535 <mss 1460,sackOK,TS val 200 ecr 100> // The following segments needs to have the timestamp option. // See https://tools.ietf.org/html/rfc7323#section-3.2 // This is enforced in https://svnweb.freebsd.org/changeset/base/367530 +0.100 < . 1:1(0) ack 1 win 65535 <nop,nop,TS val 200 ecr 200> +0.100 accept(3, ..., ...) = 4 +0 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0 // The following segment with SEG.TSval=300 enforces TS.Recent=300. +0.000 < . 1:1001(1000) ack 1 win 65535 <nop,nop,TS val 300 ecr 200> +0.000 read(4, ..., 2000) = 1000 +0.040 > . 1:1(0) ack 1001 win 65535 <nop,nop,TS val 440 ecr 300> // The following segment with SEG.TSval < TS.Recent should be dropped. +0.000 < . 1001:2001(1000) ack 1 win 65535 <nop,nop,TS val 299 ecr 440> +0.000 > . 1:1(0) ack 1001 win 65535 <nop,nop,TS val 440 ecr 300> +0.000 read(4, ..., 2000) = -1 EWOULDBLOCK (Operation would block) // The following segment with SEG.TSval == TS.Recent should be accepted. +0.000 < . 1001:2001(1000) ack 1 win 65535 <nop,nop,TS val 300 ecr 440> +0.000 read(4, ..., 2000) = 1000 +0.040 > . 1:1(0) ack 2001 win 65535 <nop,nop,TS val 480 ecr 300>