Add support for arbitrarily many routes instead of only gateways.
Closes: #219 Approved by: whitequarkv0.7.x
parent
022cad8b11
commit
728ae3fbb5
|
@ -15,7 +15,7 @@ license = "0BSD"
|
||||||
autoexamples = false
|
autoexamples = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
managed = { version = "0.5", default-features = false, features = ["map"] }
|
managed = { version = "0.7", default-features = false, features = ["map"] }
|
||||||
byteorder = { version = "1.0", default-features = false }
|
byteorder = { version = "1.0", default-features = false }
|
||||||
log = { version = "0.3", default-features = false, optional = true }
|
log = { version = "0.3", default-features = false, optional = true }
|
||||||
libc = { version = "0.2.18", optional = true }
|
libc = { version = "0.2.18", optional = true }
|
||||||
|
|
|
@ -11,7 +11,7 @@ use std::collections::BTreeMap;
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use smoltcp::phy::wait as phy_wait;
|
use smoltcp::phy::wait as phy_wait;
|
||||||
use smoltcp::wire::{EthernetAddress, Ipv4Address, IpAddress, IpCidr};
|
use smoltcp::wire::{EthernetAddress, Ipv4Address, IpAddress, IpCidr};
|
||||||
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
|
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, Routes};
|
||||||
use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
|
use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
|
||||||
use smoltcp::time::Instant;
|
use smoltcp::time::Instant;
|
||||||
|
|
||||||
|
@ -40,11 +40,14 @@ fn main() {
|
||||||
let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
|
let ethernet_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x02]);
|
||||||
let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 69, 2), 24)];
|
let ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 69, 2), 24)];
|
||||||
let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
|
let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
|
||||||
|
let mut routes_storage = [None; 1];
|
||||||
|
let mut routes = Routes::new(&mut routes_storage[..]);
|
||||||
|
routes.add_default_ipv4_route(default_v4_gw).unwrap();
|
||||||
let mut iface = EthernetInterfaceBuilder::new(device)
|
let mut iface = EthernetInterfaceBuilder::new(device)
|
||||||
.ethernet_addr(ethernet_addr)
|
.ethernet_addr(ethernet_addr)
|
||||||
.neighbor_cache(neighbor_cache)
|
.neighbor_cache(neighbor_cache)
|
||||||
.ip_addrs(ip_addrs)
|
.ip_addrs(ip_addrs)
|
||||||
.ipv4_gateway(default_v4_gw)
|
.routes(routes)
|
||||||
.finalize();
|
.finalize();
|
||||||
|
|
||||||
let mut sockets = SocketSet::new(vec![]);
|
let mut sockets = SocketSet::new(vec![]);
|
||||||
|
|
|
@ -14,7 +14,7 @@ use std::os::unix::io::AsRawFd;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use smoltcp::phy::wait as phy_wait;
|
use smoltcp::phy::wait as phy_wait;
|
||||||
use smoltcp::wire::{EthernetAddress, Ipv4Address, Ipv6Address, IpAddress, IpCidr};
|
use smoltcp::wire::{EthernetAddress, Ipv4Address, Ipv6Address, IpAddress, IpCidr};
|
||||||
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
|
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, Routes};
|
||||||
use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
|
use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
|
||||||
use smoltcp::time::Instant;
|
use smoltcp::time::Instant;
|
||||||
|
|
||||||
|
@ -47,12 +47,15 @@ fn main() {
|
||||||
IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64)];
|
IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64)];
|
||||||
let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
|
let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
|
||||||
let default_v6_gw = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100);
|
let default_v6_gw = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100);
|
||||||
|
let mut routes_storage = [None; 2];
|
||||||
|
let mut routes = Routes::new(&mut routes_storage[..]);
|
||||||
|
routes.add_default_ipv4_route(default_v4_gw).unwrap();
|
||||||
|
routes.add_default_ipv6_route(default_v6_gw).unwrap();
|
||||||
let mut iface = EthernetInterfaceBuilder::new(device)
|
let mut iface = EthernetInterfaceBuilder::new(device)
|
||||||
.ethernet_addr(ethernet_addr)
|
.ethernet_addr(ethernet_addr)
|
||||||
.neighbor_cache(neighbor_cache)
|
.neighbor_cache(neighbor_cache)
|
||||||
.ip_addrs(ip_addrs)
|
.ip_addrs(ip_addrs)
|
||||||
.ipv4_gateway(default_v4_gw)
|
.routes(routes)
|
||||||
.ipv6_gateway(default_v6_gw)
|
|
||||||
.finalize();
|
.finalize();
|
||||||
|
|
||||||
let mut sockets = SocketSet::new(vec![]);
|
let mut sockets = SocketSet::new(vec![]);
|
||||||
|
|
|
@ -17,7 +17,7 @@ use smoltcp::phy::wait as phy_wait;
|
||||||
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr,
|
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr,
|
||||||
Ipv6Address, Icmpv6Repr, Icmpv6Packet,
|
Ipv6Address, Icmpv6Repr, Icmpv6Packet,
|
||||||
Ipv4Address, Icmpv4Repr, Icmpv4Packet};
|
Ipv4Address, Icmpv4Repr, Icmpv4Packet};
|
||||||
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
|
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder, Routes};
|
||||||
use smoltcp::socket::{SocketSet, IcmpSocket, IcmpSocketBuffer, IcmpPacketMetadata, IcmpEndpoint};
|
use smoltcp::socket::{SocketSet, IcmpSocket, IcmpSocketBuffer, IcmpPacketMetadata, IcmpEndpoint};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use byteorder::{ByteOrder, NetworkEndian};
|
use byteorder::{ByteOrder, NetworkEndian};
|
||||||
|
@ -99,11 +99,14 @@ fn main() {
|
||||||
IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64)];
|
IpCidr::new(IpAddress::v6(0xfe80, 0, 0, 0, 0, 0, 0, 1), 64)];
|
||||||
let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
|
let default_v4_gw = Ipv4Address::new(192, 168, 69, 100);
|
||||||
let default_v6_gw = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100);
|
let default_v6_gw = Ipv6Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 0x100);
|
||||||
|
let mut routes_storage = [None; 2];
|
||||||
|
let mut routes = Routes::new(&mut routes_storage[..]);
|
||||||
|
routes.add_default_ipv4_route(default_v4_gw).unwrap();
|
||||||
|
routes.add_default_ipv6_route(default_v6_gw).unwrap();
|
||||||
let mut iface = EthernetInterfaceBuilder::new(device)
|
let mut iface = EthernetInterfaceBuilder::new(device)
|
||||||
.ethernet_addr(ethernet_addr)
|
.ethernet_addr(ethernet_addr)
|
||||||
.ip_addrs(ip_addrs)
|
.ip_addrs(ip_addrs)
|
||||||
.ipv4_gateway(default_v4_gw)
|
.routes(routes)
|
||||||
.ipv6_gateway(default_v6_gw)
|
|
||||||
.neighbor_cache(neighbor_cache)
|
.neighbor_cache(neighbor_cache)
|
||||||
.finalize();
|
.finalize();
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// and RFCs 8200 and 4861 for any IPv6 and NDISC work.
|
// and RFCs 8200 and 4861 for any IPv6 and NDISC work.
|
||||||
|
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use managed::ManagedSlice;
|
use managed::{ManagedSlice, ManagedMap};
|
||||||
|
|
||||||
use {Error, Result};
|
use {Error, Result};
|
||||||
use phy::{Device, DeviceCapabilities, RxToken, TxToken};
|
use phy::{Device, DeviceCapabilities, RxToken, TxToken};
|
||||||
|
@ -14,7 +14,7 @@ use wire::{IpAddress, IpProtocol, IpRepr, IpCidr};
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
use wire::{Ipv6Address, Ipv6Packet, Ipv6Repr, IPV6_MIN_MTU};
|
use wire::{Ipv6Address, Ipv6Packet, Ipv6Repr, IPV6_MIN_MTU};
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
use wire::{Ipv4Address, Ipv4Packet, Ipv4Repr, IPV4_MIN_MTU};
|
use wire::{Ipv4Packet, Ipv4Repr, IPV4_MIN_MTU};
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
use wire::{ArpPacket, ArpRepr, ArpOperation};
|
use wire::{ArpPacket, ArpRepr, ArpOperation};
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
@ -46,15 +46,16 @@ use socket::UdpSocket;
|
||||||
#[cfg(feature = "socket-tcp")]
|
#[cfg(feature = "socket-tcp")]
|
||||||
use socket::TcpSocket;
|
use socket::TcpSocket;
|
||||||
use super::{NeighborCache, NeighborAnswer};
|
use super::{NeighborCache, NeighborAnswer};
|
||||||
|
use super::Routes;
|
||||||
|
|
||||||
/// An Ethernet network interface.
|
/// An Ethernet network interface.
|
||||||
///
|
///
|
||||||
/// The network interface logically owns a number of other data structures; to avoid
|
/// 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 dependency on heap allocation, it instead owns a `BorrowMut<[T]>`, which can be
|
||||||
/// a `&mut [T]`, or `Vec<T>` if a heap is available.
|
/// a `&mut [T]`, or `Vec<T>` if a heap is available.
|
||||||
pub struct Interface<'b, 'c, DeviceT: for<'d> Device<'d>> {
|
pub struct Interface<'b, 'c, 'e, DeviceT: for<'d> Device<'d>> {
|
||||||
device: DeviceT,
|
device: DeviceT,
|
||||||
inner: InterfaceInner<'b, 'c>,
|
inner: InterfaceInner<'b, 'c, 'e>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The device independent part of an Ethernet network interface.
|
/// The device independent part of an Ethernet network interface.
|
||||||
|
@ -64,31 +65,25 @@ pub struct Interface<'b, 'c, DeviceT: for<'d> Device<'d>> {
|
||||||
/// the `device` mutably until they're used, which makes it impossible to call other
|
/// the `device` mutably until they're used, which makes it impossible to call other
|
||||||
/// methods on the `Interface` in this time (since its `device` field is borrowed
|
/// methods on the `Interface` in this time (since its `device` field is borrowed
|
||||||
/// exclusively). However, it is still possible to call methods on its `inner` field.
|
/// exclusively). However, it is still possible to call methods on its `inner` field.
|
||||||
struct InterfaceInner<'b, 'c> {
|
struct InterfaceInner<'b, 'c, 'e> {
|
||||||
neighbor_cache: NeighborCache<'b>,
|
neighbor_cache: NeighborCache<'b>,
|
||||||
ethernet_addr: EthernetAddress,
|
ethernet_addr: EthernetAddress,
|
||||||
ip_addrs: ManagedSlice<'c, IpCidr>,
|
ip_addrs: ManagedSlice<'c, IpCidr>,
|
||||||
#[cfg(feature = "proto-ipv4")]
|
routes: Routes<'e>,
|
||||||
ipv4_gateway: Option<Ipv4Address>,
|
|
||||||
#[cfg(feature = "proto-ipv6")]
|
|
||||||
ipv6_gateway: Option<Ipv6Address>,
|
|
||||||
device_capabilities: DeviceCapabilities,
|
device_capabilities: DeviceCapabilities,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A builder structure used for creating a Ethernet network
|
/// A builder structure used for creating a Ethernet network
|
||||||
/// interface.
|
/// interface.
|
||||||
pub struct InterfaceBuilder <'b, 'c, DeviceT: for<'d> Device<'d>> {
|
pub struct InterfaceBuilder <'b, 'c, 'e, DeviceT: for<'d> Device<'d>> {
|
||||||
device: DeviceT,
|
device: DeviceT,
|
||||||
ethernet_addr: Option<EthernetAddress>,
|
ethernet_addr: Option<EthernetAddress>,
|
||||||
neighbor_cache: Option<NeighborCache<'b>>,
|
neighbor_cache: Option<NeighborCache<'b>>,
|
||||||
ip_addrs: ManagedSlice<'c, IpCidr>,
|
ip_addrs: ManagedSlice<'c, IpCidr>,
|
||||||
#[cfg(feature = "proto-ipv4")]
|
routes: Routes<'e>,
|
||||||
ipv4_gateway: Option<Ipv4Address>,
|
|
||||||
#[cfg(feature = "proto-ipv6")]
|
|
||||||
ipv6_gateway: Option<Ipv6Address>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT>
|
impl<'b, 'c, 'e, DeviceT> InterfaceBuilder<'b, 'c, 'e, DeviceT>
|
||||||
where DeviceT: for<'d> Device<'d> {
|
where DeviceT: for<'d> Device<'d> {
|
||||||
/// Create a builder used for creating a network interface using the
|
/// Create a builder used for creating a network interface using the
|
||||||
/// given device and address.
|
/// given device and address.
|
||||||
|
@ -115,16 +110,13 @@ impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT>
|
||||||
/// .ip_addrs(ip_addrs)
|
/// .ip_addrs(ip_addrs)
|
||||||
/// .finalize();
|
/// .finalize();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn new(device: DeviceT) -> InterfaceBuilder<'b, 'c, DeviceT> {
|
pub fn new(device: DeviceT) -> InterfaceBuilder<'b, 'c, 'e, DeviceT> {
|
||||||
InterfaceBuilder {
|
InterfaceBuilder {
|
||||||
device: device,
|
device: device,
|
||||||
ethernet_addr: None,
|
ethernet_addr: None,
|
||||||
neighbor_cache: None,
|
neighbor_cache: None,
|
||||||
ip_addrs: ManagedSlice::Borrowed(&mut []),
|
ip_addrs: ManagedSlice::Borrowed(&mut []),
|
||||||
#[cfg(feature = "proto-ipv4")]
|
routes: Routes::new(ManagedMap::Borrowed(&mut [])),
|
||||||
ipv4_gateway: None,
|
|
||||||
#[cfg(feature = "proto-ipv6")]
|
|
||||||
ipv6_gateway: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +127,7 @@ impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT>
|
||||||
/// This function panics if the address is not unicast.
|
/// This function panics if the address is not unicast.
|
||||||
///
|
///
|
||||||
/// [ethernet_addr]: struct.EthernetInterface.html#method.ethernet_addr
|
/// [ethernet_addr]: struct.EthernetInterface.html#method.ethernet_addr
|
||||||
pub fn ethernet_addr(mut self, addr: EthernetAddress) -> InterfaceBuilder<'b, 'c, DeviceT> {
|
pub fn ethernet_addr(mut self, addr: EthernetAddress) -> InterfaceBuilder<'b, 'c, 'e, DeviceT> {
|
||||||
InterfaceInner::check_ethernet_addr(&addr);
|
InterfaceInner::check_ethernet_addr(&addr);
|
||||||
self.ethernet_addr = Some(addr);
|
self.ethernet_addr = Some(addr);
|
||||||
self
|
self
|
||||||
|
@ -148,7 +140,7 @@ impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT>
|
||||||
/// This function panics if any of the addresses are not unicast.
|
/// This function panics if any of the addresses are not unicast.
|
||||||
///
|
///
|
||||||
/// [ip_addrs]: struct.EthernetInterface.html#method.ip_addrs
|
/// [ip_addrs]: struct.EthernetInterface.html#method.ip_addrs
|
||||||
pub fn ip_addrs<T>(mut self, ip_addrs: T) -> InterfaceBuilder<'b, 'c, DeviceT>
|
pub fn ip_addrs<T>(mut self, ip_addrs: T) -> InterfaceBuilder<'b, 'c, 'e, DeviceT>
|
||||||
where T: Into<ManagedSlice<'c, IpCidr>>
|
where T: Into<ManagedSlice<'c, IpCidr>>
|
||||||
{
|
{
|
||||||
let ip_addrs = ip_addrs.into();
|
let ip_addrs = ip_addrs.into();
|
||||||
|
@ -157,43 +149,20 @@ impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT>
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the IPv4 gateway the interface will use. See also
|
/// Set the IP routes the interface will use. See also
|
||||||
/// [ipv4_gateway].
|
/// [routes].
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// [routes]: struct.EthernetInterface.html#method.routes
|
||||||
/// This function panics if the given address is not unicast.
|
pub fn routes<T>(mut self, routes: T) -> InterfaceBuilder<'b, 'c, 'e, DeviceT>
|
||||||
///
|
where T: Into<Routes<'e>>
|
||||||
/// [ipv4_gateway]: struct.EthernetInterface.html#method.ipv4_gateway
|
|
||||||
#[cfg(feature = "proto-ipv4")]
|
|
||||||
pub fn ipv4_gateway<T>(mut self, gateway: T) -> InterfaceBuilder<'b, 'c, DeviceT>
|
|
||||||
where T: Into<Ipv4Address>
|
|
||||||
{
|
{
|
||||||
let addr = gateway.into();
|
self.routes = routes.into();
|
||||||
InterfaceInner::check_ipv4_gateway_addr(&addr);
|
|
||||||
self.ipv4_gateway = Some(addr);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the IPv6 gateway the interface will use. See also
|
|
||||||
/// [ipv6_gateway].
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
/// This function panics if the given address is not unicast.
|
|
||||||
///
|
|
||||||
/// [ipv6_gateway]: struct.EthernetInterface.html#method.ipv6_gateway
|
|
||||||
#[cfg(feature = "proto-ipv6")]
|
|
||||||
pub fn ipv6_gateway<T>(mut self, gateway: T) -> InterfaceBuilder<'b, 'c, DeviceT>
|
|
||||||
where T: Into<Ipv6Address>
|
|
||||||
{
|
|
||||||
let addr = gateway.into();
|
|
||||||
InterfaceInner::check_ipv6_gateway_addr(&addr);
|
|
||||||
self.ipv6_gateway = Some(addr);
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the Neighbor Cache the interface will use.
|
/// Set the Neighbor Cache the interface will use.
|
||||||
pub fn neighbor_cache(mut self, neighbor_cache: NeighborCache<'b>) ->
|
pub fn neighbor_cache(mut self, neighbor_cache: NeighborCache<'b>) ->
|
||||||
InterfaceBuilder<'b, 'c, DeviceT> {
|
InterfaceBuilder<'b, 'c, 'e, DeviceT> {
|
||||||
self.neighbor_cache = Some(neighbor_cache);
|
self.neighbor_cache = Some(neighbor_cache);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -209,7 +178,7 @@ impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT>
|
||||||
///
|
///
|
||||||
/// [ethernet_addr]: #method.ethernet_addr
|
/// [ethernet_addr]: #method.ethernet_addr
|
||||||
/// [neighbor_cache]: #method.neighbor_cache
|
/// [neighbor_cache]: #method.neighbor_cache
|
||||||
pub fn finalize(self) -> Interface<'b, 'c, DeviceT> {
|
pub fn finalize(self) -> Interface<'b, 'c, 'e, DeviceT> {
|
||||||
match (self.ethernet_addr, self.neighbor_cache) {
|
match (self.ethernet_addr, self.neighbor_cache) {
|
||||||
(Some(ethernet_addr), Some(neighbor_cache)) => {
|
(Some(ethernet_addr), Some(neighbor_cache)) => {
|
||||||
let device_capabilities = self.device.capabilities();
|
let device_capabilities = self.device.capabilities();
|
||||||
|
@ -218,10 +187,7 @@ impl<'b, 'c, DeviceT> InterfaceBuilder<'b, 'c, DeviceT>
|
||||||
inner: InterfaceInner {
|
inner: InterfaceInner {
|
||||||
ethernet_addr, device_capabilities, neighbor_cache,
|
ethernet_addr, device_capabilities, neighbor_cache,
|
||||||
ip_addrs: self.ip_addrs,
|
ip_addrs: self.ip_addrs,
|
||||||
#[cfg(feature = "proto-ipv4")]
|
routes: self.routes,
|
||||||
ipv4_gateway: self.ipv4_gateway,
|
|
||||||
#[cfg(feature = "proto-ipv6")]
|
|
||||||
ipv6_gateway: self.ipv6_gateway,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -280,7 +246,7 @@ fn icmp_reply_payload_len(len: usize, mtu: usize, header_len: usize) -> usize {
|
||||||
cmp::min(len, mtu - header_len * 2 - 8)
|
cmp::min(len, mtu - header_len * 2 - 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT>
|
impl<'b, 'c, 'e, DeviceT> Interface<'b, 'c, 'e, DeviceT>
|
||||||
where DeviceT: for<'d> Device<'d> {
|
where DeviceT: for<'d> Device<'d> {
|
||||||
/// Get the Ethernet address of the interface.
|
/// Get the Ethernet address of the interface.
|
||||||
pub fn ethernet_addr(&self) -> EthernetAddress {
|
pub fn ethernet_addr(&self) -> EthernetAddress {
|
||||||
|
@ -315,38 +281,12 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT>
|
||||||
self.inner.has_ip_addr(addr)
|
self.inner.has_ip_addr(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the IPv4 gateway of the interface.
|
pub fn routes(&self) -> &'e Routes {
|
||||||
#[cfg(feature = "proto-ipv4")]
|
&self.inner.routes
|
||||||
pub fn ipv4_gateway(&self) -> Option<Ipv4Address> {
|
|
||||||
self.inner.ipv4_gateway
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the IPv4 gateway of the interface.
|
pub fn routes_mut(&mut self) -> &'e mut Routes {
|
||||||
///
|
&mut self.inner.routes
|
||||||
/// # Panics
|
|
||||||
/// This function panics if the given address is not unicast.
|
|
||||||
#[cfg(feature = "proto-ipv4")]
|
|
||||||
pub fn set_ipv4_gateway<GatewayAddrT>(&mut self, gateway: GatewayAddrT)
|
|
||||||
where GatewayAddrT: Into<Option<Ipv4Address>> {
|
|
||||||
self.inner.ipv4_gateway = gateway.into();
|
|
||||||
self.inner.ipv4_gateway.map(|addr| InterfaceInner::check_ipv4_gateway_addr(&addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the IPv6 gateway of the interface.
|
|
||||||
#[cfg(feature = "proto-ipv6")]
|
|
||||||
pub fn ipv6_gateway(&self) -> Option<Ipv6Address> {
|
|
||||||
self.inner.ipv6_gateway
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the IPv6 gateway of the interface.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
/// This function panics if the given address is not unicast.
|
|
||||||
#[cfg(feature = "proto-ipv6")]
|
|
||||||
pub fn set_ipv6_gateway<GatewayAddrT>(&mut self, gateway: GatewayAddrT)
|
|
||||||
where GatewayAddrT: Into<Option<Ipv6Address>> {
|
|
||||||
self.inner.ipv6_gateway = gateway.into();
|
|
||||||
self.inner.ipv6_gateway.map(|addr| InterfaceInner::check_ipv6_gateway_addr(&addr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transmit packets queued in the given sockets, and receive packets queued
|
/// Transmit packets queued in the given sockets, and receive packets queued
|
||||||
|
@ -525,7 +465,7 @@ impl<'b, 'c, DeviceT> Interface<'b, 'c, DeviceT>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b, 'c> InterfaceInner<'b, 'c> {
|
impl<'b, 'c, 'e> InterfaceInner<'b, 'c, 'e> {
|
||||||
fn check_ethernet_addr(addr: &EthernetAddress) {
|
fn check_ethernet_addr(addr: &EthernetAddress) {
|
||||||
if addr.is_multicast() {
|
if addr.is_multicast() {
|
||||||
panic!("Ethernet address {} is not unicast", addr)
|
panic!("Ethernet address {} is not unicast", addr)
|
||||||
|
@ -540,20 +480,6 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "proto-ipv4")]
|
|
||||||
fn check_ipv4_gateway_addr(addr: &Ipv4Address) {
|
|
||||||
if !addr.is_unicast() {
|
|
||||||
panic!("gateway IP address {} is not unicast", addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "proto-ipv6")]
|
|
||||||
fn check_ipv6_gateway_addr(addr: &Ipv6Address) {
|
|
||||||
if !addr.is_unicast() {
|
|
||||||
panic!("gateway IP address {} is not unicast", addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Determine if the given `Ipv6Address` is the solicited node
|
/// Determine if the given `Ipv6Address` is the solicited node
|
||||||
/// multicast address for a IPv6 addresses assigned to the interface.
|
/// multicast address for a IPv6 addresses assigned to the interface.
|
||||||
/// See [RFC 4291 § 2.7.1] for more details.
|
/// See [RFC 4291 § 2.7.1] for more details.
|
||||||
|
@ -1238,30 +1164,21 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
|
||||||
.is_some()
|
.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn route(&self, addr: &IpAddress) -> Result<IpAddress> {
|
fn route(&self, addr: &IpAddress, timestamp: Instant) -> Result<IpAddress> {
|
||||||
// Send directly.
|
// Send directly.
|
||||||
if self.in_same_network(addr) || addr.is_broadcast() {
|
if self.in_same_network(addr) || addr.is_broadcast() {
|
||||||
return Ok(addr.clone())
|
return Ok(addr.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Route via a gateway.
|
// Route via a router.
|
||||||
match addr {
|
match self.routes.lookup(addr, timestamp) {
|
||||||
#[cfg(feature = "proto-ipv4")]
|
Some(router_addr) => Ok(router_addr),
|
||||||
&IpAddress::Ipv4(_) => match self.ipv4_gateway {
|
None => Err(Error::Unaddressable),
|
||||||
Some(gateway) => Ok(gateway.into()),
|
|
||||||
None => Err(Error::Unaddressable),
|
|
||||||
}
|
|
||||||
#[cfg(feature = "proto-ipv6")]
|
|
||||||
&IpAddress::Ipv6(_) => match self.ipv6_gateway {
|
|
||||||
Some(gateway) => Ok(gateway.into()),
|
|
||||||
None => Err(Error::Unaddressable),
|
|
||||||
}
|
|
||||||
_ => Err(Error::Unaddressable)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_neighbor<'a>(&self, addr: &'a IpAddress, timestamp: Instant) -> bool {
|
fn has_neighbor<'a>(&self, addr: &'a IpAddress, timestamp: Instant) -> bool {
|
||||||
match self.route(addr) {
|
match self.route(addr, timestamp) {
|
||||||
Ok(routed_addr) => {
|
Ok(routed_addr) => {
|
||||||
self.neighbor_cache
|
self.neighbor_cache
|
||||||
.lookup_pure(&routed_addr, timestamp)
|
.lookup_pure(&routed_addr, timestamp)
|
||||||
|
@ -1309,7 +1226,7 @@ impl<'b, 'c> InterfaceInner<'b, 'c> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let dst_addr = self.route(dst_addr)?;
|
let dst_addr = self.route(dst_addr, timestamp)?;
|
||||||
|
|
||||||
match self.neighbor_cache.lookup(&dst_addr, timestamp) {
|
match self.neighbor_cache.lookup(&dst_addr, timestamp) {
|
||||||
NeighborAnswer::Found(hardware_addr) =>
|
NeighborAnswer::Found(hardware_addr) =>
|
||||||
|
@ -1435,8 +1352,8 @@ mod test {
|
||||||
|
|
||||||
use super::Packet;
|
use super::Packet;
|
||||||
|
|
||||||
fn create_loopback<'a, 'b>() -> (EthernetInterface<'static, 'b, Loopback>,
|
fn create_loopback<'a, 'b, 'c>() -> (EthernetInterface<'static, 'b, 'c, Loopback>,
|
||||||
SocketSet<'static, 'a, 'b>) {
|
SocketSet<'static, 'a, 'b>) {
|
||||||
// Create a basic device
|
// Create a basic device
|
||||||
let device = Loopback::new();
|
let device = Loopback::new();
|
||||||
let ip_addrs = [
|
let ip_addrs = [
|
||||||
|
|
|
@ -5,10 +5,12 @@ provides lookup and caching of hardware addresses, and handles management packet
|
||||||
*/
|
*/
|
||||||
|
|
||||||
mod neighbor;
|
mod neighbor;
|
||||||
|
mod route;
|
||||||
mod ethernet;
|
mod ethernet;
|
||||||
|
|
||||||
pub use self::neighbor::Neighbor as Neighbor;
|
pub use self::neighbor::Neighbor as Neighbor;
|
||||||
pub(crate) use self::neighbor::Answer as NeighborAnswer;
|
pub(crate) use self::neighbor::Answer as NeighborAnswer;
|
||||||
pub use self::neighbor::Cache as NeighborCache;
|
pub use self::neighbor::Cache as NeighborCache;
|
||||||
|
pub use self::route::{Route, Routes};
|
||||||
pub use self::ethernet::{Interface as EthernetInterface,
|
pub use self::ethernet::{Interface as EthernetInterface,
|
||||||
InterfaceBuilder as EthernetInterfaceBuilder};
|
InterfaceBuilder as EthernetInterfaceBuilder};
|
||||||
|
|
|
@ -0,0 +1,229 @@
|
||||||
|
use managed::ManagedMap;
|
||||||
|
use time::Instant;
|
||||||
|
use core::ops::Bound;
|
||||||
|
|
||||||
|
use {Error, Result};
|
||||||
|
use wire::{IpCidr, IpAddress};
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
use wire::{Ipv4Address, Ipv4Cidr};
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
use wire::{Ipv6Address, Ipv6Cidr};
|
||||||
|
|
||||||
|
/// A prefix of addresses that should be routed via a router
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Route {
|
||||||
|
pub via_router: IpAddress,
|
||||||
|
/// `None` means "forever".
|
||||||
|
pub preferred_until: Option<Instant>,
|
||||||
|
/// `None` means "forever".
|
||||||
|
pub expires_at: Option<Instant>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Route {
|
||||||
|
/// Returns a route to 0.0.0.0/0 via the `gateway`, with no expiry.
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
pub fn new_ipv4_gateway(gateway: Ipv4Address) -> Route {
|
||||||
|
Route {
|
||||||
|
via_router: gateway.into(),
|
||||||
|
preferred_until: None,
|
||||||
|
expires_at: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a route to ::/0 via the `gateway`, with no expiry.
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
pub fn new_ipv6_gateway(gateway: Ipv6Address) -> Route {
|
||||||
|
Route {
|
||||||
|
via_router: gateway.into(),
|
||||||
|
preferred_until: None,
|
||||||
|
expires_at: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A routing table.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// On systems with heap, this table can be created with:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use std::collections::BTreeMap;
|
||||||
|
/// use smoltcp::iface::Routes;
|
||||||
|
/// let mut routes = Routes::new(BTreeMap::new());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// On systems without heap, use:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use smoltcp::iface::Routes;
|
||||||
|
/// let mut routes_storage = [];
|
||||||
|
/// let mut routes = Routes::new(&mut routes_storage[..]);
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Routes<'a> {
|
||||||
|
storage: ManagedMap<'a, IpCidr, Route>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Routes<'a> {
|
||||||
|
/// Creates a routing tables. The backing storage is **not** cleared
|
||||||
|
/// upon creation.
|
||||||
|
pub fn new<T>(storage: T) -> Routes<'a>
|
||||||
|
where T: Into<ManagedMap<'a, IpCidr, Route>> {
|
||||||
|
let storage = storage.into();
|
||||||
|
Routes { storage }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update the routes of this node.
|
||||||
|
pub fn update<F: FnOnce(&mut ManagedMap<'a, IpCidr, Route>)>(&mut self, f: F) {
|
||||||
|
f(&mut self.storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a default ipv4 gateway (ie. "ip route add 0.0.0.0/0 via `gateway`").
|
||||||
|
///
|
||||||
|
/// On success, returns the previous default route, if any.
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
pub fn add_default_ipv4_route(&mut self, gateway: Ipv4Address) -> Result<Option<Route>> {
|
||||||
|
let cidr = IpCidr::new(IpAddress::v4(0, 0, 0, 0), 0);
|
||||||
|
let route = Route::new_ipv4_gateway(gateway);
|
||||||
|
match self.storage.insert(cidr, route) {
|
||||||
|
Ok(route) => Ok(route),
|
||||||
|
Err((_cidr, _route)) => Err(Error::Exhausted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a default ipv6 gateway (ie. "ip -6 route add ::/0 via `gateway`").
|
||||||
|
///
|
||||||
|
/// On success, returns the previous default route, if any.
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
pub fn add_default_ipv6_route(&mut self, gateway: Ipv6Address) -> Result<Option<Route>> {
|
||||||
|
let cidr = IpCidr::new(IpAddress::v6(0, 0, 0, 0, 0, 0, 0, 0), 0);
|
||||||
|
let route = Route::new_ipv6_gateway(gateway);
|
||||||
|
match self.storage.insert(cidr, route) {
|
||||||
|
Ok(route) => Ok(route),
|
||||||
|
Err((_cidr, _route)) => Err(Error::Exhausted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn lookup(&self, addr: &IpAddress, timestamp: Instant) ->
|
||||||
|
Option<IpAddress> {
|
||||||
|
assert!(addr.is_unicast());
|
||||||
|
|
||||||
|
let cidr = match addr {
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
IpAddress::Ipv4(addr) => IpCidr::Ipv4(Ipv4Cidr::new(*addr, 32)),
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
IpAddress::Ipv6(addr) => IpCidr::Ipv6(Ipv6Cidr::new(*addr, 128)),
|
||||||
|
_ => unimplemented!()
|
||||||
|
};
|
||||||
|
|
||||||
|
for (prefix, route) in self.storage.range((Bound::Unbounded, Bound::Included(cidr))).rev() {
|
||||||
|
// TODO: do something with route.preferred_until
|
||||||
|
if let Some(expires_at) = route.expires_at {
|
||||||
|
if timestamp > expires_at {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if prefix.contains_addr(addr) {
|
||||||
|
return Some(route.via_router);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
mod mock {
|
||||||
|
use super::super::*;
|
||||||
|
pub const ADDR_1A: Ipv6Address = Ipv6Address(
|
||||||
|
[0xfe, 0x80, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1]);
|
||||||
|
pub const ADDR_1B: Ipv6Address = Ipv6Address(
|
||||||
|
[0xfe, 0x80, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 13]);
|
||||||
|
pub const ADDR_1C: Ipv6Address = Ipv6Address(
|
||||||
|
[0xfe, 0x80, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 42]);
|
||||||
|
pub fn cidr_1() -> Ipv6Cidr {
|
||||||
|
Ipv6Cidr::new(Ipv6Address(
|
||||||
|
[0xfe, 0x80, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0]), 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ADDR_2A: Ipv6Address = Ipv6Address(
|
||||||
|
[0xfe, 0x80, 0, 0, 0, 0, 51, 100, 0, 0, 0, 0, 0, 0, 0, 1]);
|
||||||
|
pub const ADDR_2B: Ipv6Address = Ipv6Address(
|
||||||
|
[0xfe, 0x80, 0, 0, 0, 0, 51, 100, 0, 0, 0, 0, 0, 0, 0, 21]);
|
||||||
|
pub fn cidr_2() -> Ipv6Cidr {
|
||||||
|
Ipv6Cidr::new(Ipv6Address(
|
||||||
|
[0xfe, 0x80, 0, 0, 0, 0, 51, 100, 0, 0, 0, 0, 0, 0, 0, 0]), 64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "proto-ipv4", not(feature = "proto-ipv6")))]
|
||||||
|
mod mock {
|
||||||
|
use super::super::*;
|
||||||
|
pub const ADDR_1A: Ipv4Address = Ipv4Address([192, 0, 2, 1]);
|
||||||
|
pub const ADDR_1B: Ipv4Address = Ipv4Address([192, 0, 2, 13]);
|
||||||
|
pub const ADDR_1C: Ipv4Address = Ipv4Address([192, 0, 2, 42]);
|
||||||
|
pub fn cidr_1() -> Ipv4Cidr {
|
||||||
|
Ipv4Cidr::new(Ipv4Address([192, 0, 2, 0]), 24)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const ADDR_2A: Ipv4Address = Ipv4Address([198, 51, 100, 1]);
|
||||||
|
pub const ADDR_2B: Ipv4Address = Ipv4Address([198, 51, 100, 21]);
|
||||||
|
pub fn cidr_2() -> Ipv4Cidr {
|
||||||
|
Ipv4Cidr::new(Ipv4Address([198, 51, 100, 0]), 24)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use self::mock::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fill() {
|
||||||
|
let mut routes_storage = [None, None, None];
|
||||||
|
let mut routes = Routes::new(&mut routes_storage[..]);
|
||||||
|
|
||||||
|
assert_eq!(routes.lookup(&ADDR_1A.into(), Instant::from_millis(0)), None);
|
||||||
|
assert_eq!(routes.lookup(&ADDR_1B.into(), Instant::from_millis(0)), None);
|
||||||
|
assert_eq!(routes.lookup(&ADDR_1C.into(), Instant::from_millis(0)), None);
|
||||||
|
assert_eq!(routes.lookup(&ADDR_2A.into(), Instant::from_millis(0)), None);
|
||||||
|
assert_eq!(routes.lookup(&ADDR_2B.into(), Instant::from_millis(0)), None);
|
||||||
|
|
||||||
|
let route = Route {
|
||||||
|
via_router: ADDR_1A.into(),
|
||||||
|
preferred_until: None, expires_at: None,
|
||||||
|
};
|
||||||
|
routes.update(|storage| {
|
||||||
|
storage.insert(cidr_1().into(), route).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(routes.lookup(&ADDR_1A.into(), Instant::from_millis(0)), Some(ADDR_1A.into()));
|
||||||
|
assert_eq!(routes.lookup(&ADDR_1B.into(), Instant::from_millis(0)), Some(ADDR_1A.into()));
|
||||||
|
assert_eq!(routes.lookup(&ADDR_1C.into(), Instant::from_millis(0)), Some(ADDR_1A.into()));
|
||||||
|
assert_eq!(routes.lookup(&ADDR_2A.into(), Instant::from_millis(0)), None);
|
||||||
|
assert_eq!(routes.lookup(&ADDR_2B.into(), Instant::from_millis(0)), None);
|
||||||
|
|
||||||
|
let route2 = Route {
|
||||||
|
via_router: ADDR_2A.into(),
|
||||||
|
preferred_until: Some(Instant::from_millis(10)),
|
||||||
|
expires_at: Some(Instant::from_millis(10)),
|
||||||
|
};
|
||||||
|
routes.update(|storage| {
|
||||||
|
storage.insert(cidr_2().into(), route2).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(routes.lookup(&ADDR_1A.into(), Instant::from_millis(0)), Some(ADDR_1A.into()));
|
||||||
|
assert_eq!(routes.lookup(&ADDR_1B.into(), Instant::from_millis(0)), Some(ADDR_1A.into()));
|
||||||
|
assert_eq!(routes.lookup(&ADDR_1C.into(), Instant::from_millis(0)), Some(ADDR_1A.into()));
|
||||||
|
assert_eq!(routes.lookup(&ADDR_2A.into(), Instant::from_millis(0)), Some(ADDR_2A.into()));
|
||||||
|
assert_eq!(routes.lookup(&ADDR_2B.into(), Instant::from_millis(0)), Some(ADDR_2A.into()));
|
||||||
|
|
||||||
|
assert_eq!(routes.lookup(&ADDR_1A.into(), Instant::from_millis(10)), Some(ADDR_1A.into()));
|
||||||
|
assert_eq!(routes.lookup(&ADDR_1B.into(), Instant::from_millis(10)), Some(ADDR_1A.into()));
|
||||||
|
assert_eq!(routes.lookup(&ADDR_1C.into(), Instant::from_millis(10)), Some(ADDR_1A.into()));
|
||||||
|
assert_eq!(routes.lookup(&ADDR_2A.into(), Instant::from_millis(10)), Some(ADDR_2A.into()));
|
||||||
|
assert_eq!(routes.lookup(&ADDR_2B.into(), Instant::from_millis(10)), Some(ADDR_2A.into()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -325,6 +325,20 @@ impl Cidr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
impl From<Ipv4Cidr> for Cidr {
|
||||||
|
fn from(addr: Ipv4Cidr) -> Self {
|
||||||
|
Cidr::Ipv4(addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
impl From<Ipv6Cidr> for Cidr {
|
||||||
|
fn from(addr: Ipv6Cidr) -> Self {
|
||||||
|
Cidr::Ipv6(addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for Cidr {
|
impl fmt::Display for Cidr {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -243,7 +243,7 @@ impl<'a> Repr<'a> {
|
||||||
let opt = NdiscOption::new_checked(packet.payload())?;
|
let opt = NdiscOption::new_checked(packet.payload())?;
|
||||||
match opt.option_type() {
|
match opt.option_type() {
|
||||||
NdiscOptionType::SourceLinkLayerAddr => Some(opt.link_layer_addr()),
|
NdiscOptionType::SourceLinkLayerAddr => Some(opt.link_layer_addr()),
|
||||||
_ => None,
|
_ => { return Err(Error::Unrecognized); }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -260,7 +260,7 @@ impl<'a> Repr<'a> {
|
||||||
NdiscOptionRepr::SourceLinkLayerAddr(addr) => lladdr = Some(addr),
|
NdiscOptionRepr::SourceLinkLayerAddr(addr) => lladdr = Some(addr),
|
||||||
NdiscOptionRepr::Mtu(val) => mtu = Some(val),
|
NdiscOptionRepr::Mtu(val) => mtu = Some(val),
|
||||||
NdiscOptionRepr::PrefixInformation(info) => prefix_info = Some(info),
|
NdiscOptionRepr::PrefixInformation(info) => prefix_info = Some(info),
|
||||||
_ => ()
|
_ => { return Err(Error::Unrecognized); }
|
||||||
}
|
}
|
||||||
offset += opt.buffer_len();
|
offset += opt.buffer_len();
|
||||||
}
|
}
|
||||||
|
@ -278,7 +278,7 @@ impl<'a> Repr<'a> {
|
||||||
let opt = NdiscOption::new_checked(packet.payload())?;
|
let opt = NdiscOption::new_checked(packet.payload())?;
|
||||||
match opt.option_type() {
|
match opt.option_type() {
|
||||||
NdiscOptionType::SourceLinkLayerAddr => Some(opt.link_layer_addr()),
|
NdiscOptionType::SourceLinkLayerAddr => Some(opt.link_layer_addr()),
|
||||||
_ => None,
|
_ => { return Err(Error::Unrecognized); }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -292,7 +292,7 @@ impl<'a> Repr<'a> {
|
||||||
let opt = NdiscOption::new_checked(packet.payload())?;
|
let opt = NdiscOption::new_checked(packet.payload())?;
|
||||||
match opt.option_type() {
|
match opt.option_type() {
|
||||||
NdiscOptionType::TargetLinkLayerAddr => Some(opt.link_layer_addr()),
|
NdiscOptionType::TargetLinkLayerAddr => Some(opt.link_layer_addr()),
|
||||||
_ => None,
|
_ => { return Err(Error::Unrecognized); }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -326,7 +326,7 @@ impl<'a> Repr<'a> {
|
||||||
offset += 8 + ip_repr.buffer_len() + data.len();
|
offset += 8 + ip_repr.buffer_len() + data.len();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => { return Err(Error::Unrecognized); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Repr::Redirect {
|
Ok(Repr::Redirect {
|
||||||
|
|
Loading…
Reference in New Issue