In this section, we will incrementally develop the sender and receiver sides of a
reliable data transfer protocol, considering increasingly complex models of the underlying channel. For example, we’ll consider what protocol mechanisms are needed when
the underlying channel can corrupt bits or lose entire packets. One assumption we’ll
adopt throughout our discussion here is that packets will be delivered in the order in
which they were sent, with some packets possibly being lost; that is, the underlying
channel will not reorder packets. Figure 3.8(b) illustrates the interfaces for our data
transfer protocol. The sending side of the data transfer protocol will be invoked from
above by a call to rdt_send(). It will pass the data to be delivered to the upper layer
at the receiving side. (Here rdt stands for reliable data transfer protocol and _send