2017-01-10 19:37:12 +08:00
|
|
|
use managed::{Managed, ManagedSlice};
|
2016-12-15 13:15:00 +08:00
|
|
|
|
2016-12-12 15:19:53 +08:00
|
|
|
use Error;
|
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-18 18:14:20 +08:00
|
|
|
use socket::{Socket, SocketSet, RawSocket, 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-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-01-11 13:25:54 +08:00
|
|
|
pub fn poll(&mut self, sockets: &mut SocketSet, timestamp: u64) -> Result<(), Error> {
|
2016-12-13 07:22:59 +08:00
|
|
|
enum Response<'a> {
|
2016-12-12 15:19:53 +08:00
|
|
|
Nop,
|
2016-12-13 07:22:59 +08:00
|
|
|
Arp(ArpRepr),
|
2016-12-21 03:18:35 +08:00
|
|
|
Icmpv4(Ipv4Repr, Icmpv4Repr<'a>),
|
|
|
|
Tcpv4(Ipv4Repr, TcpRepr<'a>)
|
2016-12-12 15:19:53 +08:00
|
|
|
}
|
|
|
|
|
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-06-25 00:34:32 +08:00
|
|
|
let rx_buffer = self.device.receive()?;
|
|
|
|
let eth_frame = EthernetFrame::new_checked(&rx_buffer)?;
|
2016-12-13 23:18:56 +08:00
|
|
|
|
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
|
|
|
|
2016-12-13 23:18:56 +08:00
|
|
|
let mut response = Response::Nop;
|
2016-12-13 07:22:59 +08:00
|
|
|
match eth_frame.ethertype() {
|
|
|
|
// Snoop all ARP traffic, and respond to ARP packets directed at us.
|
2016-12-20 21:54:11 +08:00
|
|
|
EthernetProtocol::Arp => {
|
2017-06-25 00:34:32 +08:00
|
|
|
let arp_packet = ArpPacket::new_checked(eth_frame.payload())?;
|
|
|
|
match ArpRepr::parse(&arp_packet)? {
|
2016-12-13 06:41:34 +08:00
|
|
|
// Respond to ARP requests aimed at us, and fill the ARP cache
|
|
|
|
// from all ARP requests, including gratuitous.
|
2016-12-12 20:30:35 +08:00
|
|
|
ArpRepr::EthernetIpv4 {
|
|
|
|
operation: ArpOperation::Request,
|
|
|
|
source_hardware_addr, source_protocol_addr,
|
|
|
|
target_protocol_addr, ..
|
|
|
|
} => {
|
2017-03-07 14:32:09 +08:00
|
|
|
if source_protocol_addr.is_unicast() && source_hardware_addr.is_unicast() {
|
|
|
|
self.arp_cache.fill(&source_protocol_addr.into(),
|
|
|
|
&source_hardware_addr);
|
|
|
|
}
|
2016-12-13 06:41:34 +08:00
|
|
|
|
2016-12-12 20:30:35 +08:00
|
|
|
if self.has_protocol_addr(target_protocol_addr) {
|
|
|
|
response = 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
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
2016-12-13 06:41:34 +08:00
|
|
|
|
|
|
|
// Fill the ARP cache from gratuitous ARP replies.
|
|
|
|
ArpRepr::EthernetIpv4 {
|
|
|
|
operation: ArpOperation::Reply,
|
|
|
|
source_hardware_addr, source_protocol_addr, ..
|
|
|
|
} => {
|
2017-03-07 14:32:09 +08:00
|
|
|
if source_protocol_addr.is_unicast() && source_hardware_addr.is_unicast() {
|
|
|
|
self.arp_cache.fill(&source_protocol_addr.into(),
|
|
|
|
&source_hardware_addr);
|
|
|
|
}
|
2016-12-13 06:41:34 +08:00
|
|
|
},
|
|
|
|
|
2016-12-12 20:30:35 +08:00
|
|
|
_ => return Err(Error::Unrecognized)
|
|
|
|
}
|
|
|
|
},
|
2016-12-13 07:22:59 +08:00
|
|
|
|
2016-12-15 01:39:44 +08:00
|
|
|
// Handle IP packets directed at us.
|
2016-12-20 21:54:11 +08:00
|
|
|
EthernetProtocol::Ipv4 => {
|
2017-06-25 00:34:32 +08:00
|
|
|
let ipv4_packet = Ipv4Packet::new_checked(eth_frame.payload())?;
|
|
|
|
let ipv4_repr = Ipv4Repr::parse(&ipv4_packet)?;
|
2016-12-23 15:31:02 +08:00
|
|
|
|
|
|
|
// Fill the ARP cache from IP header.
|
2017-03-07 14:32:09 +08:00
|
|
|
if ipv4_repr.src_addr.is_unicast() && eth_frame.src_addr().is_unicast() {
|
|
|
|
self.arp_cache.fill(&IpAddress::Ipv4(ipv4_repr.src_addr),
|
|
|
|
ð_frame.src_addr());
|
|
|
|
}
|
2016-12-23 15:31:02 +08:00
|
|
|
|
2017-06-18 18:14:20 +08:00
|
|
|
// Pass every IP packet to all raw sockets we have registered.
|
|
|
|
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()) {
|
|
|
|
Ok(()) | Err(Error::Rejected) => (),
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-26 18:06:49 +08:00
|
|
|
match ipv4_repr {
|
2016-12-13 07:22:59 +08:00
|
|
|
// Ignore IP packets not directed at us.
|
|
|
|
Ipv4Repr { dst_addr, .. } if !self.has_protocol_addr(dst_addr) => (),
|
|
|
|
|
|
|
|
// Respond to ICMP packets.
|
2017-01-14 19:07:06 +08:00
|
|
|
Ipv4Repr { protocol: IpProtocol::Icmp, src_addr, dst_addr, .. } => {
|
2017-06-25 00:34:32 +08:00
|
|
|
let icmp_packet = Icmpv4Packet::new_checked(ipv4_packet.payload())?;
|
|
|
|
let icmp_repr = Icmpv4Repr::parse(&icmp_packet)?;
|
2016-12-13 07:22:59 +08:00
|
|
|
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,
|
2016-12-13 23:18:56 +08:00
|
|
|
data: data
|
2016-12-13 07:22:59 +08:00
|
|
|
};
|
2017-01-14 19:07:06 +08:00
|
|
|
let ipv4_reply_repr = Ipv4Repr {
|
|
|
|
src_addr: dst_addr,
|
|
|
|
dst_addr: src_addr,
|
|
|
|
protocol: IpProtocol::Icmp,
|
|
|
|
payload_len: icmp_reply_repr.buffer_len()
|
|
|
|
};
|
2016-12-26 18:06:49 +08:00
|
|
|
response = Response::Icmpv4(ipv4_reply_repr, icmp_reply_repr)
|
2016-12-13 07:22:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ignore any echo replies.
|
|
|
|
Icmpv4Repr::EchoReply { .. } => (),
|
|
|
|
|
|
|
|
// FIXME: do something correct here?
|
|
|
|
_ => return Err(Error::Unrecognized)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-12-15 13:15:00 +08:00
|
|
|
// Try dispatching a packet to a socket.
|
2017-01-14 19:07:06 +08:00
|
|
|
Ipv4Repr { src_addr, dst_addr, protocol, .. } => {
|
2016-12-21 03:18:35 +08:00
|
|
|
let mut handled = false;
|
2017-01-11 13:25:54 +08:00
|
|
|
for socket in sockets.iter_mut() {
|
2016-12-26 19:20:20 +08:00
|
|
|
let ip_repr = IpRepr::Ipv4(ipv4_repr);
|
2016-12-31 16:35:07 +08:00
|
|
|
match socket.process(timestamp, &ip_repr, ipv4_packet.payload()) {
|
2016-12-25 17:22:49 +08:00
|
|
|
Ok(()) => {
|
|
|
|
// The packet was valid and handled by socket.
|
|
|
|
handled = true;
|
|
|
|
break
|
|
|
|
}
|
|
|
|
Err(Error::Rejected) => {
|
|
|
|
// The packet wasn't addressed to the socket.
|
|
|
|
// For TCP, send RST only if no other socket accepts
|
|
|
|
// the packet.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
Err(Error::Malformed) => {
|
|
|
|
// The packet was addressed to the socket but is malformed.
|
|
|
|
// For TCP, send RST immediately.
|
|
|
|
break
|
|
|
|
}
|
2016-12-15 13:15:00 +08:00
|
|
|
Err(e) => return Err(e)
|
|
|
|
}
|
|
|
|
}
|
2016-12-15 01:39:44 +08:00
|
|
|
|
2016-12-21 03:18:35 +08:00
|
|
|
if !handled && protocol == IpProtocol::Tcp {
|
2017-06-25 00:34:32 +08:00
|
|
|
let tcp_packet = TcpPacket::new_checked(ipv4_packet.payload())?;
|
2017-01-17 12:33:37 +08:00
|
|
|
if !tcp_packet.rst() {
|
|
|
|
let tcp_reply_repr = TcpRepr {
|
2017-01-27 09:09:34 +08:00
|
|
|
src_port: tcp_packet.dst_port(),
|
|
|
|
dst_port: tcp_packet.src_port(),
|
|
|
|
control: TcpControl::Rst,
|
2017-06-25 16:20:25 +08:00
|
|
|
push: false,
|
2017-01-27 09:09:34 +08:00
|
|
|
seq_number: tcp_packet.ack_number(),
|
|
|
|
ack_number: Some(tcp_packet.seq_number() +
|
|
|
|
tcp_packet.segment_len()),
|
|
|
|
window_len: 0,
|
|
|
|
max_seg_size: None,
|
|
|
|
payload: &[]
|
2017-01-17 12:33:37 +08:00
|
|
|
};
|
|
|
|
let ipv4_reply_repr = Ipv4Repr {
|
|
|
|
src_addr: dst_addr,
|
|
|
|
dst_addr: src_addr,
|
|
|
|
protocol: IpProtocol::Tcp,
|
|
|
|
payload_len: tcp_reply_repr.buffer_len()
|
|
|
|
};
|
|
|
|
response = Response::Tcpv4(ipv4_reply_repr, tcp_reply_repr);
|
|
|
|
}
|
2016-12-21 03:18:35 +08:00
|
|
|
} else if !handled {
|
|
|
|
let reason;
|
|
|
|
if protocol == IpProtocol::Udp {
|
|
|
|
reason = Icmpv4DstUnreachable::PortUnreachable
|
|
|
|
} else {
|
|
|
|
reason = Icmpv4DstUnreachable::ProtoUnreachable
|
|
|
|
}
|
|
|
|
|
|
|
|
let icmp_reply_repr = Icmpv4Repr::DstUnreachable {
|
2017-01-14 19:07:06 +08:00
|
|
|
reason: reason,
|
|
|
|
header: ipv4_repr,
|
2017-06-21 12:08:33 +08:00
|
|
|
data: &ipv4_packet.payload()[0..8]
|
2017-01-14 19:07:06 +08:00
|
|
|
};
|
|
|
|
let ipv4_reply_repr = Ipv4Repr {
|
|
|
|
src_addr: dst_addr,
|
|
|
|
dst_addr: src_addr,
|
|
|
|
protocol: IpProtocol::Icmp,
|
|
|
|
payload_len: icmp_reply_repr.buffer_len()
|
2016-12-21 03:18:35 +08:00
|
|
|
};
|
2016-12-26 18:06:49 +08:00
|
|
|
response = Response::Icmpv4(ipv4_reply_repr, icmp_reply_repr)
|
2016-12-21 03:18:35 +08:00
|
|
|
}
|
2016-12-15 13:15:00 +08:00
|
|
|
},
|
2016-12-13 07:22:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Drop all other traffic.
|
2016-12-12 20:30:35 +08:00
|
|
|
_ => return Err(Error::Unrecognized)
|
|
|
|
}
|
2016-12-12 15:19:53 +08:00
|
|
|
|
2016-12-21 03:18:35 +08:00
|
|
|
macro_rules! ip_response {
|
2017-01-14 19:07:06 +08:00
|
|
|
($tx_buffer:ident, $frame:ident, $ip_repr:ident) => ({
|
2016-12-21 03:18:35 +08:00
|
|
|
let dst_hardware_addr =
|
2016-12-26 18:06:49 +08:00
|
|
|
match self.arp_cache.lookup(&$ip_repr.dst_addr.into()) {
|
2016-12-21 03:18:35 +08:00
|
|
|
None => return Err(Error::Unaddressable),
|
|
|
|
Some(hardware_addr) => hardware_addr
|
|
|
|
};
|
|
|
|
|
|
|
|
let frame_len = EthernetFrame::<&[u8]>::buffer_len($ip_repr.buffer_len() +
|
2017-01-14 19:07:06 +08:00
|
|
|
$ip_repr.payload_len);
|
2017-06-25 00:34:32 +08:00
|
|
|
$tx_buffer = self.device.transmit(frame_len)?;
|
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
|
|
|
$frame = EthernetFrame::new_checked(&mut $tx_buffer)
|
|
|
|
.expect("transmit frame too small");
|
2016-12-21 03:18:35 +08:00
|
|
|
$frame.set_src_addr(self.hardware_addr);
|
|
|
|
$frame.set_dst_addr(dst_hardware_addr);
|
|
|
|
$frame.set_ethertype(EthernetProtocol::Ipv4);
|
|
|
|
|
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-01-14 19:07:06 +08:00
|
|
|
$ip_repr.emit(&mut ip_packet);
|
2016-12-21 03:18:35 +08:00
|
|
|
ip_packet
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-12-13 07:22:59 +08:00
|
|
|
match response {
|
2016-12-12 15:19:53 +08:00
|
|
|
Response::Arp(repr) => {
|
2016-12-20 07:50:04 +08:00
|
|
|
let tx_len = EthernetFrame::<&[u8]>::buffer_len(repr.buffer_len());
|
2017-06-25 00:34:32 +08:00
|
|
|
let mut tx_buffer = self.device.transmit(tx_len)?;
|
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 frame = EthernetFrame::new_checked(&mut tx_buffer)
|
|
|
|
.expect("transmit frame too small");
|
2016-12-15 13:15:00 +08:00
|
|
|
frame.set_src_addr(self.hardware_addr);
|
2016-12-13 01:26:06 +08:00
|
|
|
frame.set_dst_addr(match repr {
|
2016-12-12 20:30:35 +08:00
|
|
|
ArpRepr::EthernetIpv4 { target_hardware_addr, .. } => target_hardware_addr,
|
|
|
|
_ => unreachable!()
|
|
|
|
});
|
2016-12-20 21:54:11 +08:00
|
|
|
frame.set_ethertype(EthernetProtocol::Arp);
|
2016-12-12 15:19:53 +08:00
|
|
|
|
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 packet = ArpPacket::new(frame.payload_mut());
|
2016-12-20 08:07:02 +08:00
|
|
|
repr.emit(&mut packet);
|
|
|
|
|
|
|
|
Ok(())
|
2016-12-13 07:22:59 +08:00
|
|
|
},
|
|
|
|
|
|
|
|
Response::Icmpv4(ip_repr, icmp_repr) => {
|
2016-12-21 03:18:35 +08:00
|
|
|
let mut tx_buffer;
|
|
|
|
let mut frame;
|
2017-01-14 19:07:06 +08:00
|
|
|
let mut ip_packet = ip_response!(tx_buffer, frame, ip_repr);
|
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 icmp_packet = Icmpv4Packet::new(ip_packet.payload_mut());
|
2016-12-13 07:22:59 +08:00
|
|
|
icmp_repr.emit(&mut icmp_packet);
|
2016-12-21 03:18:35 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
2016-12-20 08:07:02 +08:00
|
|
|
|
2016-12-21 03:18:35 +08:00
|
|
|
Response::Tcpv4(ip_repr, tcp_repr) => {
|
|
|
|
let mut tx_buffer;
|
|
|
|
let mut frame;
|
2017-01-14 19:07:06 +08:00
|
|
|
let mut ip_packet = ip_response!(tx_buffer, frame, ip_repr);
|
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 tcp_packet = TcpPacket::new(ip_packet.payload_mut());
|
2016-12-21 03:18:35 +08:00
|
|
|
tcp_repr.emit(&mut tcp_packet,
|
|
|
|
&IpAddress::Ipv4(ip_repr.src_addr),
|
|
|
|
&IpAddress::Ipv4(ip_repr.dst_addr));
|
2016-12-20 08:07:02 +08:00
|
|
|
Ok(())
|
2016-12-12 15:19:53 +08:00
|
|
|
}
|
2016-12-13 07:22:59 +08:00
|
|
|
|
2016-12-15 13:15:00 +08:00
|
|
|
Response::Nop => {
|
2016-12-20 08:07:02 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-11 13:25:54 +08:00
|
|
|
fn emit(&mut self, sockets: &mut SocketSet, timestamp: u64) -> Result<bool, Error> {
|
2016-12-20 08:07:02 +08:00
|
|
|
// Borrow checker is being overly careful around closures, so we have
|
|
|
|
// to hack around that.
|
|
|
|
let src_hardware_addr = self.hardware_addr;
|
2017-01-10 19:37:12 +08:00
|
|
|
let src_protocol_addrs = self.protocol_addrs.as_ref();
|
2016-12-20 08:07:02 +08:00
|
|
|
let arp_cache = &mut self.arp_cache;
|
|
|
|
let device = &mut self.device;
|
2017-03-07 18:56:48 +08:00
|
|
|
|
|
|
|
let mut limits = device.limits();
|
|
|
|
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-03-07 18:56:48 +08:00
|
|
|
let result = socket.dispatch(timestamp, &limits, &mut |repr, payload| {
|
2017-06-25 00:34:32 +08:00
|
|
|
let repr = repr.lower(src_protocol_addrs)?;
|
2016-12-20 08:07:02 +08:00
|
|
|
|
2017-03-05 12:59:51 +08:00
|
|
|
match arp_cache.lookup(&repr.dst_addr()) {
|
|
|
|
Some(dst_hardware_addr) => {
|
|
|
|
let tx_len = EthernetFrame::<&[u8]>::buffer_len(repr.buffer_len() +
|
|
|
|
payload.buffer_len());
|
2017-06-25 00:34:32 +08:00
|
|
|
let mut tx_buffer = device.transmit(tx_len)?;
|
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 frame = EthernetFrame::new_checked(&mut tx_buffer)
|
|
|
|
.expect("transmit frame too small");
|
2017-03-05 12:59:51 +08:00
|
|
|
frame.set_src_addr(src_hardware_addr);
|
|
|
|
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,
|
|
|
|
source_hardware_addr: src_hardware_addr,
|
|
|
|
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-06-25 00:34:32 +08:00
|
|
|
let mut tx_buffer = device.transmit(tx_len)?;
|
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 frame = EthernetFrame::new_checked(&mut tx_buffer)
|
|
|
|
.expect("transmit frame too small");
|
2017-03-05 12:59:51 +08:00
|
|
|
frame.set_src_addr(src_hardware_addr);
|
|
|
|
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
|
|
|
}
|
2016-12-15 13:15:00 +08:00
|
|
|
|