2017-01-10 19:37:12 +08:00
|
|
|
use managed::{Managed, ManagedSlice};
|
2016-12-15 13:15:00 +08:00
|
|
|
|
2017-07-27 21:51:02 +08:00
|
|
|
use {Error, Result};
|
2016-12-12 10:39:46 +08:00
|
|
|
use phy::Device;
|
2016-12-20 21:54:11 +08:00
|
|
|
use wire::{EthernetAddress, EthernetProtocol, EthernetFrame};
|
2016-12-12 15:19:53 +08:00
|
|
|
use wire::{ArpPacket, ArpRepr, ArpOperation};
|
2016-12-26 19:20:20 +08:00
|
|
|
use wire::{Ipv4Packet, Ipv4Repr};
|
2016-12-21 03:18:35 +08:00
|
|
|
use wire::{Icmpv4Packet, Icmpv4Repr, Icmpv4DstUnreachable};
|
2016-12-26 19:20:20 +08:00
|
|
|
use wire::{IpAddress, IpProtocol, IpRepr};
|
2016-12-21 03:18:35 +08:00
|
|
|
use wire::{TcpPacket, TcpRepr, TcpControl};
|
2017-06-26 00:08:32 +08:00
|
|
|
use socket::{Socket, SocketSet, RawSocket, TcpSocket, UdpSocket, AsSocket};
|
2017-01-11 13:25:54 +08:00
|
|
|
use super::ArpCache;
|
2016-12-12 10:39:46 +08:00
|
|
|
|
|
|
|
/// An Ethernet network interface.
|
2016-12-15 13:15:00 +08:00
|
|
|
///
|
|
|
|
/// The network interface logically owns a number of other data structures; to avoid
|
|
|
|
/// a dependency on heap allocation, it instead owns a `BorrowMut<[T]>`, which can be
|
|
|
|
/// a `&mut [T]`, or `Vec<T>` if a heap is available.
|
2017-01-11 13:25:54 +08:00
|
|
|
pub struct Interface<'a, 'b, 'c, DeviceT: Device + 'a> {
|
2017-01-10 19:37:12 +08:00
|
|
|
device: Managed<'a, DeviceT>,
|
2017-01-11 13:25:54 +08:00
|
|
|
arp_cache: Managed<'b, ArpCache>,
|
2016-12-12 15:19:53 +08:00
|
|
|
hardware_addr: EthernetAddress,
|
2017-01-11 13:25:54 +08:00
|
|
|
protocol_addrs: ManagedSlice<'c, IpAddress>,
|
2016-12-12 10:39:46 +08:00
|
|
|
}
|
|
|
|
|
2017-06-26 00:08:32 +08:00
|
|
|
enum Response<'a> {
|
|
|
|
Nop,
|
|
|
|
Arp(ArpRepr),
|
|
|
|
Icmpv4(Ipv4Repr, Icmpv4Repr<'a>),
|
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 10:59:51 +08:00
|
|
|
Tcp((IpRepr, TcpRepr<'a>))
|
2017-06-26 00:08:32 +08:00
|
|
|
}
|
|
|
|
|
2017-01-11 13:25:54 +08:00
|
|
|
impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
2016-12-12 10:39:46 +08:00
|
|
|
/// Create a network interface using the provided network device.
|
|
|
|
///
|
2016-12-15 13:15:00 +08:00
|
|
|
/// # Panics
|
|
|
|
/// See the restrictions on [set_hardware_addr](#method.set_hardware_addr)
|
|
|
|
/// and [set_protocol_addrs](#method.set_protocol_addrs) functions.
|
2017-01-11 13:25:54 +08:00
|
|
|
pub fn new<DeviceMT, ArpCacheMT, ProtocolAddrsMT>
|
|
|
|
(device: DeviceMT, arp_cache: ArpCacheMT,
|
|
|
|
hardware_addr: EthernetAddress, protocol_addrs: ProtocolAddrsMT) ->
|
|
|
|
Interface<'a, 'b, 'c, DeviceT>
|
2017-01-10 19:37:12 +08:00
|
|
|
where DeviceMT: Into<Managed<'a, DeviceT>>,
|
2017-01-11 13:25:54 +08:00
|
|
|
ArpCacheMT: Into<Managed<'b, ArpCache>>,
|
|
|
|
ProtocolAddrsMT: Into<ManagedSlice<'c, IpAddress>>, {
|
2017-01-10 19:37:12 +08:00
|
|
|
let device = device.into();
|
|
|
|
let arp_cache = arp_cache.into();
|
2017-01-11 13:25:54 +08:00
|
|
|
let protocol_addrs = protocol_addrs.into();
|
2017-01-10 19:37:12 +08:00
|
|
|
|
2016-12-15 13:15:00 +08:00
|
|
|
Self::check_hardware_addr(&hardware_addr);
|
2017-01-10 19:37:12 +08:00
|
|
|
Self::check_protocol_addrs(&protocol_addrs);
|
2016-12-12 10:39:46 +08:00
|
|
|
Interface {
|
2016-12-12 15:19:53 +08:00
|
|
|
device: device,
|
|
|
|
arp_cache: arp_cache,
|
2016-12-15 13:15:00 +08:00
|
|
|
hardware_addr: hardware_addr,
|
|
|
|
protocol_addrs: protocol_addrs,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_hardware_addr(addr: &EthernetAddress) {
|
|
|
|
if addr.is_multicast() {
|
|
|
|
panic!("hardware address {} is not unicast", addr)
|
2016-12-12 10:39:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the hardware address of the interface.
|
|
|
|
pub fn hardware_addr(&self) -> EthernetAddress {
|
|
|
|
self.hardware_addr
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set the hardware address of the interface.
|
|
|
|
///
|
|
|
|
/// # Panics
|
2016-12-12 15:19:53 +08:00
|
|
|
/// This function panics if the address is not unicast.
|
2016-12-12 10:39:46 +08:00
|
|
|
pub fn set_hardware_addr(&mut self, addr: EthernetAddress) {
|
2016-12-15 13:15:00 +08:00
|
|
|
self.hardware_addr = addr;
|
|
|
|
Self::check_hardware_addr(&self.hardware_addr);
|
|
|
|
}
|
2016-12-12 15:19:53 +08:00
|
|
|
|
2016-12-20 21:54:11 +08:00
|
|
|
fn check_protocol_addrs(addrs: &[IpAddress]) {
|
2016-12-15 13:15:00 +08:00
|
|
|
for addr in addrs {
|
|
|
|
if !addr.is_unicast() {
|
|
|
|
panic!("protocol address {} is not unicast", addr)
|
|
|
|
}
|
|
|
|
}
|
2016-12-12 10:39:46 +08:00
|
|
|
}
|
2016-12-12 15:19:53 +08:00
|
|
|
|
|
|
|
/// Get the protocol addresses of the interface.
|
2016-12-20 21:54:11 +08:00
|
|
|
pub fn protocol_addrs(&self) -> &[IpAddress] {
|
2017-01-10 19:37:12 +08:00
|
|
|
self.protocol_addrs.as_ref()
|
2016-12-12 15:19:53 +08:00
|
|
|
}
|
|
|
|
|
2016-12-15 13:15:00 +08:00
|
|
|
/// Update the protocol addresses of the interface.
|
2016-12-12 15:19:53 +08:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
/// This function panics if any of the addresses is not unicast.
|
2017-01-11 13:25:54 +08:00
|
|
|
pub fn update_protocol_addrs<F: FnOnce(&mut ManagedSlice<'c, IpAddress>)>(&mut self, f: F) {
|
2016-12-21 06:57:21 +08:00
|
|
|
f(&mut self.protocol_addrs);
|
2017-01-10 19:37:12 +08:00
|
|
|
Self::check_protocol_addrs(&self.protocol_addrs)
|
2016-12-12 15:19:53 +08:00
|
|
|
}
|
|
|
|
|
2016-12-17 12:15:12 +08:00
|
|
|
/// Check whether the interface has the given protocol address assigned.
|
2016-12-20 21:54:11 +08:00
|
|
|
pub fn has_protocol_addr<T: Into<IpAddress>>(&self, addr: T) -> bool {
|
2016-12-12 15:19:53 +08:00
|
|
|
let addr = addr.into();
|
2017-01-10 19:37:12 +08:00
|
|
|
self.protocol_addrs.iter().any(|&probe| probe == addr)
|
2016-12-12 15:19:53 +08:00
|
|
|
}
|
|
|
|
|
2017-01-11 13:25:54 +08:00
|
|
|
/// Receive and process a packet, if available, and then transmit a packet, if necessary,
|
|
|
|
/// handling the given set of sockets.
|
2016-12-31 16:35:07 +08:00
|
|
|
///
|
|
|
|
/// The timestamp is a monotonically increasing number of milliseconds.
|
2017-07-27 21:51:02 +08:00
|
|
|
pub fn poll(&mut self, sockets: &mut SocketSet, timestamp: u64) -> Result<()> {
|
2016-12-20 08:07:02 +08:00
|
|
|
// First, transmit any outgoing packets.
|
|
|
|
loop {
|
2017-06-25 00:34:32 +08:00
|
|
|
if self.emit(sockets, timestamp)? { break }
|
2016-12-20 08:07:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now, receive any incoming packets.
|
2017-07-23 17:44:54 +08:00
|
|
|
let rx_buffer = self.device.receive(timestamp)?;
|
2017-06-25 00:34:32 +08:00
|
|
|
let eth_frame = EthernetFrame::new_checked(&rx_buffer)?;
|
2016-12-13 23:18:56 +08:00
|
|
|
|
2017-06-26 00:08:32 +08:00
|
|
|
// Ignore any packets not directed to our hardware address.
|
2017-03-06 12:00:13 +08:00
|
|
|
if !eth_frame.dst_addr().is_broadcast() &&
|
|
|
|
eth_frame.dst_addr() != self.hardware_addr {
|
|
|
|
return Ok(())
|
|
|
|
}
|
2017-03-06 11:58:19 +08:00
|
|
|
|
2017-06-26 00:08:32 +08:00
|
|
|
let response = match eth_frame.ethertype() {
|
|
|
|
EthernetProtocol::Arp =>
|
|
|
|
self.process_arp(ð_frame)?,
|
|
|
|
EthernetProtocol::Ipv4 =>
|
|
|
|
self.process_ipv4(sockets, timestamp, ð_frame)?,
|
|
|
|
// Drop all other traffic.
|
|
|
|
_ => return Err(Error::Unrecognized),
|
|
|
|
};
|
2016-12-13 07:22:59 +08:00
|
|
|
|
2017-07-23 17:44:54 +08:00
|
|
|
self.send_response(timestamp, response)
|
2017-06-26 00:08:32 +08:00
|
|
|
}
|
2016-12-23 15:31:02 +08:00
|
|
|
|
2017-06-26 00:08:32 +08:00
|
|
|
// Snoop all ARP traffic, and respond to ARP packets directed at us.
|
|
|
|
fn process_arp<'frame, T: AsRef<[u8]>>
|
|
|
|
(&mut self, eth_frame: &EthernetFrame<&'frame T>) ->
|
2017-07-27 21:51:02 +08:00
|
|
|
Result<Response<'frame>> {
|
2017-06-26 00:08:32 +08:00
|
|
|
let arp_packet = ArpPacket::new_checked(eth_frame.payload())?;
|
|
|
|
let arp_repr = ArpRepr::parse(&arp_packet)?;
|
|
|
|
|
|
|
|
match arp_repr {
|
2017-08-21 15:08:06 +08:00
|
|
|
// Respond to ARP requests aimed at us, and fill the ARP cache from all ARP
|
|
|
|
// requests and replies, to minimize the chance that we have to perform
|
|
|
|
// an explicit ARP request.
|
2017-06-26 00:08:32 +08:00
|
|
|
ArpRepr::EthernetIpv4 {
|
2017-08-21 15:08:06 +08:00
|
|
|
operation, source_hardware_addr, source_protocol_addr, target_protocol_addr, ..
|
2017-06-26 00:08:32 +08:00
|
|
|
} => {
|
|
|
|
if source_protocol_addr.is_unicast() && source_hardware_addr.is_unicast() {
|
|
|
|
self.arp_cache.fill(&source_protocol_addr.into(),
|
|
|
|
&source_hardware_addr);
|
2017-08-21 15:08:06 +08:00
|
|
|
} else {
|
|
|
|
// Discard packets with non-unicast source addresses.
|
|
|
|
net_debug!("non-unicast source in {}", arp_repr);
|
|
|
|
return Err(Error::Malformed)
|
2017-03-07 14:32:09 +08:00
|
|
|
}
|
2016-12-23 15:31:02 +08:00
|
|
|
|
2017-08-22 15:44:43 +08:00
|
|
|
if operation == ArpOperation::Request &&
|
2017-08-21 15:08:06 +08:00
|
|
|
self.has_protocol_addr(target_protocol_addr) {
|
2017-06-26 00:08:32 +08:00
|
|
|
Ok(Response::Arp(ArpRepr::EthernetIpv4 {
|
|
|
|
operation: ArpOperation::Reply,
|
|
|
|
source_hardware_addr: self.hardware_addr,
|
|
|
|
source_protocol_addr: target_protocol_addr,
|
|
|
|
target_hardware_addr: source_hardware_addr,
|
|
|
|
target_protocol_addr: source_protocol_addr
|
|
|
|
}))
|
|
|
|
} else {
|
|
|
|
Ok(Response::Nop)
|
2017-06-18 18:14:20 +08:00
|
|
|
}
|
2017-06-26 00:08:32 +08:00
|
|
|
}
|
2017-06-18 18:14:20 +08:00
|
|
|
|
2017-06-26 00:08:32 +08:00
|
|
|
_ => Err(Error::Unrecognized)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_ipv4<'frame, T: AsRef<[u8]>>
|
|
|
|
(&mut self, sockets: &mut SocketSet, timestamp: u64,
|
|
|
|
eth_frame: &EthernetFrame<&'frame T>) ->
|
2017-07-27 21:51:02 +08:00
|
|
|
Result<Response<'frame>> {
|
2017-06-26 00:08:32 +08:00
|
|
|
let ipv4_packet = Ipv4Packet::new_checked(eth_frame.payload())?;
|
|
|
|
let ipv4_repr = Ipv4Repr::parse(&ipv4_packet)?;
|
|
|
|
|
2017-06-28 05:51:56 +08:00
|
|
|
if !ipv4_repr.src_addr.is_unicast() {
|
2017-06-27 01:01:23 +08:00
|
|
|
// Discard packets with non-unicast source addresses.
|
2017-08-21 15:08:06 +08:00
|
|
|
net_debug!("non-unicast source in {}", ipv4_repr);
|
2017-06-27 01:01:23 +08:00
|
|
|
return Err(Error::Malformed)
|
|
|
|
}
|
|
|
|
|
|
|
|
if eth_frame.src_addr().is_unicast() {
|
2017-06-26 00:08:32 +08:00
|
|
|
// Fill the ARP cache from IP header of unicast frames.
|
|
|
|
self.arp_cache.fill(&IpAddress::Ipv4(ipv4_repr.src_addr),
|
|
|
|
ð_frame.src_addr());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pass every IP packet to all raw sockets we have registered.
|
|
|
|
let mut handled_by_raw_socket = false;
|
|
|
|
for raw_socket in sockets.iter_mut().filter_map(
|
|
|
|
<Socket as AsSocket<RawSocket>>::try_as_socket) {
|
|
|
|
match raw_socket.process(timestamp, &IpRepr::Ipv4(ipv4_repr),
|
|
|
|
ipv4_packet.payload()) {
|
2017-07-24 15:01:35 +08:00
|
|
|
// The packet is valid and handled by socket.
|
2017-06-26 00:08:32 +08:00
|
|
|
Ok(()) => handled_by_raw_socket = true,
|
2017-07-24 15:01:35 +08:00
|
|
|
// The packet isn't addressed to the socket, or cannot be accepted by it.
|
|
|
|
Err(Error::Rejected) | Err(Error::Exhausted) => (),
|
|
|
|
// Raw sockets either accept or reject packets, not parse them.
|
2017-06-26 00:08:32 +08:00
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !self.has_protocol_addr(ipv4_repr.dst_addr) {
|
|
|
|
// Ignore IP packets not directed at us.
|
|
|
|
return Ok(Response::Nop)
|
2016-12-12 20:30:35 +08:00
|
|
|
}
|
2016-12-12 15:19:53 +08:00
|
|
|
|
2017-06-26 00:08:32 +08:00
|
|
|
match ipv4_repr.protocol {
|
|
|
|
IpProtocol::Icmp =>
|
|
|
|
Self::process_icmpv4(ipv4_repr, ipv4_packet.payload()),
|
|
|
|
IpProtocol::Udp =>
|
|
|
|
Self::process_udpv4(sockets, timestamp, ipv4_repr, ipv4_packet.payload()),
|
2017-08-23 06:32:05 +08:00
|
|
|
IpProtocol::Tcp =>
|
|
|
|
Self::process_tcp(sockets, timestamp, ipv4_repr.into(), ipv4_packet.payload()),
|
2017-07-24 14:56:06 +08:00
|
|
|
_ if handled_by_raw_socket =>
|
|
|
|
Ok(Response::Nop),
|
2017-06-26 00:08:32 +08:00
|
|
|
_ => {
|
2017-07-24 14:56:06 +08:00
|
|
|
let icmp_reply_repr = Icmpv4Repr::DstUnreachable {
|
2017-07-24 15:07:43 +08:00
|
|
|
reason: Icmpv4DstUnreachable::ProtoUnreachable,
|
2017-07-24 14:56:06 +08:00
|
|
|
header: ipv4_repr,
|
|
|
|
data: &ipv4_packet.payload()[0..8]
|
|
|
|
};
|
|
|
|
let ipv4_reply_repr = Ipv4Repr {
|
|
|
|
src_addr: ipv4_repr.dst_addr,
|
|
|
|
dst_addr: ipv4_repr.src_addr,
|
|
|
|
protocol: IpProtocol::Icmp,
|
|
|
|
payload_len: icmp_reply_repr.buffer_len()
|
|
|
|
};
|
|
|
|
Ok(Response::Icmpv4(ipv4_reply_repr, icmp_reply_repr))
|
2017-06-26 00:08:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_icmpv4<'frame>(ipv4_repr: Ipv4Repr, ip_payload: &'frame [u8]) ->
|
2017-07-27 21:51:02 +08:00
|
|
|
Result<Response<'frame>> {
|
2017-06-26 00:08:32 +08:00
|
|
|
let icmp_packet = Icmpv4Packet::new_checked(ip_payload)?;
|
|
|
|
let icmp_repr = Icmpv4Repr::parse(&icmp_packet)?;
|
|
|
|
|
|
|
|
match icmp_repr {
|
|
|
|
// Respond to echo requests.
|
|
|
|
Icmpv4Repr::EchoRequest {
|
|
|
|
ident, seq_no, data
|
|
|
|
} => {
|
|
|
|
let icmp_reply_repr = Icmpv4Repr::EchoReply {
|
|
|
|
ident: ident,
|
|
|
|
seq_no: seq_no,
|
|
|
|
data: data
|
|
|
|
};
|
|
|
|
let ipv4_reply_repr = Ipv4Repr {
|
|
|
|
src_addr: ipv4_repr.dst_addr,
|
|
|
|
dst_addr: ipv4_repr.src_addr,
|
|
|
|
protocol: IpProtocol::Icmp,
|
|
|
|
payload_len: icmp_reply_repr.buffer_len()
|
|
|
|
};
|
|
|
|
Ok(Response::Icmpv4(ipv4_reply_repr, icmp_reply_repr))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ignore any echo replies.
|
|
|
|
Icmpv4Repr::EchoReply { .. } => Ok(Response::Nop),
|
|
|
|
|
|
|
|
// FIXME: do something correct here?
|
|
|
|
_ => Err(Error::Unrecognized),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-24 14:56:06 +08:00
|
|
|
fn process_udpv4<'frame>(sockets: &mut SocketSet, timestamp: u64,
|
|
|
|
ipv4_repr: Ipv4Repr, ip_payload: &'frame [u8]) ->
|
2017-07-27 21:51:02 +08:00
|
|
|
Result<Response<'frame>> {
|
2017-07-24 14:56:06 +08:00
|
|
|
let ip_repr = IpRepr::Ipv4(ipv4_repr);
|
|
|
|
|
|
|
|
for udp_socket in sockets.iter_mut().filter_map(
|
|
|
|
<Socket as AsSocket<UdpSocket>>::try_as_socket) {
|
|
|
|
match udp_socket.process(timestamp, &ip_repr, ip_payload) {
|
2017-07-24 15:01:35 +08:00
|
|
|
// The packet is valid and handled by socket.
|
2017-07-24 14:56:06 +08:00
|
|
|
Ok(()) => return Ok(Response::Nop),
|
2017-07-24 15:01:35 +08:00
|
|
|
// The packet isn't addressed to the socket.
|
2017-07-24 14:56:06 +08:00
|
|
|
Err(Error::Rejected) => continue,
|
2017-07-24 15:01:35 +08:00
|
|
|
// The packet is malformed, or addressed to the socket but cannot be accepted.
|
2017-07-24 14:56:06 +08:00
|
|
|
Err(e) => return Err(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-24 15:01:35 +08:00
|
|
|
// The packet wasn't handled by a socket, send an ICMP port unreachable packet.
|
2017-07-24 14:56:06 +08:00
|
|
|
let icmp_reply_repr = Icmpv4Repr::DstUnreachable {
|
|
|
|
reason: Icmpv4DstUnreachable::PortUnreachable,
|
|
|
|
header: ipv4_repr,
|
|
|
|
data: &ip_payload[0..8]
|
|
|
|
};
|
|
|
|
let ipv4_reply_repr = Ipv4Repr {
|
|
|
|
src_addr: ipv4_repr.dst_addr,
|
|
|
|
dst_addr: ipv4_repr.src_addr,
|
|
|
|
protocol: IpProtocol::Icmp,
|
|
|
|
payload_len: icmp_reply_repr.buffer_len()
|
|
|
|
};
|
|
|
|
Ok(Response::Icmpv4(ipv4_reply_repr, icmp_reply_repr))
|
|
|
|
}
|
|
|
|
|
2017-08-23 06:32:05 +08:00
|
|
|
fn process_tcp<'frame>(sockets: &mut SocketSet, timestamp: u64,
|
|
|
|
ip_repr: IpRepr, ip_payload: &'frame [u8]) ->
|
|
|
|
Result<Response<'frame>> {
|
2017-06-26 00:08:32 +08:00
|
|
|
for tcp_socket in sockets.iter_mut().filter_map(
|
|
|
|
<Socket as AsSocket<TcpSocket>>::try_as_socket) {
|
|
|
|
match tcp_socket.process(timestamp, &ip_repr, ip_payload) {
|
2017-07-24 15:01:35 +08:00
|
|
|
// The packet is valid and handled by socket.
|
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 10:59:51 +08:00
|
|
|
Ok(reply) => return Ok(reply.map_or(Response::Nop, Response::Tcp)),
|
2017-07-24 15:01:35 +08:00
|
|
|
// The packet isn't addressed to the socket.
|
2017-06-26 00:08:32 +08:00
|
|
|
// Send RST only if no other socket accepts the packet.
|
|
|
|
Err(Error::Rejected) => continue,
|
2017-07-24 15:01:35 +08:00
|
|
|
// The packet is malformed, or addressed to the socket but cannot be accepted.
|
2017-06-26 00:08:32 +08:00
|
|
|
Err(e) => return Err(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The packet wasn't handled by a socket, send a TCP RST packet.
|
|
|
|
let tcp_packet = TcpPacket::new_checked(ip_payload)?;
|
2017-08-23 06:32:05 +08:00
|
|
|
let tcp_repr = TcpRepr::parse(&tcp_packet, &ip_repr.src_addr(), &ip_repr.dst_addr())?;
|
|
|
|
if tcp_repr.control == TcpControl::Rst {
|
|
|
|
// Never reply to a TCP RST packet with another TCP RST packet.
|
|
|
|
Ok(Response::Nop)
|
|
|
|
} else {
|
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 10:59:51 +08:00
|
|
|
Ok(Response::Tcp(TcpSocket::rst_reply(&ip_repr, &tcp_repr)))
|
2017-06-26 00:08:32 +08:00
|
|
|
}
|
2017-06-26 00:08:32 +08:00
|
|
|
}
|
|
|
|
|
2017-07-27 21:51:02 +08:00
|
|
|
fn send_response(&mut self, timestamp: u64, response: Response) -> Result<()> {
|
2017-08-23 06:32:05 +08:00
|
|
|
macro_rules! emit_packet {
|
|
|
|
(Ethernet, $buffer_len:expr, |$frame:ident| $code:stmt) => ({
|
|
|
|
let tx_len = EthernetFrame::<&[u8]>::buffer_len($buffer_len);
|
|
|
|
let mut tx_buffer = self.device.transmit(timestamp, tx_len)?;
|
|
|
|
debug_assert!(tx_buffer.as_ref().len() == tx_len);
|
2017-08-06 23:09:05 +08:00
|
|
|
|
2017-08-23 06:32:05 +08:00
|
|
|
let mut $frame = EthernetFrame::new(&mut tx_buffer);
|
2016-12-21 03:18:35 +08:00
|
|
|
$frame.set_src_addr(self.hardware_addr);
|
|
|
|
|
2017-08-23 06:32:05 +08:00
|
|
|
$code
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
|
|
|
|
(Ip, $ip_repr:expr, |$payload:ident| $code:stmt) => ({
|
|
|
|
let ip_repr = $ip_repr.lower(&self.protocol_addrs)?;
|
|
|
|
match self.arp_cache.lookup(&ip_repr.dst_addr()) {
|
|
|
|
None => Err(Error::Unaddressable),
|
|
|
|
Some(dst_hardware_addr) => {
|
|
|
|
emit_packet!(Ethernet, ip_repr.total_len(), |frame| {
|
|
|
|
frame.set_dst_addr(dst_hardware_addr);
|
|
|
|
match ip_repr {
|
|
|
|
IpRepr::Ipv4(_) => frame.set_ethertype(EthernetProtocol::Ipv4),
|
|
|
|
_ => unreachable!()
|
|
|
|
}
|
|
|
|
|
|
|
|
ip_repr.emit(frame.payload_mut());
|
|
|
|
|
|
|
|
let $payload = &mut frame.payload_mut()[ip_repr.buffer_len()..];
|
|
|
|
$code
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2016-12-21 03:18:35 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-12-13 07:22:59 +08:00
|
|
|
match response {
|
2017-08-23 06:32:05 +08:00
|
|
|
Response::Arp(arp_repr) => {
|
|
|
|
let dst_hardware_addr =
|
|
|
|
match arp_repr {
|
|
|
|
ArpRepr::EthernetIpv4 { target_hardware_addr, .. } => target_hardware_addr,
|
|
|
|
_ => unreachable!()
|
|
|
|
};
|
2016-12-12 15:19:53 +08:00
|
|
|
|
2017-08-23 06:32:05 +08:00
|
|
|
emit_packet!(Ethernet, arp_repr.buffer_len(), |frame| {
|
|
|
|
frame.set_dst_addr(dst_hardware_addr);
|
|
|
|
frame.set_ethertype(EthernetProtocol::Arp);
|
2016-12-20 08:07:02 +08:00
|
|
|
|
2017-08-23 06:32:05 +08:00
|
|
|
let mut packet = ArpPacket::new(frame.payload_mut());
|
|
|
|
arp_repr.emit(&mut packet);
|
|
|
|
})
|
2016-12-13 07:22:59 +08:00
|
|
|
},
|
2017-08-23 06:32:05 +08:00
|
|
|
Response::Icmpv4(ipv4_repr, icmpv4_repr) => {
|
|
|
|
emit_packet!(Ip, IpRepr::Ipv4(ipv4_repr), |payload| {
|
|
|
|
icmpv4_repr.emit(&mut Icmpv4Packet::new(payload));
|
|
|
|
})
|
2016-12-12 15:19:53 +08:00
|
|
|
}
|
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 10:59:51 +08:00
|
|
|
Response::Tcp((ip_repr, tcp_repr)) => {
|
2017-08-23 06:32:05 +08:00
|
|
|
emit_packet!(Ip, ip_repr, |payload| {
|
|
|
|
tcp_repr.emit(&mut TcpPacket::new(payload),
|
|
|
|
&ip_repr.src_addr(), &ip_repr.dst_addr());
|
|
|
|
})
|
2016-12-20 08:07:02 +08:00
|
|
|
}
|
2017-08-23 06:32:05 +08:00
|
|
|
Response::Nop => Ok(())
|
2016-12-20 08:07:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-27 21:51:02 +08:00
|
|
|
fn emit(&mut self, sockets: &mut SocketSet, timestamp: u64) -> Result<bool> {
|
2017-08-28 08:59:33 +08:00
|
|
|
let mut limits = self.device.limits();
|
2017-03-07 18:56:48 +08:00
|
|
|
limits.max_transmission_unit -= EthernetFrame::<&[u8]>::header_len();
|
2016-12-20 08:07:02 +08:00
|
|
|
|
|
|
|
let mut nothing_to_transmit = true;
|
2017-01-11 13:25:54 +08:00
|
|
|
for socket in sockets.iter_mut() {
|
2017-08-28 08:59:33 +08:00
|
|
|
let result = socket.dispatch(timestamp, &limits, |repr, payload| {
|
|
|
|
let repr = repr.lower(self.protocol_addrs.as_ref())?;
|
2016-12-20 08:07:02 +08:00
|
|
|
|
2017-08-28 08:59:33 +08:00
|
|
|
match self.arp_cache.lookup(&repr.dst_addr()) {
|
2017-03-05 12:59:51 +08:00
|
|
|
Some(dst_hardware_addr) => {
|
|
|
|
let tx_len = EthernetFrame::<&[u8]>::buffer_len(repr.buffer_len() +
|
|
|
|
payload.buffer_len());
|
2017-08-28 08:59:33 +08:00
|
|
|
let mut tx_buffer = self.device.transmit(timestamp, tx_len)?;
|
2017-08-06 23:09:05 +08:00
|
|
|
debug_assert!(tx_buffer.as_ref().len() == tx_len);
|
|
|
|
|
|
|
|
let mut frame = EthernetFrame::new(&mut tx_buffer);
|
2017-08-28 08:59:33 +08:00
|
|
|
frame.set_src_addr(self.hardware_addr);
|
2017-03-05 12:59:51 +08:00
|
|
|
frame.set_dst_addr(dst_hardware_addr);
|
|
|
|
frame.set_ethertype(EthernetProtocol::Ipv4);
|
|
|
|
|
|
|
|
repr.emit(frame.payload_mut());
|
|
|
|
|
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 17:15:22 +08:00
|
|
|
let mut ip_packet = Ipv4Packet::new(frame.payload_mut());
|
2017-03-05 12:59:51 +08:00
|
|
|
payload.emit(&repr, ip_packet.payload_mut());
|
|
|
|
}
|
|
|
|
|
|
|
|
None => {
|
|
|
|
let (src_addr, dst_addr) =
|
|
|
|
match (repr.src_addr(), repr.dst_addr()) {
|
|
|
|
(IpAddress::Ipv4(src_addr), IpAddress::Ipv4(dst_addr)) =>
|
|
|
|
(src_addr, dst_addr),
|
2017-06-22 08:38:11 +08:00
|
|
|
// We've lowered all addresses to a concrete form.
|
|
|
|
_ => unreachable!()
|
2017-03-05 12:59:51 +08:00
|
|
|
};
|
2016-12-20 08:07:02 +08:00
|
|
|
|
2017-03-05 12:59:51 +08:00
|
|
|
let payload = ArpRepr::EthernetIpv4 {
|
|
|
|
operation: ArpOperation::Request,
|
2017-08-28 08:59:33 +08:00
|
|
|
source_hardware_addr: self.hardware_addr,
|
2017-03-05 12:59:51 +08:00
|
|
|
source_protocol_addr: src_addr,
|
|
|
|
target_hardware_addr: EthernetAddress::default(),
|
|
|
|
target_protocol_addr: dst_addr,
|
|
|
|
};
|
|
|
|
|
|
|
|
let tx_len = EthernetFrame::<&[u8]>::buffer_len(payload.buffer_len());
|
2017-08-28 08:59:33 +08:00
|
|
|
let mut tx_buffer = self.device.transmit(timestamp, tx_len)?;
|
2017-08-06 23:09:05 +08:00
|
|
|
debug_assert!(tx_buffer.as_ref().len() == tx_len);
|
|
|
|
|
|
|
|
let mut frame = EthernetFrame::new(&mut tx_buffer);
|
2017-08-28 08:59:33 +08:00
|
|
|
frame.set_src_addr(self.hardware_addr);
|
2017-03-05 12:59:51 +08:00
|
|
|
frame.set_dst_addr(EthernetAddress([0xff; 6]));
|
|
|
|
frame.set_ethertype(EthernetProtocol::Arp);
|
|
|
|
|
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 17:15:22 +08:00
|
|
|
let mut arp_packet = ArpPacket::new(frame.payload_mut());
|
2017-03-05 12:59:51 +08:00
|
|
|
payload.emit(&mut arp_packet);
|
|
|
|
}
|
|
|
|
}
|
2016-12-20 08:07:02 +08:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
|
|
|
|
match result {
|
|
|
|
Ok(()) => {
|
|
|
|
nothing_to_transmit = false;
|
|
|
|
break
|
2016-12-15 13:15:00 +08:00
|
|
|
}
|
2016-12-20 08:07:02 +08:00
|
|
|
Err(Error::Exhausted) => continue,
|
|
|
|
Err(e) => return Err(e)
|
2016-12-15 13:15:00 +08:00
|
|
|
}
|
2016-12-12 15:19:53 +08:00
|
|
|
}
|
2016-12-13 07:22:59 +08:00
|
|
|
|
2016-12-20 08:07:02 +08:00
|
|
|
Ok(nothing_to_transmit)
|
2016-12-12 15:19:53 +08:00
|
|
|
}
|
2016-12-12 10:39:46 +08:00
|
|
|
}
|