renet/src/iface/ethernet.rs

643 lines
26 KiB
Rust
Raw Normal View History

// Heads up! Before working on this file you should read the parts
// of RFC 1122 that discuss Ethernet, ARP and IP.
use managed::{Managed, ManagedSlice};
use {Error, Result};
2016-12-12 10:39:46 +08:00
use phy::Device;
use wire::{EthernetAddress, EthernetProtocol, EthernetFrame};
2017-10-03 15:28:00 +08:00
use wire::{Ipv4Address};
use wire::{IpAddress, IpProtocol, IpRepr, IpCidr};
2016-12-12 15:19:53 +08:00
use wire::{ArpPacket, ArpRepr, ArpOperation};
use wire::{Ipv4Packet, Ipv4Repr};
use wire::{Icmpv4Packet, Icmpv4Repr, Icmpv4DstUnreachable};
#[cfg(feature = "socket-udp")] use wire::{UdpPacket, UdpRepr};
#[cfg(feature = "socket-tcp")] use wire::{TcpPacket, TcpRepr, TcpControl};
use socket::{Socket, SocketSet, AsSocket};
#[cfg(feature = "socket-raw")] use socket::RawSocket;
#[cfg(feature = "socket-udp")] use socket::UdpSocket;
#[cfg(feature = "socket-tcp")] use socket::TcpSocket;
2017-01-11 13:25:54 +08:00
use super::ArpCache;
2016-12-12 10:39:46 +08:00
/// An Ethernet network interface.
///
/// 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> {
device: Managed<'a, DeviceT>,
2017-01-11 13:25:54 +08:00
arp_cache: Managed<'b, ArpCache>,
ethernet_addr: EthernetAddress,
ip_addrs: ManagedSlice<'c, IpCidr>,
2017-10-03 15:28:00 +08:00
ipv4_gateway: Option<Ipv4Address>,
2016-12-12 10:39:46 +08:00
}
enum Packet<'a> {
None,
Arp(ArpRepr),
Icmpv4(Ipv4Repr, Icmpv4Repr<'a>),
#[cfg(feature = "socket-raw")]
Raw((IpRepr, &'a [u8])),
#[cfg(feature = "socket-udp")]
Udp((IpRepr, UdpRepr<'a>)),
#[cfg(feature = "socket-tcp")]
Tcp((IpRepr, TcpRepr<'a>))
}
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.
///
/// # Panics
/// See the restrictions on [set_hardware_addr](#method.set_hardware_addr)
/// and [set_protocol_addrs](#method.set_protocol_addrs) functions.
2017-10-03 15:28:00 +08:00
pub fn new<DeviceMT, ArpCacheMT, ProtocolAddrsMT, Ipv4GatewayAddrT>
2017-01-11 13:25:54 +08:00
(device: DeviceMT, arp_cache: ArpCacheMT,
ethernet_addr: EthernetAddress,
ip_addrs: ProtocolAddrsMT,
2017-10-03 15:28:00 +08:00
ipv4_gateway: Ipv4GatewayAddrT) ->
2017-01-11 13:25:54 +08:00
Interface<'a, 'b, 'c, DeviceT>
where DeviceMT: Into<Managed<'a, DeviceT>>,
2017-01-11 13:25:54 +08:00
ArpCacheMT: Into<Managed<'b, ArpCache>>,
2017-10-03 15:28:00 +08:00
ProtocolAddrsMT: Into<ManagedSlice<'c, IpCidr>>,
Ipv4GatewayAddrT: Into<Option<Ipv4Address>>, {
let device = device.into();
let arp_cache = arp_cache.into();
let ip_addrs = ip_addrs.into();
2017-10-03 15:28:00 +08:00
let ipv4_gateway = ipv4_gateway.into();
Self::check_ethernet_addr(&ethernet_addr);
Self::check_ip_addrs(&ip_addrs);
Interface { device, arp_cache, ethernet_addr, ip_addrs, ipv4_gateway }
}
fn check_ethernet_addr(addr: &EthernetAddress) {
if addr.is_multicast() {
panic!("Ethernet address {} is not unicast", addr)
2016-12-12 10:39:46 +08:00
}
}
/// Get the Ethernet address of the interface.
pub fn ethernet_addr(&self) -> EthernetAddress {
self.ethernet_addr
2016-12-12 10:39:46 +08:00
}
/// Set the Ethernet address of the interface.
2016-12-12 10:39:46 +08:00
///
/// # Panics
2016-12-12 15:19:53 +08:00
/// This function panics if the address is not unicast.
pub fn set_ethernet_addr(&mut self, addr: EthernetAddress) {
self.ethernet_addr = addr;
Self::check_ethernet_addr(&self.ethernet_addr);
}
2016-12-12 15:19:53 +08:00
fn check_ip_addrs(addrs: &[IpCidr]) {
2017-10-03 15:28:00 +08:00
for cidr in addrs {
if !cidr.address().is_unicast() {
panic!("IP address {} is not unicast", cidr.address())
}
}
2016-12-12 10:39:46 +08:00
}
2016-12-12 15:19:53 +08:00
/// Get the IP addresses of the interface.
pub fn ip_addrs(&self) -> &[IpCidr] {
self.ip_addrs.as_ref()
2016-12-12 15:19:53 +08:00
}
/// Update the IP addresses of the interface.
2016-12-12 15:19:53 +08:00
///
/// # Panics
/// This function panics if any of the addresses is not unicast.
pub fn update_ip_addrs<F: FnOnce(&mut ManagedSlice<'c, IpCidr>)>(&mut self, f: F) {
f(&mut self.ip_addrs);
Self::check_ip_addrs(&self.ip_addrs)
2016-12-12 15:19:53 +08:00
}
/// Check whether the interface has the given IP address assigned.
pub fn has_ip_addr<T: Into<IpAddress>>(&self, addr: T) -> bool {
2016-12-12 15:19:53 +08:00
let addr = addr.into();
self.ip_addrs.iter().any(|probe| probe.address() == addr)
2017-10-03 15:28:00 +08:00
}
/// Get the IPv4 gateway of the interface.
pub fn ipv4_gateway(&self) -> Option<Ipv4Address> {
self.ipv4_gateway
}
/// Set the IPv4 gateway of the interface.
pub fn set_ipv4_gateway<GatewayAddrT>(&mut self, gateway: GatewayAddrT)
where GatewayAddrT: Into<Option<Ipv4Address>> {
self.ipv4_gateway = gateway.into();
2016-12-12 15:19:53 +08:00
}
/// Transmit packets queued in the given sockets, and receive packets queued
/// in the device.
2016-12-31 16:35:07 +08:00
///
/// The timestamp must be a number of milliseconds, monotonically increasing
/// since an arbitrary moment in time, such as system startup.
///
/// This function returns a _soft deadline_ for calling it the next time.
/// That is, if `iface.poll(&mut sockets, 1000)` returns `Ok(Some(2000))`,
/// it harmless (but wastes energy) to call it 500 ms later, and potentially
/// harmful (impacting quality of service) to call it 1500 ms later.
2017-10-04 04:41:45 +08:00
///
/// # Errors
/// This method will routinely return errors in response to normal network
/// activity as well as certain boundary conditions such as buffer exhaustion.
/// These errors are provided as an aid for troubleshooting, and are meant
/// to be logged and ignored.
2017-10-04 09:54:39 +08:00
///
2017-10-04 04:41:45 +08:00
/// As a special case, `Err(Error::Unrecognized)` is returned in response to
/// packets containing any unsupported protocol, option, or form, which is
/// a very common occurrence and on a production system it should not even
/// be logged.
pub fn poll(&mut self, sockets: &mut SocketSet, timestamp: u64) -> Result<Option<u64>> {
self.socket_egress(sockets, timestamp)?;
if self.socket_ingress(sockets, timestamp)? {
Ok(Some(0))
} else {
Ok(sockets.iter().filter_map(|socket| socket.poll_at()).min())
}
}
fn socket_ingress(&mut self, sockets: &mut SocketSet, timestamp: u64) -> Result<bool> {
let mut processed_any = false;
loop {
let frame =
match self.device.receive(timestamp) {
Ok(frame) => frame,
Err(Error::Exhausted) => break, // nothing to receive
Err(err) => return Err(err)
};
let response =
match self.process_ethernet(sockets, timestamp, &frame) {
Ok(response) => response,
Err(err) => {
net_debug!("cannot process ingress packet: {}", err);
return Err(err)
}
};
processed_any = true;
match self.dispatch(timestamp, response) {
Ok(()) => (),
Err(err) => {
net_debug!("cannot dispatch response packet: {}", err);
return Err(err)
}
}
}
Ok(processed_any)
}
fn socket_egress(&mut self, sockets: &mut SocketSet, timestamp: u64) -> Result<()> {
let mut caps = self.device.capabilities();
caps.max_transmission_unit -= EthernetFrame::<&[u8]>::header_len();
for socket in sockets.iter_mut() {
let mut device_result = Ok(());
let socket_result =
match socket {
#[cfg(feature = "socket-raw")]
&mut Socket::Raw(ref mut socket) =>
socket.dispatch(|response| {
device_result = self.dispatch(timestamp, Packet::Raw(response));
device_result
}, &caps.checksum),
#[cfg(feature = "socket-udp")]
&mut Socket::Udp(ref mut socket) =>
socket.dispatch(|response| {
device_result = self.dispatch(timestamp, Packet::Udp(response));
device_result
}),
#[cfg(feature = "socket-tcp")]
&mut Socket::Tcp(ref mut socket) =>
socket.dispatch(timestamp, &caps, |response| {
device_result = self.dispatch(timestamp, Packet::Tcp(response));
device_result
}),
&mut Socket::__Nonexhaustive(_) => unreachable!()
};
match (device_result, socket_result) {
(Err(Error::Unaddressable), _) => break, // no one to transmit to
(Err(Error::Exhausted), _) => break, // nowhere to transmit
(Ok(()), Err(Error::Exhausted)) => (), // nothing to transmit
(Err(err), _) | (_, Err(err)) => {
net_debug!("cannot dispatch egress packet: {}", err);
return Err(err)
}
(Ok(()), Ok(())) => ()
}
}
Ok(())
}
fn process_ethernet<'frame, T: AsRef<[u8]>>
(&mut self, sockets: &mut SocketSet, timestamp: u64,
frame: &'frame T) ->
Result<Packet<'frame>> {
let eth_frame = EthernetFrame::new_checked(frame)?;
// Ignore any packets not directed to our hardware address.
if !eth_frame.dst_addr().is_broadcast() &&
eth_frame.dst_addr() != self.ethernet_addr {
return Ok(Packet::None)
}
match eth_frame.ethertype() {
EthernetProtocol::Arp =>
self.process_arp(&eth_frame),
EthernetProtocol::Ipv4 =>
self.process_ipv4(sockets, timestamp, &eth_frame),
// Drop all other traffic.
_ => Err(Error::Unrecognized),
}
}
fn process_arp<'frame, T: AsRef<[u8]>>
(&mut self, eth_frame: &EthernetFrame<&'frame T>) ->
Result<Packet<'frame>> {
let arp_packet = ArpPacket::new_checked(eth_frame.payload())?;
let arp_repr = ArpRepr::parse(&arp_packet)?;
match arp_repr {
// 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.
ArpRepr::EthernetIpv4 {
operation, source_hardware_addr, source_protocol_addr, target_protocol_addr, ..
} => {
if source_protocol_addr.is_unicast() && source_hardware_addr.is_unicast() {
self.arp_cache.fill(&source_protocol_addr.into(),
&source_hardware_addr);
} else {
// Discard packets with non-unicast source addresses.
net_debug!("non-unicast source in {}", arp_repr);
return Err(Error::Malformed)
}
if operation == ArpOperation::Request && self.has_ip_addr(target_protocol_addr) {
Ok(Packet::Arp(ArpRepr::EthernetIpv4 {
operation: ArpOperation::Reply,
source_hardware_addr: self.ethernet_addr,
source_protocol_addr: target_protocol_addr,
target_hardware_addr: source_hardware_addr,
target_protocol_addr: source_protocol_addr
}))
} else {
Ok(Packet::None)
2017-06-18 18:14:20 +08:00
}
}
2017-06-18 18:14:20 +08:00
_ => Err(Error::Unrecognized)
}
}
fn process_ipv4<'frame, T: AsRef<[u8]>>
2017-09-25 08:46:53 +08:00
(&mut self, sockets: &mut SocketSet, _timestamp: u64,
eth_frame: &EthernetFrame<&'frame T>) ->
Result<Packet<'frame>> {
let ipv4_packet = Ipv4Packet::new_checked(eth_frame.payload())?;
let checksum_caps = self.device.capabilities().checksum;
let ipv4_repr = Ipv4Repr::parse(&ipv4_packet, &checksum_caps)?;
2017-06-28 05:51:56 +08:00
if !ipv4_repr.src_addr.is_unicast() {
// Discard packets with non-unicast source addresses.
net_debug!("non-unicast source in {}", ipv4_repr);
return Err(Error::Malformed)
}
if eth_frame.src_addr().is_unicast() {
// Fill the ARP cache from IP header of unicast frames.
self.arp_cache.fill(&IpAddress::Ipv4(ipv4_repr.src_addr),
&eth_frame.src_addr());
}
let ip_repr = IpRepr::Ipv4(ipv4_repr);
let ip_payload = ipv4_packet.payload();
#[cfg(feature = "socket-raw")]
let mut handled_by_raw_socket = false;
// Pass every IP packet to all raw sockets we have registered.
#[cfg(feature = "socket-raw")]
for raw_socket in sockets.iter_mut().filter_map(
<Socket as AsSocket<RawSocket>>::try_as_socket) {
2017-09-01 05:43:22 +08:00
if !raw_socket.accepts(&ip_repr) { continue }
match raw_socket.process(&ip_repr, ip_payload, &checksum_caps) {
// The packet is valid and handled by socket.
Ok(()) => handled_by_raw_socket = true,
2017-09-01 05:43:22 +08:00
// The socket buffer is full.
Err(Error::Exhausted) => (),
// Raw sockets don't validate the packets in any way.
Err(_) => unreachable!(),
}
}
if !self.has_ip_addr(ipv4_repr.dst_addr) {
// Ignore IP packets not directed at us.
return Ok(Packet::None)
2016-12-12 20:30:35 +08:00
}
2016-12-12 15:19:53 +08:00
match ipv4_repr.protocol {
IpProtocol::Icmp =>
self.process_icmpv4(ipv4_repr, ip_payload),
#[cfg(feature = "socket-udp")]
IpProtocol::Udp =>
self.process_udp(sockets, ip_repr, ip_payload),
#[cfg(feature = "socket-tcp")]
IpProtocol::Tcp =>
self.process_tcp(sockets, _timestamp, ip_repr, ip_payload),
#[cfg(feature = "socket-raw")]
_ if handled_by_raw_socket =>
Ok(Packet::None),
_ => {
let icmp_reply_repr = Icmpv4Repr::DstUnreachable {
reason: Icmpv4DstUnreachable::ProtoUnreachable,
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(Packet::Icmpv4(ipv4_reply_repr, icmp_reply_repr))
}
}
}
2017-10-03 22:27:01 +08:00
fn process_icmpv4<'frame>(&self, ipv4_repr: Ipv4Repr, ip_payload: &'frame [u8]) ->
Result<Packet<'frame>> {
let icmp_packet = Icmpv4Packet::new_checked(ip_payload)?;
let checksum_caps = self.device.capabilities().checksum;
let icmp_repr = Icmpv4Repr::parse(&icmp_packet, &checksum_caps)?;
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(Packet::Icmpv4(ipv4_reply_repr, icmp_reply_repr))
}
// Ignore any echo replies.
Icmpv4Repr::EchoReply { .. } => Ok(Packet::None),
// FIXME: do something correct here?
_ => Err(Error::Unrecognized),
}
}
#[cfg(feature = "socket-udp")]
fn process_udp<'frame>(&self, sockets: &mut SocketSet,
2017-08-28 18:36:27 +08:00
ip_repr: IpRepr, ip_payload: &'frame [u8]) ->
Result<Packet<'frame>> {
let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr());
let udp_packet = UdpPacket::new_checked(ip_payload)?;
let checksum_caps = self.device.capabilities().checksum;
let udp_repr = UdpRepr::parse(&udp_packet, &src_addr, &dst_addr, &checksum_caps)?;
for udp_socket in sockets.iter_mut().filter_map(
<Socket as AsSocket<UdpSocket>>::try_as_socket) {
2017-09-01 05:44:21 +08:00
if !udp_socket.accepts(&ip_repr, &udp_repr) { continue }
match udp_socket.process(&ip_repr, &udp_repr) {
// The packet is valid and handled by socket.
Ok(()) => return Ok(Packet::None),
2017-09-01 05:44:21 +08:00
// The packet is malformed, or the socket buffer is full.
Err(e) => return Err(e)
}
}
// The packet wasn't handled by a socket, send an ICMP port unreachable packet.
match ip_repr {
IpRepr::Ipv4(ipv4_repr) => {
let icmpv4_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: icmpv4_reply_repr.buffer_len()
};
Ok(Packet::Icmpv4(ipv4_reply_repr, icmpv4_reply_repr))
},
IpRepr::Unspecified { .. } |
IpRepr::__Nonexhaustive =>
unreachable!()
}
}
#[cfg(feature = "socket-tcp")]
fn process_tcp<'frame>(&self, sockets: &mut SocketSet, timestamp: u64,
ip_repr: IpRepr, ip_payload: &'frame [u8]) ->
Result<Packet<'frame>> {
let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr());
let tcp_packet = TcpPacket::new_checked(ip_payload)?;
let checksum_caps = self.device.capabilities().checksum;
let tcp_repr = TcpRepr::parse(&tcp_packet, &src_addr, &dst_addr, &checksum_caps)?;
for tcp_socket in sockets.iter_mut().filter_map(
<Socket as AsSocket<TcpSocket>>::try_as_socket) {
2017-09-01 05:44:41 +08:00
if !tcp_socket.accepts(&ip_repr, &tcp_repr) { continue }
match tcp_socket.process(timestamp, &ip_repr, &tcp_repr) {
// The packet is valid and handled by socket.
Ok(reply) => return Ok(reply.map_or(Packet::None, Packet::Tcp)),
2017-09-01 05:44:41 +08:00
// The packet is malformed, or doesn't match the socket state,
// or the socket buffer is full.
Err(e) => return Err(e)
}
}
if tcp_repr.control == TcpControl::Rst {
// Never reply to a TCP RST packet with another TCP RST packet.
Ok(Packet::None)
} else {
// The packet wasn't handled by a socket, send a TCP RST packet.
Ok(Packet::Tcp(TcpSocket::rst_reply(&ip_repr, &tcp_repr)))
}
}
fn dispatch(&mut self, timestamp: u64, packet: Packet) -> Result<()> {
let checksum_caps = self.device.capabilities().checksum;
match packet {
Packet::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
self.dispatch_ethernet(timestamp, arp_repr.buffer_len(), |mut frame| {
frame.set_dst_addr(dst_hardware_addr);
frame.set_ethertype(EthernetProtocol::Arp);
let mut packet = ArpPacket::new(frame.payload_mut());
arp_repr.emit(&mut packet);
})
2016-12-13 07:22:59 +08:00
},
Packet::Icmpv4(ipv4_repr, icmpv4_repr) => {
self.dispatch_ip(timestamp, IpRepr::Ipv4(ipv4_repr), |_ip_repr, payload| {
icmpv4_repr.emit(&mut Icmpv4Packet::new(payload), &checksum_caps);
})
2016-12-12 15:19:53 +08:00
}
#[cfg(feature = "socket-raw")]
Packet::Raw((ip_repr, raw_packet)) => {
self.dispatch_ip(timestamp, ip_repr, |_ip_repr, payload| {
payload.copy_from_slice(raw_packet);
})
}
#[cfg(feature = "socket-udp")]
Packet::Udp((ip_repr, udp_repr)) => {
self.dispatch_ip(timestamp, ip_repr, |ip_repr, payload| {
udp_repr.emit(&mut UdpPacket::new(payload),
2017-10-03 22:27:01 +08:00
&ip_repr.src_addr(), &ip_repr.dst_addr(),
&checksum_caps);
})
}
#[cfg(feature = "socket-tcp")]
Packet::Tcp((ip_repr, mut tcp_repr)) => {
let caps = self.device.capabilities();
self.dispatch_ip(timestamp, ip_repr, |ip_repr, payload| {
// This is a terrible hack to make TCP performance more acceptable on systems
// where the TCP buffers are significantly larger than network buffers,
// e.g. a 64 kB TCP receive buffer (and so, when empty, a 64k window)
// together with four 1500 B Ethernet receive buffers. If left untreated,
// this would result in our peer pushing our window and sever packet loss.
//
// I'm really not happy about this "solution" but I don't know what else to do.
if let Some(max_burst_size) = caps.max_burst_size {
let mut max_segment_size = caps.max_transmission_unit;
max_segment_size -= EthernetFrame::<&[u8]>::header_len();
max_segment_size -= ip_repr.buffer_len();
max_segment_size -= tcp_repr.header_len();
let max_window_size = max_burst_size * max_segment_size;
if tcp_repr.window_len as usize > max_window_size {
tcp_repr.window_len = max_window_size as u16;
}
}
tcp_repr.emit(&mut TcpPacket::new(payload),
&ip_repr.src_addr(), &ip_repr.dst_addr(),
&checksum_caps);
})
}
Packet::None => Ok(())
2016-12-12 15:19:53 +08:00
}
}
fn dispatch_ethernet<F>(&mut self, timestamp: u64, buffer_len: usize, f: F) -> Result<()>
where F: FnOnce(EthernetFrame<&mut [u8]>) {
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);
let mut frame = EthernetFrame::new(tx_buffer.as_mut());
frame.set_src_addr(self.ethernet_addr);
f(frame);
Ok(())
}
fn route(&self, addr: &IpAddress) -> Result<IpAddress> {
self.ip_addrs
2017-10-03 15:28:00 +08:00
.iter()
.find(|cidr| cidr.contains_addr(&addr))
.map(|_cidr| Ok(addr.clone())) // route directly
.unwrap_or_else(|| {
match (addr, self.ipv4_gateway) {
// route via a gateway
(&IpAddress::Ipv4(_), Some(gateway)) =>
Ok(gateway.into()),
// unroutable
_ => Err(Error::Unaddressable)
}
})
}
fn lookup_hardware_addr(&mut self, timestamp: u64,
src_addr: &IpAddress, dst_addr: &IpAddress) ->
Result<EthernetAddress> {
let dst_addr = self.route(dst_addr)?;
2017-10-03 15:28:00 +08:00
if let Some(hardware_addr) = self.arp_cache.lookup(&dst_addr) {
return Ok(hardware_addr)
}
if dst_addr.is_broadcast() {
2017-09-21 05:52:28 +08:00
return Ok(EthernetAddress::BROADCAST)
}
match (src_addr, dst_addr) {
2017-10-03 15:28:00 +08:00
(&IpAddress::Ipv4(src_addr), IpAddress::Ipv4(dst_addr)) => {
net_debug!("address {} not in ARP cache, sending request",
dst_addr);
let arp_repr = ArpRepr::EthernetIpv4 {
operation: ArpOperation::Request,
source_hardware_addr: self.ethernet_addr,
source_protocol_addr: src_addr,
2017-09-21 05:52:28 +08:00
target_hardware_addr: EthernetAddress::BROADCAST,
target_protocol_addr: dst_addr,
};
self.dispatch_ethernet(timestamp, arp_repr.buffer_len(), |mut frame| {
2017-09-21 05:52:28 +08:00
frame.set_dst_addr(EthernetAddress::BROADCAST);
frame.set_ethertype(EthernetProtocol::Arp);
arp_repr.emit(&mut ArpPacket::new(frame.payload_mut()))
})?;
Err(Error::Unaddressable)
}
_ => unreachable!()
}
}
fn dispatch_ip<F>(&mut self, timestamp: u64, ip_repr: IpRepr, f: F) -> Result<()>
where F: FnOnce(IpRepr, &mut [u8]) {
let ip_repr = ip_repr.lower(&self.ip_addrs)?;
let checksum_caps = self.device.capabilities().checksum;
let dst_hardware_addr =
self.lookup_hardware_addr(timestamp, &ip_repr.src_addr(), &ip_repr.dst_addr())?;
self.dispatch_ethernet(timestamp, ip_repr.total_len(), |mut 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(), &checksum_caps);
let payload = &mut frame.payload_mut()[ip_repr.buffer_len()..];
f(ip_repr, payload)
})
}
2016-12-12 10:39:46 +08:00
}