set_len() with a positive length change is better represented
with enqueue(), and set_len() with a negative length change
is not really a valid operation on its own.
This also makes TcpSocket::{send,recv}_slice slightly more efficient
in case when the slice wraps around the corresponding buffer,
halving the necessary amount of calls.
This is prohibited by RFC 1122. Instead, aggregate them, and respond
once in the egress function.
However, still instantly send challenge ACKs to trigger fast
retransmit.
Commit 21282fdb was not completely sufficient because e.g. receiving
one octet and then blocking meant that an ACK with window length
of one is then sent, and this isn't motivating the other TCP stacks
all that much.
In any case, preemptively notifying the peer of window size increase
can only be beneficial, modulo network congestion.
Zero is a valid sequence number, treating it as an absence of value
isn't any good. This is unlikely to cause any real harm but it
just isn't good practice, nor does it make for understandable code.
These functions only skipped the header, but what they should have
done is cut the packet at its total length and skip the header.
Otherwise, if the buffer the IP packet is constructed from contains
padding, such as Ethernet packets, the payload would be too long.
We still print them into our debug log though, because it has more
context; the caller may opt to ignore any poll errors and only
use the smoltcp debug log as a, well, debugging aid, or it could
print user-visible warnings to alert the user to unusual network
conditions.
Before this commit, if the amount of data in the buffer caused it
to be split among many outgoing packets, and retransmit timer
was active, the socket would behave very erratically and flood
the peer.
Before this commit, anything that touched RawSocket or TapInterface
worked partly by accident and partly because of a horrible crutch
that resulted in massive latencies as well as inevitable packet loss
every time an ARP request had to be issued. Also, there was no way
to use poll() other than by continuously calling it in a busy loop.
After this commit, poll() indicates when the earliest timer expires,
and so the caller can sleep until that moment (or until packets
arrive).
Note that there is a subtle problem remaining: every time poll()
is called, every socket with a pending outbound packet whose
IP address doesn't correspond to a MAC address will send a new
ARP request, resulting in potentially a whole lot of such requests.
ARP rate limiting is a separate topic though.
We don't transmit anything in FIN-WAIT-2, so we don't need the timer
running, or we'll get spurious log messages about retransmissions.
This also makes logic cleaner, although with no functional change.
This is done for simplification. FIN implies PSH, RST doesn't have
any meaning with PSH, and SYN|PSH only makes sense in the context
of TCP Fast Open, in the context of which, any data in the original
SYN already implies PSH.
This commit completely reworks packet dispatch in TCP sockets,
and brings significant improvements to processing as well.
In particular:
* Challenge ACKs now do not reset retransmit timer; instead,
TcpSocket::process directly returns a TcpRepr without altering
any internal state at all.
* Retransmit and close (aka TIME-WAIT) timers are unified
and restructured into a enum that actually matches semantics
of the timers.
* If a packet cannot be emitted, no internal state is changed.
* The dispatch of RST packets in case of connection abort
is brought in line with dispatch of all other packets.
* Packet dispatch now follows a series of steps with clean
separation of concerns, like packet processing:
1. If we should retransmit, update state to assume that
all in-flight packets are lost.
2. Prepare the packet that would be sent next, considering
the in-flight packets, if any.
3. Check if the packet contains anything new, or it's the same
as the one already in flight. If it is, bail.
4. Finalize and try to actually transmit the packet.
If we can't do that, bail.
5. Update the internal state to reflect that the packet
we've just sent is in flight.