|
@@ -6,10 +6,11 @@ use managed::{Managed, ManagedSlice};
|
|
|
use {Error, Result};
|
|
|
use phy::Device;
|
|
|
use wire::{EthernetAddress, EthernetProtocol, EthernetFrame};
|
|
|
+use wire::{Ipv4Address};
|
|
|
+use wire::{IpAddress, IpProtocol, IpRepr, IpCidr};
|
|
|
use wire::{ArpPacket, ArpRepr, ArpOperation};
|
|
|
use wire::{Ipv4Packet, Ipv4Repr};
|
|
|
use wire::{Icmpv4Packet, Icmpv4Repr, Icmpv4DstUnreachable};
|
|
|
-use wire::{IpAddress, IpProtocol, IpRepr};
|
|
|
#[cfg(feature = "socket-udp")] use wire::{UdpPacket, UdpRepr};
|
|
|
#[cfg(feature = "socket-tcp")] use wire::{TcpPacket, TcpRepr, TcpControl};
|
|
|
use socket::{Socket, SocketSet, AsSocket};
|
|
@@ -27,7 +28,8 @@ pub struct Interface<'a, 'b, 'c, DeviceT: Device + 'a> {
|
|
|
device: Managed<'a, DeviceT>,
|
|
|
arp_cache: Managed<'b, ArpCache>,
|
|
|
hardware_addr: EthernetAddress,
|
|
|
- protocol_addrs: ManagedSlice<'c, IpAddress>,
|
|
|
+ protocol_addrs: ManagedSlice<'c, IpCidr>,
|
|
|
+ ipv4_gateway: Option<Ipv4Address>,
|
|
|
}
|
|
|
|
|
|
enum Packet<'a> {
|
|
@@ -48,24 +50,29 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|
|
/// # Panics
|
|
|
/// See the restrictions on [set_hardware_addr](#method.set_hardware_addr)
|
|
|
/// and [set_protocol_addrs](#method.set_protocol_addrs) functions.
|
|
|
- pub fn new<DeviceMT, ArpCacheMT, ProtocolAddrsMT>
|
|
|
+ pub fn new<DeviceMT, ArpCacheMT, ProtocolAddrsMT, Ipv4GatewayAddrT>
|
|
|
(device: DeviceMT, arp_cache: ArpCacheMT,
|
|
|
- hardware_addr: EthernetAddress, protocol_addrs: ProtocolAddrsMT) ->
|
|
|
+ hardware_addr: EthernetAddress,
|
|
|
+ protocol_addrs: ProtocolAddrsMT,
|
|
|
+ ipv4_gateway: Ipv4GatewayAddrT) ->
|
|
|
Interface<'a, 'b, 'c, DeviceT>
|
|
|
where DeviceMT: Into<Managed<'a, DeviceT>>,
|
|
|
ArpCacheMT: Into<Managed<'b, ArpCache>>,
|
|
|
- ProtocolAddrsMT: Into<ManagedSlice<'c, IpAddress>>, {
|
|
|
+ ProtocolAddrsMT: Into<ManagedSlice<'c, IpCidr>>,
|
|
|
+ Ipv4GatewayAddrT: Into<Option<Ipv4Address>>, {
|
|
|
let device = device.into();
|
|
|
let arp_cache = arp_cache.into();
|
|
|
let protocol_addrs = protocol_addrs.into();
|
|
|
+ let ipv4_gateway = ipv4_gateway.into();
|
|
|
|
|
|
Self::check_hardware_addr(&hardware_addr);
|
|
|
Self::check_protocol_addrs(&protocol_addrs);
|
|
|
Interface {
|
|
|
- device: device,
|
|
|
- arp_cache: arp_cache,
|
|
|
- hardware_addr: hardware_addr,
|
|
|
- protocol_addrs: protocol_addrs,
|
|
|
+ device,
|
|
|
+ arp_cache,
|
|
|
+ hardware_addr,
|
|
|
+ protocol_addrs,
|
|
|
+ ipv4_gateway,
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -89,16 +96,16 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|
|
Self::check_hardware_addr(&self.hardware_addr);
|
|
|
}
|
|
|
|
|
|
- fn check_protocol_addrs(addrs: &[IpAddress]) {
|
|
|
- for addr in addrs {
|
|
|
- if !addr.is_unicast() {
|
|
|
- panic!("protocol address {} is not unicast", addr)
|
|
|
+ fn check_protocol_addrs(addrs: &[IpCidr]) {
|
|
|
+ for cidr in addrs {
|
|
|
+ if !cidr.address().is_unicast() {
|
|
|
+ panic!("protocol address {} is not unicast", cidr.address())
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// Get the protocol addresses of the interface.
|
|
|
- pub fn protocol_addrs(&self) -> &[IpAddress] {
|
|
|
+ pub fn protocol_addrs(&self) -> &[IpCidr] {
|
|
|
self.protocol_addrs.as_ref()
|
|
|
}
|
|
|
|
|
@@ -106,7 +113,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|
|
///
|
|
|
/// # Panics
|
|
|
/// This function panics if any of the addresses is not unicast.
|
|
|
- pub fn update_protocol_addrs<F: FnOnce(&mut ManagedSlice<'c, IpAddress>)>(&mut self, f: F) {
|
|
|
+ pub fn update_protocol_addrs<F: FnOnce(&mut ManagedSlice<'c, IpCidr>)>(&mut self, f: F) {
|
|
|
f(&mut self.protocol_addrs);
|
|
|
Self::check_protocol_addrs(&self.protocol_addrs)
|
|
|
}
|
|
@@ -114,7 +121,18 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|
|
/// Check whether the interface has the given protocol address assigned.
|
|
|
pub fn has_protocol_addr<T: Into<IpAddress>>(&self, addr: T) -> bool {
|
|
|
let addr = addr.into();
|
|
|
- self.protocol_addrs.iter().any(|&probe| probe == addr)
|
|
|
+ self.protocol_addrs.iter().any(|probe| probe.address() == addr)
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 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();
|
|
|
}
|
|
|
|
|
|
/// Transmit packets queued in the given sockets, and receive packets queued
|
|
@@ -541,10 +559,28 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
+ fn route_address(&self, addr: &IpAddress) -> Result<IpAddress> {
|
|
|
+ self.protocol_addrs
|
|
|
+ .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> {
|
|
|
- if let Some(hardware_addr) = self.arp_cache.lookup(dst_addr) {
|
|
|
+ let dst_addr = self.route_address(dst_addr)?;
|
|
|
+
|
|
|
+ if let Some(hardware_addr) = self.arp_cache.lookup(&dst_addr) {
|
|
|
return Ok(hardware_addr)
|
|
|
}
|
|
|
|
|
@@ -553,7 +589,7 @@ impl<'a, 'b, 'c, DeviceT: Device + 'a> Interface<'a, 'b, 'c, DeviceT> {
|
|
|
}
|
|
|
|
|
|
match (src_addr, dst_addr) {
|
|
|
- (&IpAddress::Ipv4(src_addr), &IpAddress::Ipv4(dst_addr)) => {
|
|
|
+ (&IpAddress::Ipv4(src_addr), IpAddress::Ipv4(dst_addr)) => {
|
|
|
net_debug!("address {} not in ARP cache, sending request",
|
|
|
dst_addr);
|
|
|
|