Commit Graph

79 Commits

Author SHA1 Message Date
Egor Karavaev 0e88617b82 Uncomment associated constants. 2017-09-24 23:25:18 +00:00
whitequark a1b2605af7 Revert "Keep dispatching packets from a socket as long as there are any."
This reverts commit 51b2f18d1165bf7257de8894df101299cc93b094.

There's no throughput difference so far as I could measure, but
this greatly increases worst-case latency. At some later point
we could perhaps pass a deadline to the poll function, but for now
reverting this is simple enough.
2017-09-22 18:09:18 +00:00
whitequark 05a480575c Keep dispatching packets from a socket as long as there are any.
Typically, the poll function is used as a part of a larger RTOS.
If we only dispatch one packet per socket per poll() call,
then we have to wait for a complete scheduler roundtrip,
which is potentially a lot of time, and as a result we are
not filling the peer's window efficiently.
2017-09-22 17:55:49 +00:00
Egor Karavaev 8404fe908c Factor out TcpSocket::accepts. 2017-09-08 00:57:42 +00:00
Egor Karavaev 02b699e18c Factor out UdpSocket::accepts. 2017-09-08 00:57:19 +00:00
Egor Karavaev b4d6a53e34 Factor out RawSocket::accepts. 2017-09-08 00:56:42 +00:00
whitequark 8876d71802 According to RFC 1122, unsupported IP options MUST be ignored. 2017-09-01 19:31:09 +00:00
whitequark 7db21529e5 An unaddressable egress packet should not be a reportable error. 2017-09-01 10:30:56 +00:00
whitequark b585fbd368 Exhaustion of transmit buffers should not be a reportable error. 2017-08-31 16:27:50 +00:00
whitequark c2bc20e9bf Move the TCP receive window clamping hack downwards in stack.
Otherwise, our response ACKs did not get the clamping treatment,
and severe packet loss resulted.

Also, explain why it's needed and how it works.
2017-08-30 14:00:14 +00:00
whitequark 5a066fbc6c Return from EthernetInterface::poll() on errors, don't swallow them.
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.
2017-08-30 10:20:11 +00:00
whitequark 996389d653 Compute soft deadline in poll() and use nonblocking sockets.
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.
2017-08-29 19:47:11 +00:00
whitequark cdf236412f Clarify a function name. 2017-08-28 12:45:33 +00:00
whitequark 695c61fd05 Break up the EthernetInterface::dispatch macro atrocity into functions.
There wasn't any real reason for it to be a macro, it was ugly
and unreadable, and it resulted in combinatorial bloat when compiled.
2017-08-28 05:49:56 +00:00
whitequark 34db543cac Factor out packet parsing from Socket::process.
Not only is it incredibly wasteful, but this information is
in any case already necessary within the EthernetInterface::process_*
methods.
2017-08-28 05:48:16 +00:00
whitequark 379bc60924 Get rid of unused arguments in Socket::{process,dispatch}.
I've left those "for consistency" but it just implies data
dependencies where there are none, and bloats signatures.
2017-08-28 04:14:25 +00:00
whitequark 760174048d Get rid of IpPayload and indirection in Socket::dispatch.
This was just completely pointless, and only served to obfuscate
the data path and make testing harder.
2017-08-28 03:56:34 +00:00
whitequark bab5c0b7aa Unify EthernetInterface::{send_response,emit} transmit paths. 2017-08-28 02:11:04 +00:00
whitequark 1d01189278 Use FnOnce, not FnMut, in Socket::dispatch() functions.
There was never any reason to use FnMut and this significantly
simplifies the job of the borrow checker.
2017-08-28 00:59:33 +00:00
whitequark 5b2de544c8 Radically simplify and optimize TCP packet dispatch.
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.
2017-08-25 03:53:31 +00:00
whitequark 9d0084171f Rework responses to TCP packets and factor in RST replies to TcpSocket. 2017-08-22 22:32:05 +00:00
whitequark 7c9a072dd2 Fix a typo that broke ARP replies. 2017-08-22 07:44:43 +00:00
whitequark 925e13b61a Simplify ARP handling code in EthernetInterface. 2017-08-21 07:28:38 +00:00
whitequark be1038f382 Assert that the transmit frame returned by driver has right length.
We checked for frames too short before, but frames too long are
troublesome too, since e.g. TCP and UDP do not carry an explicit
payload length in their headers.
2017-08-06 15:09:55 +00:00
whitequark 8d8a4ea583 Get rid of Result<_, ()>.
The use of this type has several drawbacks:
  * It does not allow distinguishing between different error
    conditions. In fact, we wrongly conflated some of them
    before this commit.
  * It does not allow propagation via ? and requires manual use
    of map_err, which is especially tiresome for downstream code.
  * It prevents us from expanding the set of error conditions
    even if right now we have only one.
  * It prevents us from blanket using Result<T> everywhere
    (a nitpick at most).

