|
@@ -11,9 +11,7 @@ use crate::{Error, Result};
|
|
|
/// Internet protocol version.
|
|
|
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
|
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
|
-#[non_exhaustive]
|
|
|
pub enum Version {
|
|
|
- Unspecified,
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
Ipv4,
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
@@ -39,7 +37,6 @@ impl Version {
|
|
|
impl fmt::Display for Version {
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
match *self {
|
|
|
- Version::Unspecified => write!(f, "IPv?"),
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
Version::Ipv4 => write!(f, "IPv4"),
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
@@ -84,11 +81,7 @@ impl fmt::Display for Protocol {
|
|
|
|
|
|
/// An internetworking address.
|
|
|
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
|
|
-#[non_exhaustive]
|
|
|
pub enum Address {
|
|
|
- /// An unspecified address.
|
|
|
- /// May be used as a placeholder for storage where the address is not assigned yet.
|
|
|
- Unspecified,
|
|
|
/// An IPv4 address.
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
Ipv4(Ipv4Address),
|
|
@@ -112,20 +105,18 @@ impl Address {
|
|
|
}
|
|
|
|
|
|
/// Return the protocol version.
|
|
|
- pub fn version(&self) -> Option<Version> {
|
|
|
+ pub fn version(&self) -> Version {
|
|
|
match self {
|
|
|
- Address::Unspecified => None,
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
- Address::Ipv4(_) => Some(Version::Ipv4),
|
|
|
+ Address::Ipv4(_) => Version::Ipv4,
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
- Address::Ipv6(_) => Some(Version::Ipv6),
|
|
|
+ Address::Ipv6(_) => Version::Ipv6,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// Return an address as a sequence of octets, in big-endian.
|
|
|
pub fn as_bytes(&self) -> &[u8] {
|
|
|
match *self {
|
|
|
- Address::Unspecified => &[],
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
Address::Ipv4(ref addr) => addr.as_bytes(),
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
@@ -136,7 +127,6 @@ impl Address {
|
|
|
/// Query whether the address is a valid unicast address.
|
|
|
pub fn is_unicast(&self) -> bool {
|
|
|
match *self {
|
|
|
- Address::Unspecified => false,
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
Address::Ipv4(addr) => addr.is_unicast(),
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
@@ -147,7 +137,6 @@ impl Address {
|
|
|
/// Query whether the address is a valid multicast address.
|
|
|
pub fn is_multicast(&self) -> bool {
|
|
|
match *self {
|
|
|
- Address::Unspecified => false,
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
Address::Ipv4(addr) => addr.is_multicast(),
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
@@ -158,7 +147,6 @@ impl Address {
|
|
|
/// Query whether the address is the broadcast address.
|
|
|
pub fn is_broadcast(&self) -> bool {
|
|
|
match *self {
|
|
|
- Address::Unspecified => false,
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
Address::Ipv4(addr) => addr.is_broadcast(),
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
@@ -169,7 +157,6 @@ impl Address {
|
|
|
/// Query whether the address falls into the "unspecified" range.
|
|
|
pub fn is_unspecified(&self) -> bool {
|
|
|
match *self {
|
|
|
- Address::Unspecified => true,
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
Address::Ipv4(addr) => addr.is_unspecified(),
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
@@ -177,17 +164,6 @@ impl Address {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /// Return an unspecified address that has the same IP version as `self`.
|
|
|
- pub fn as_unspecified(&self) -> Address {
|
|
|
- match *self {
|
|
|
- Address::Unspecified => Address::Unspecified,
|
|
|
- #[cfg(feature = "proto-ipv4")]
|
|
|
- Address::Ipv4(_) => Address::Ipv4(Ipv4Address::UNSPECIFIED),
|
|
|
- #[cfg(feature = "proto-ipv6")]
|
|
|
- Address::Ipv6(_) => Address::Ipv6(Ipv6Address::UNSPECIFIED),
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
/// If `self` is a CIDR-compatible subnet mask, return `Some(prefix_len)`,
|
|
|
/// where `prefix_len` is the number of leading zeroes. Return `None` otherwise.
|
|
|
pub fn prefix_len(&self) -> Option<u8> {
|
|
@@ -233,7 +209,6 @@ impl From<Address> for ::std::net::IpAddr {
|
|
|
Address::Ipv4(ipv4) => ::std::net::IpAddr::V4(ipv4.into()),
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
Address::Ipv6(ipv6) => ::std::net::IpAddr::V6(ipv6.into()),
|
|
|
- _ => unreachable!(),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -252,12 +227,6 @@ impl From<::std::net::Ipv6Addr> for Address {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl Default for Address {
|
|
|
- fn default() -> Address {
|
|
|
- Address::Unspecified
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
impl From<Ipv4Address> for Address {
|
|
|
fn from(addr: Ipv4Address) -> Self {
|
|
@@ -275,7 +244,6 @@ impl From<Ipv6Address> for Address {
|
|
|
impl fmt::Display for Address {
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
match *self {
|
|
|
- Address::Unspecified => write!(f, "*"),
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
Address::Ipv4(addr) => write!(f, "{}", addr),
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
@@ -288,7 +256,6 @@ impl fmt::Display for Address {
|
|
|
impl defmt::Format for Address {
|
|
|
fn format(&self, f: defmt::Formatter) {
|
|
|
match self {
|
|
|
- &Address::Unspecified => defmt::write!(f, "{:?}", "*"),
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
&Address::Ipv4(addr) => defmt::write!(f, "{:?}", addr),
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
@@ -300,7 +267,6 @@ impl defmt::Format for Address {
|
|
|
/// A specification of a CIDR block, containing an address and a variable-length
|
|
|
/// subnet masking prefix length.
|
|
|
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
|
|
-#[non_exhaustive]
|
|
|
pub enum Cidr {
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
Ipv4(Ipv4Cidr),
|
|
@@ -312,17 +278,13 @@ impl Cidr {
|
|
|
/// Create a CIDR block from the given address and prefix length.
|
|
|
///
|
|
|
/// # Panics
|
|
|
- /// This function panics if the given address is unspecified, or
|
|
|
- /// the given prefix length is invalid for the given address.
|
|
|
+ /// This function panics if the given prefix length is invalid for the given address.
|
|
|
pub fn new(addr: Address, prefix_len: u8) -> Cidr {
|
|
|
match addr {
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
Address::Ipv4(addr) => Cidr::Ipv4(Ipv4Cidr::new(addr, prefix_len)),
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
Address::Ipv6(addr) => Cidr::Ipv6(Ipv6Cidr::new(addr, prefix_len)),
|
|
|
- Address::Unspecified => {
|
|
|
- panic!("a CIDR block cannot be based on an unspecified address")
|
|
|
- }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -354,14 +316,8 @@ impl Cidr {
|
|
|
(&Cidr::Ipv4(ref cidr), &Address::Ipv4(ref addr)) => cidr.contains_addr(addr),
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
(&Cidr::Ipv6(ref cidr), &Address::Ipv6(ref addr)) => cidr.contains_addr(addr),
|
|
|
- #[cfg(all(feature = "proto-ipv6", feature = "proto-ipv4"))]
|
|
|
- (&Cidr::Ipv4(_), &Address::Ipv6(_)) | (&Cidr::Ipv6(_), &Address::Ipv4(_)) => false,
|
|
|
- (_, &Address::Unspecified) =>
|
|
|
- // a fully unspecified address covers both IPv4 and IPv6,
|
|
|
- // and no CIDR block can do that.
|
|
|
- {
|
|
|
- false
|
|
|
- }
|
|
|
+ #[allow(unreachable_patterns)]
|
|
|
+ _ => false,
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -373,8 +329,8 @@ impl Cidr {
|
|
|
(&Cidr::Ipv4(ref cidr), &Cidr::Ipv4(ref other)) => cidr.contains_subnet(other),
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
(&Cidr::Ipv6(ref cidr), &Cidr::Ipv6(ref other)) => cidr.contains_subnet(other),
|
|
|
- #[cfg(all(feature = "proto-ipv6", feature = "proto-ipv4"))]
|
|
|
- (&Cidr::Ipv4(_), &Cidr::Ipv6(_)) | (&Cidr::Ipv6(_), &Cidr::Ipv4(_)) => false,
|
|
|
+ #[allow(unreachable_patterns)]
|
|
|
+ _ => false,
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -418,28 +374,20 @@ impl defmt::Format for Cidr {
|
|
|
|
|
|
/// An internet endpoint address.
|
|
|
///
|
|
|
-/// An endpoint can be constructed from a port, in which case the address is unspecified.
|
|
|
-#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
|
|
|
+/// `Endpoint` always fully specifies both the address and the port.
|
|
|
+///
|
|
|
+/// See also ['ListenEndpoint'], which allows not specifying the address
|
|
|
+/// in order to listen on a given port on any address.
|
|
|
+#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
|
|
pub struct Endpoint {
|
|
|
pub addr: Address,
|
|
|
pub port: u16,
|
|
|
}
|
|
|
|
|
|
impl Endpoint {
|
|
|
- /// An endpoint with unspecified address and port.
|
|
|
- pub const UNSPECIFIED: Endpoint = Endpoint {
|
|
|
- addr: Address::Unspecified,
|
|
|
- port: 0,
|
|
|
- };
|
|
|
-
|
|
|
/// Create an endpoint address from given address and port.
|
|
|
pub fn new(addr: Address, port: u16) -> Endpoint {
|
|
|
- Endpoint { addr, port }
|
|
|
- }
|
|
|
-
|
|
|
- /// Query whether the endpoint has a specified address and port.
|
|
|
- pub fn is_specified(&self) -> bool {
|
|
|
- !self.addr.is_unspecified() && self.port != 0
|
|
|
+ Endpoint { addr: addr, port }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -486,19 +434,100 @@ impl defmt::Format for Endpoint {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl From<u16> for Endpoint {
|
|
|
- fn from(port: u16) -> Endpoint {
|
|
|
+impl<T: Into<Address>> From<(T, u16)> for Endpoint {
|
|
|
+ fn from((addr, port): (T, u16)) -> Endpoint {
|
|
|
Endpoint {
|
|
|
- addr: Address::Unspecified,
|
|
|
+ addr: addr.into(),
|
|
|
port,
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-impl<T: Into<Address>> From<(T, u16)> for Endpoint {
|
|
|
- fn from((addr, port): (T, u16)) -> Endpoint {
|
|
|
- Endpoint {
|
|
|
- addr: addr.into(),
|
|
|
+/// An internet endpoint address for listening.
|
|
|
+///
|
|
|
+/// In contrast with [`Endpoint`], `ListenEndpoint` allows not specifying the address,
|
|
|
+/// in order to listen on a given port at all our addresses.
|
|
|
+///
|
|
|
+/// An endpoint can be constructed from a port, in which case the address is unspecified.
|
|
|
+#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
|
|
|
+pub struct ListenEndpoint {
|
|
|
+ pub addr: Option<Address>,
|
|
|
+ pub port: u16,
|
|
|
+}
|
|
|
+
|
|
|
+impl ListenEndpoint {
|
|
|
+ /// Query whether the endpoint has a specified address and port.
|
|
|
+ pub fn is_specified(&self) -> bool {
|
|
|
+ self.addr.is_some() && self.port != 0
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[cfg(all(feature = "std", feature = "proto-ipv4", feature = "proto-ipv6"))]
|
|
|
+impl From<::std::net::SocketAddr> for ListenEndpoint {
|
|
|
+ fn from(x: ::std::net::SocketAddr) -> ListenEndpoint {
|
|
|
+ ListenEndpoint {
|
|
|
+ addr: Some(x.ip().into()),
|
|
|
+ port: x.port(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[cfg(all(feature = "std", feature = "proto-ipv4"))]
|
|
|
+impl From<::std::net::SocketAddrV4> for ListenEndpoint {
|
|
|
+ fn from(x: ::std::net::SocketAddrV4) -> ListenEndpoint {
|
|
|
+ ListenEndpoint {
|
|
|
+ addr: Some((*x.ip()).into()),
|
|
|
+ port: x.port(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[cfg(all(feature = "std", feature = "proto-ipv6"))]
|
|
|
+impl From<::std::net::SocketAddrV6> for ListenEndpoint {
|
|
|
+ fn from(x: ::std::net::SocketAddrV6) -> ListenEndpoint {
|
|
|
+ ListenEndpoint {
|
|
|
+ addr: Some((*x.ip()).into()),
|
|
|
+ port: x.port(),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl fmt::Display for ListenEndpoint {
|
|
|
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
+ if let Some(addr) = self.addr {
|
|
|
+ write!(f, "{}:{}", addr, self.port)
|
|
|
+ } else {
|
|
|
+ write!(f, "*:{}", self.port)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[cfg(feature = "defmt")]
|
|
|
+impl defmt::Format for ListenEndpoint {
|
|
|
+ fn format(&self, f: defmt::Formatter) {
|
|
|
+ defmt::write!(f, "{:?}:{=u16}", self.addr, self.port);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl From<u16> for ListenEndpoint {
|
|
|
+ fn from(port: u16) -> ListenEndpoint {
|
|
|
+ ListenEndpoint { addr: None, port }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl From<Endpoint> for ListenEndpoint {
|
|
|
+ fn from(endpoint: Endpoint) -> ListenEndpoint {
|
|
|
+ ListenEndpoint {
|
|
|
+ addr: Some(endpoint.addr),
|
|
|
+ port: endpoint.port,
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl<T: Into<Address>> From<(T, u16)> for ListenEndpoint {
|
|
|
+ fn from((addr, port): (T, u16)) -> ListenEndpoint {
|
|
|
+ ListenEndpoint {
|
|
|
+ addr: Some(addr.into()),
|
|
|
port,
|
|
|
}
|
|
|
}
|
|
@@ -510,7 +539,6 @@ impl<T: Into<Address>> From<(T, u16)> for Endpoint {
|
|
|
/// or IPv6 concrete high-level representation.
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
|
-#[non_exhaustive]
|
|
|
pub enum Repr {
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
Ipv4(Ipv4Repr),
|
|
@@ -562,6 +590,7 @@ impl Repr {
|
|
|
payload_len,
|
|
|
hop_limit,
|
|
|
}),
|
|
|
+ #[allow(unreachable_patterns)]
|
|
|
_ => panic!("IP version mismatch: src={:?} dst={:?}", src_addr, dst_addr),
|
|
|
}
|
|
|
}
|
|
@@ -618,17 +647,11 @@ impl Repr {
|
|
|
|
|
|
/// Set the payload length.
|
|
|
pub fn set_payload_len(&mut self, length: usize) {
|
|
|
- match *self {
|
|
|
+ match self {
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
- Repr::Ipv4(Ipv4Repr {
|
|
|
- ref mut payload_len,
|
|
|
- ..
|
|
|
- }) => *payload_len = length,
|
|
|
+ Repr::Ipv4(Ipv4Repr { payload_len, .. }) => *payload_len = length,
|
|
|
#[cfg(feature = "proto-ipv6")]
|
|
|
- Repr::Ipv6(Ipv6Repr {
|
|
|
- ref mut payload_len,
|
|
|
- ..
|
|
|
- }) => *payload_len = length,
|
|
|
+ Repr::Ipv6(Ipv6Repr { payload_len, .. }) => *payload_len = length,
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -759,6 +782,7 @@ pub mod checksum {
|
|
|
])
|
|
|
}
|
|
|
|
|
|
+ #[allow(unreachable_patterns)]
|
|
|
_ => panic!(
|
|
|
"Unexpected pseudo header addresses: {}, {}",
|
|
|
src_addr, dst_addr
|
|
@@ -892,11 +916,6 @@ pub(crate) mod test {
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
use crate::wire::{Ipv4Address, Ipv4Repr};
|
|
|
|
|
|
- #[test]
|
|
|
- fn endpoint_unspecified() {
|
|
|
- assert!(!Endpoint::UNSPECIFIED.is_specified());
|
|
|
- }
|
|
|
-
|
|
|
#[test]
|
|
|
#[cfg(feature = "proto-ipv4")]
|
|
|
fn to_prefix_len_ipv4() {
|