The intent was to run custom code after the user is done modifying the socket,
for example to update a (not yet existing) port->socket map in SocketSet. However
this wouldn't work, since the SocketRef would have to borrow the SocketSet at
the same time as the Socket to be able to notify the SocketSet.
I believe such indexing can be achieved by setting a "dirty" bit *before* giving
the socket to the user, then on poll() reindexing all dirty sockets. This could
even be faster: if user gets a socket multiple times between polls, it'd be reindexed
only once.
- Add `medium` in `DeviceCapabilities`.
- Rename EthernetInterface to Interface.
- Add support to Interface for both Ethernet and IP mediums. The medium to use is detected from `device.capabilities().medium`.
- Ethernet-only features are gated behind the "ethernet" feature, as before.
- IP features are always enabled for now.
These were flagged by `cargo clippy`:
warning: you seem to be trying to use match for destructuring a
single pattern. Consider using `if let`
warning: called `.nth(0)` on a `std::iter::Iterator`, when `.next()`
is equivalent
warning: using `write!()` with a format string that ends in a single
newline
warning: useless conversion to the same type:
`smoltcp::wire::Ipv4Address`
warning: called `map(f)` on an `Option` value where `f` is a closure
that returns the unit type `()`
warning: returning the result of a `let` binding from a block
warning: use of `unwrap_or` followed by a function call
The previous model was flawed. Consider the following case:
* The main loop looks as follows (pseudocode):
loop {
let _ = (tcp:1234).read_all()
wait(iface.poll())
}
* The remote end is continuously transmitting data and at some
point fills the window of (tcp:1234), stopping the transmission
afterwards.
* The local end processes the packets and, as a part of egress
routine, emits an ACK. That also updates the window, and
the socket's poll_at() routine returns None, since there is
nothing to transmit or retransmit.
* The local end now waits indefinitely even though it can start
processing the data in the socket buffers right now.
To be precise, I'm talking about IPX, AppleTalk and DECnet here,
not things like PPPoE, ATAoE, FCoE, or PTP, which make sense
to implement on top of EthernetInterface but do not work on
the same level on top of it as IP.
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.