Instead, use Result<T, Error> everywhere, and differentiate error
conditions where applicable.
2017-07-27 13:55:47 +00:00
whitequark d35fd9940e Fix ICMP error returned by EthernetInterface for unknown IP protocols. 2017-07-24 07:07:43 +00:00
whitequark 936bd44f8f Clean up socket error handling in EthernetInterface. 2017-07-24 07:01:35 +00:00
whitequark c8d714cd87 Reorganize EthernetInterface impl. NFC. 2017-07-24 06:56:06 +00:00
whitequark b97cacd521 Inject the current timestamp into Device::{transmit,receive}.
Various parts of smoltcp require an arrow of time; a monotonically
increasing timestamp. Most obviously this is TCP sockets, but
the tracer and the pcap writer devices also benefit from having
timestamps. There are a few ways this could be implemented:
  1. using a static Cell, global for the entire smoltcp crate;
  2. using a static method on Device;
  3. using an instance method on Device;
  4. passing the current timestamp into *Interface::poll.

The first two options are undesirable because they create a notion
of global clock, and interfere e.g. with mocking.
The third option is undesirable because not all devices are
inherently tied to a particular clock, e.g. a loopback device isn't.

Therefore, the timestamp is injected into both sockets and devices
through the *Interface::poll method.
2017-07-23 09:48:14 +00:00
whitequark 6ad8fea31f Fix a typo in 5c3fc493. 2017-06-27 21:51:56 +00:00
whitequark 04bd8a0051 Discard packets with non-unicast source addresses at IP level.
This is required by RFC 1122 and helps avoid "broadcast storms".
2017-06-26 17:01:23 +00:00
Egor Karavaev 4f2804e104 Don't reply to a TCP RST packet with another TCP RST packet. 2017-06-26 05:48:30 +00:00
Egor Karavaev 1e8cd1a65f Refactor EthernetInterface::poll.
Also, after this commit, we stop iterating over TCP/UDP sockets after
finding one that accepts the packet.
2017-06-26 05:48:27 +00:00
whitequark b86d22701d Expose PSH flag in TcpRepr. 2017-06-25 08:20:25 +00:00
whitequark 74823b0dff try! → ? 2017-06-24 16:34:32 +00:00
whitequark 8b27330c8b Do not attempt to validate length of packets being emitted.
This is a form of an uninitialized read bug; although safe it caused
panics. In short, transmit buffers received from the network stack
should be considered uninitialized (in practice they will often
contain previously transmitted packets or parts thereof). Wrapping
them with the only method we had (e.g. Ipv4Packet) treated the buffer
as if it contained a valid incoming packet, which can easily fail
with Error::Truncated.

This commit splits every `fn new(buffer: T) -> Result<Self, Error>`
method on a `Packet` into three smaller ones:
  * `fn check_len(&self) -> Result<(), Error>`, purely a validator;
  * `fn new(T) -> Self`, purely a wrapper;
  * `fn new_checked(T) -> Result<Self, Error>`, a validating wrapper.

This makes it easy to process ingress packets (using `new_checked`),
egress packets (using `new`), and, if needed, maintain the invariants
at any point during packet construction (using `check_len`).

Fixes #17.
2017-06-24 11:42:32 +00:00
whitequark be29789192 Fix an unimplemented!() invocation that should be unreachable!(). 2017-06-22 00:38:45 +00:00
whitequark 83cf86f1d0 Unbreak parsing of ICMP unreachable messages.
Fixes #16.
2017-06-21 04:08:33 +00:00
Egor Karavaev ca56baca65 Add `RawSocket`. 2017-06-21 03:29:31 +00:00
whitequark 1d46ccf432 fn Device::mtu() -> usize → Device::limits() -> DeviceLimits 2017-03-07 11:10:26 +00:00
whitequark 393ebbe682 Don't put non-unicast (IP or Ethernet) addresses into ARP cache.
Thanks @little-dude for pointing this out--it's probably a DoS bug.
2017-03-07 06:32:18 +00:00
whitequark 5137608aed Follow-up to b9e79d19; always process broadcast frames. 2017-03-06 04:00:13 +00:00
whitequark d25eebc0ef Ignore Ethernet frames for which we aren't a destination. 2017-03-06 03:58:19 +00:00
whitequark 0d32fcee5b Send an ARP request when the destination is not in cache. 2017-03-05 04:59:51 +00:00
whitequark bc1d65ea89 Send the TCP MSS option. 2017-01-27 02:56:27 +00:00
whitequark 077513fda6 Add support for TCP MSS option in TCP representation. 2017-01-27 02:56:27 +00:00
whitequark 591993014e Reject, not accept, TCP RST packets in LISTEN state.
These packets may have been destined for a different socket.
2017-01-17 04:33:37 +00:00
whitequark 578d7bce5f Calculate IP payload length from the total length field.
Before this commit, IP payload length was calculated by subtracting
the IP header length from the total underlying buffer length, which
fails if the underlying buffer has padding, e.g. like Ethernet
does.
2017-01-14 11:07:06 +00:00
whitequark 362c954624 Make interfaces not own the sockets. 2017-01-11 05:25:54 +00:00
whitequark 234e5ef29e Implement socket sets. 2017-01-11 04:05:41 +00:00