Computing MPTCP’s initial Data Sequence Number (IDSN)

On a regular TCP subflow, the sequence number used in the SYN segment serves as the initial sequence number. All subsequent segments are numbered starting at this initial sequence number.

msc {
width=800, arcgradient = 4;

c [label="Client", linecolour=black],
s [label="Server", linecolour=black];
|||;
c=>s [ label = "SYN(seq=x)\n\n"];
|||;
s=>c [label = "SYN+ACK(seq=y,ack=x+1)\n\n"];
|||;
c=>s [label="ACK(ack=y+1)\n\n"];
|||;
c=>s [label="First data(seq=x+1,ack=y+1)\n\n"];
|||;
}

Multipath TCP uses two levels of sequence numbers : the regular sequence numbers that appear inside the header of each TCP segment and the Multipath-level Data Sequence Numbers that are used inside Multipath TCP options. The DSNs enable the receiver to reorder the data received over the different subflows. The Data Sequence Number is incremented every time data is sent and an initial Data Sequence Number is negotiated during the three way handshake on the first subflow. Due to the limited TCP option space, the initial DSN is computed from the information exchanged during the three-way handshake.

msc {
width=800,arcgradient = 4;

c [label="Client", linecolour=black],
s [label="Server", linecolour=black];

|||;
c=>s [ label = "SYN(seq=x, MP_CAPABLE(ClientKey))\n\n" ];
|||;
s=>c [label = "SYN+ACK(seq=y,ack=x+1,  MP_CAPABLE(ServerKey))\n\n" ];
|||;
c=>s [label="ACK(ack=y+1),  MP_CAPABLE(ClientKey,ServerKey)\n\n"];
|||;
}

At the end of the three-way handshake, the initial DSN can be computed as the low order 64 bits of the hash of the sender’s key. At this point, one could wonder why we need an initial DSN for each Multipath TCP connection. There are two reasons for that. The first one is that using an initial DSN can improve the resilience to segment injection attacks by using an initial DSN that cannot be easily predicted by attackers. The second reason is to prevent data losses in case of failure of the initial subflow. Consider the scenario depicted below. The client creates the first subflow,

msc {
width=800,arcgradient = 4;
c1 [label="Client1", linecolour=black],
c2 [label="Client2", linecolour=black],
s [label="Server", linecolour=black];

|||;
c1=>s [ label = "SYN(seq=x, MP_CAPABLE(ClientKey))\n\n" ];
|||;
s=>c1 [label = "SYN+ACK(seq=y,ack=x+1,  MP_CAPABLE(ServerKey))\n\n" ];
|||;
c1=>s [label="ACK(ack=y+1),  MP_CAPABLE(ClientKey,ServerKey)\n\n"];
|||;
c1-x s [label="First Data(seq=x+1,DSS(seq=idsn),data=a)\n\n"];
|||;
c2=>s [ label = "SYN(seq=w, MP_JOIN)\n\n" ];
|||;
s=>c2 [label = "SYN+ACK(seq=z,ack=w+1, MP_JOIN)\n\n"];
|||;
c2=>s [label="ACK(ack=z+1))\n\n"];
|||;
c2=> s [label="Second Data(seq=w+1,DSS(seq=idsn+1),data=b)\n\n"];
|||;
}

Without an agreement on the initial DSN, the server would not know whether the first data that it receives on the second subflow is the initial data at the Multipath TCP level or not.