|
@@ -5,8 +5,6 @@ use core::fmt;
|
|
|
|
|
|
use super::{Error, Result};
|
|
|
use crate::wire::ip::pretty_print_ip_payload;
|
|
|
-#[cfg(feature = "proto-ipv4")]
|
|
|
-use crate::wire::ipv4;
|
|
|
|
|
|
pub use super::IpProtocol as Protocol;
|
|
|
|
|
@@ -20,10 +18,25 @@ pub const MIN_MTU: usize = 1280;
|
|
|
/// [RFC 8200 § 2]: https://www.rfc-editor.org/rfc/rfc4291#section-2
|
|
|
pub const ADDR_SIZE: usize = 16;
|
|
|
|
|
|
-/// Size of IPv4-mapping prefix in octets.
|
|
|
+/// The link-local [all nodes multicast address].
|
|
|
///
|
|
|
-/// [RFC 8200 § 2]: https://www.rfc-editor.org/rfc/rfc4291#section-2
|
|
|
-pub const IPV4_MAPPED_PREFIX_SIZE: usize = ADDR_SIZE - 4; // 4 == ipv4::ADDR_SIZE , cannot DRY here because of dependency on a IPv4 module which is behind the feature
|
|
|
+/// [all nodes multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1
|
|
|
+pub const LINK_LOCAL_ALL_NODES: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1);
|
|
|
+
|
|
|
+/// The link-local [all routers multicast address].
|
|
|
+///
|
|
|
+/// [all routers multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1
|
|
|
+pub const LINK_LOCAL_ALL_ROUTERS: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 2);
|
|
|
+
|
|
|
+/// The link-local [all MLVDv2-capable routers multicast address].
|
|
|
+///
|
|
|
+/// [all MLVDv2-capable routers multicast address]: https://tools.ietf.org/html/rfc3810#section-11
|
|
|
+pub const LINK_LOCAL_ALL_MLDV2_ROUTERS: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x16);
|
|
|
+
|
|
|
+/// The link-local [all RPL nodes multicast address].
|
|
|
+///
|
|
|
+/// [all RPL nodes multicast address]: https://www.rfc-editor.org/rfc/rfc6550.html#section-20.19
|
|
|
+pub const LINK_LOCAL_ALL_RPL_NODES: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x1a);
|
|
|
|
|
|
/// The [scope] of an address.
|
|
|
///
|
|
@@ -61,211 +74,92 @@ impl From<u8> for MulticastScope {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-/// A sixteen-octet IPv6 address.
|
|
|
-#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
|
|
|
-pub struct Address(pub [u8; ADDR_SIZE]);
|
|
|
-
|
|
|
-impl Address {
|
|
|
- /// The [unspecified address].
|
|
|
- ///
|
|
|
- /// [unspecified address]: https://tools.ietf.org/html/rfc4291#section-2.5.2
|
|
|
- pub const UNSPECIFIED: Address = Address([0x00; ADDR_SIZE]);
|
|
|
+pub use core::net::Ipv6Addr as Address;
|
|
|
|
|
|
- /// The link-local [all nodes multicast address].
|
|
|
+pub(crate) trait AddressExt {
|
|
|
+ /// Construct an IPv6 address from a sequence of octets, in big-endian.
|
|
|
///
|
|
|
- /// [all nodes multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1
|
|
|
- pub const LINK_LOCAL_ALL_NODES: Address = Address([
|
|
|
- 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
- 0x01,
|
|
|
- ]);
|
|
|
+ /// # Panics
|
|
|
+ /// The function panics if `data` is not sixteen octets long.
|
|
|
+ fn from_bytes(data: &[u8]) -> Address;
|
|
|
|
|
|
- /// The link-local [all routers multicast address].
|
|
|
+ /// Query whether the IPv6 address is an [unicast address].
|
|
|
///
|
|
|
- /// [all routers multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1
|
|
|
- pub const LINK_LOCAL_ALL_ROUTERS: Address = Address([
|
|
|
- 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
- 0x02,
|
|
|
- ]);
|
|
|
-
|
|
|
- /// The link-local [all MLVDv2-capable routers multicast address].
|
|
|
+ /// [unicast address]: https://tools.ietf.org/html/rfc4291#section-2.5
|
|
|
///
|
|
|
- /// [all MLVDv2-capable routers multicast address]: https://tools.ietf.org/html/rfc3810#section-11
|
|
|
- pub const LINK_LOCAL_ALL_MLDV2_ROUTERS: Address = Address([
|
|
|
- 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
- 0x16,
|
|
|
- ]);
|
|
|
+ /// `x_` prefix is to avoid a collision with the still-unstable method in `core::ip`.
|
|
|
+ fn x_is_unicast(&self) -> bool;
|
|
|
|
|
|
- /// The link-local [all RPL nodes multicast address].
|
|
|
+ /// Query whether the IPv6 address is a [global unicast address].
|
|
|
///
|
|
|
- /// [all RPL nodes multicast address]: https://www.rfc-editor.org/rfc/rfc6550.html#section-20.19
|
|
|
- pub const LINK_LOCAL_ALL_RPL_NODES: Address = Address([
|
|
|
- 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
- 0x1a,
|
|
|
- ]);
|
|
|
+ /// [global unicast address]: https://datatracker.ietf.org/doc/html/rfc3587
|
|
|
+ fn is_global_unicast(&self) -> bool;
|
|
|
|
|
|
- /// The [loopback address].
|
|
|
+ /// Query whether the IPv6 address is in the [link-local] scope.
|
|
|
///
|
|
|
- /// [loopback address]: https://tools.ietf.org/html/rfc4291#section-2.5.3
|
|
|
- pub const LOOPBACK: Address = Address([
|
|
|
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
- 0x01,
|
|
|
- ]);
|
|
|
+ /// [link-local]: https://tools.ietf.org/html/rfc4291#section-2.5.6
|
|
|
+ fn is_link_local(&self) -> bool;
|
|
|
|
|
|
- /// The prefix used in [IPv4-mapped addresses].
|
|
|
+ /// Query whether the IPv6 address is a [Unique Local Address] (ULA).
|
|
|
///
|
|
|
- /// [IPv4-mapped addresses]: https://www.rfc-editor.org/rfc/rfc4291#section-2.5.5.2
|
|
|
- pub const IPV4_MAPPED_PREFIX: [u8; IPV4_MAPPED_PREFIX_SIZE] =
|
|
|
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff];
|
|
|
-
|
|
|
- /// Construct an IPv6 address from parts.
|
|
|
- #[allow(clippy::too_many_arguments)]
|
|
|
- pub const fn new(
|
|
|
- a0: u16,
|
|
|
- a1: u16,
|
|
|
- a2: u16,
|
|
|
- a3: u16,
|
|
|
- a4: u16,
|
|
|
- a5: u16,
|
|
|
- a6: u16,
|
|
|
- a7: u16,
|
|
|
- ) -> Address {
|
|
|
- Address([
|
|
|
- (a0 >> 8) as u8,
|
|
|
- a0 as u8,
|
|
|
- (a1 >> 8) as u8,
|
|
|
- a1 as u8,
|
|
|
- (a2 >> 8) as u8,
|
|
|
- a2 as u8,
|
|
|
- (a3 >> 8) as u8,
|
|
|
- a3 as u8,
|
|
|
- (a4 >> 8) as u8,
|
|
|
- a4 as u8,
|
|
|
- (a5 >> 8) as u8,
|
|
|
- a5 as u8,
|
|
|
- (a6 >> 8) as u8,
|
|
|
- a6 as u8,
|
|
|
- (a7 >> 8) as u8,
|
|
|
- a7 as u8,
|
|
|
- ])
|
|
|
- }
|
|
|
-
|
|
|
- /// Construct an IPv6 address from a sequence of octets, in big-endian.
|
|
|
+ /// [Unique Local Address]: https://tools.ietf.org/html/rfc4193
|
|
|
///
|
|
|
- /// # Panics
|
|
|
- /// The function panics if `data` is not sixteen octets long.
|
|
|
- pub fn from_bytes(data: &[u8]) -> Address {
|
|
|
- let mut bytes = [0; ADDR_SIZE];
|
|
|
- bytes.copy_from_slice(data);
|
|
|
- Address(bytes)
|
|
|
- }
|
|
|
+ /// `x_` prefix is to avoid a collision with the still-unstable method in `core::ip`.
|
|
|
+ fn x_is_unique_local(&self) -> bool;
|
|
|
|
|
|
- /// Construct an IPv6 address from a sequence of words, in big-endian.
|
|
|
+ /// Helper function used to mask an address given a prefix.
|
|
|
///
|
|
|
/// # Panics
|
|
|
- /// The function panics if `data` is not 8 words long.
|
|
|
- pub fn from_parts(data: &[u16]) -> Address {
|
|
|
- assert!(data.len() >= 8);
|
|
|
- let mut bytes = [0; ADDR_SIZE];
|
|
|
- for (word_idx, chunk) in bytes.chunks_mut(2).enumerate() {
|
|
|
- NetworkEndian::write_u16(chunk, data[word_idx]);
|
|
|
- }
|
|
|
- Address(bytes)
|
|
|
- }
|
|
|
+ /// This function panics if `mask` is greater than 128.
|
|
|
+ fn mask(&self, mask: u8) -> [u8; ADDR_SIZE];
|
|
|
|
|
|
- /// Write a IPv6 address to the given slice.
|
|
|
+ /// The solicited node for the given unicast address.
|
|
|
///
|
|
|
/// # Panics
|
|
|
- /// The function panics if `data` is not 8 words long.
|
|
|
- pub fn write_parts(&self, data: &mut [u16]) {
|
|
|
- assert!(data.len() >= 8);
|
|
|
- for (i, chunk) in self.0.chunks(2).enumerate() {
|
|
|
- data[i] = NetworkEndian::read_u16(chunk);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Return an IPv6 address as a sequence of octets, in big-endian.
|
|
|
- pub const fn as_bytes(&self) -> &[u8] {
|
|
|
- &self.0
|
|
|
- }
|
|
|
-
|
|
|
- /// Query whether the IPv6 address is an [unicast address].
|
|
|
- ///
|
|
|
- /// [unicast address]: https://tools.ietf.org/html/rfc4291#section-2.5
|
|
|
- pub fn is_unicast(&self) -> bool {
|
|
|
- !(self.is_multicast() || self.is_unspecified())
|
|
|
- }
|
|
|
+ /// This function panics if the given address is not
|
|
|
+ /// unicast.
|
|
|
+ fn solicited_node(&self) -> Address;
|
|
|
|
|
|
- /// Query whether the IPv6 address is a [global unicast address].
|
|
|
+ /// Return the scope of the address.
|
|
|
///
|
|
|
- /// [global unicast address]: https://datatracker.ietf.org/doc/html/rfc3587
|
|
|
- pub const fn is_global_unicast(&self) -> bool {
|
|
|
- (self.0[0] >> 5) == 0b001
|
|
|
- }
|
|
|
+ /// `x_` prefix is to avoid a collision with the still-unstable method in `core::ip`.
|
|
|
+ fn x_multicast_scope(&self) -> MulticastScope;
|
|
|
|
|
|
- /// Query whether the IPv6 address is a [multicast address].
|
|
|
- ///
|
|
|
- /// [multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7
|
|
|
- pub const fn is_multicast(&self) -> bool {
|
|
|
- self.0[0] == 0xff
|
|
|
- }
|
|
|
+ /// If `self` is a CIDR-compatible subnet mask, return `Some(prefix_len)`,
|
|
|
+ /// where `prefix_len` is the number of leading zeroes. Return `None` otherwise.
|
|
|
+ fn prefix_len(&self) -> Option<u8>;
|
|
|
+}
|
|
|
|
|
|
- /// Query whether the IPv6 address is the [unspecified address].
|
|
|
- ///
|
|
|
- /// [unspecified address]: https://tools.ietf.org/html/rfc4291#section-2.5.2
|
|
|
- pub fn is_unspecified(&self) -> bool {
|
|
|
- self.0 == [0x00; ADDR_SIZE]
|
|
|
+impl AddressExt for Address {
|
|
|
+ fn from_bytes(data: &[u8]) -> Address {
|
|
|
+ let mut bytes = [0; ADDR_SIZE];
|
|
|
+ bytes.copy_from_slice(data);
|
|
|
+ Address::from(bytes)
|
|
|
}
|
|
|
|
|
|
- /// Query whether the IPv6 address is in the [link-local] scope.
|
|
|
- ///
|
|
|
- /// [link-local]: https://tools.ietf.org/html/rfc4291#section-2.5.6
|
|
|
- pub fn is_link_local(&self) -> bool {
|
|
|
- self.0[0..8] == [0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
|
|
|
+ fn x_is_unicast(&self) -> bool {
|
|
|
+ !(self.is_multicast() || self.is_unspecified())
|
|
|
}
|
|
|
|
|
|
- /// Query whether the IPv6 address is a [Unique Local Address] (ULA).
|
|
|
- ///
|
|
|
- /// [Unique Local Address]: https://tools.ietf.org/html/rfc4193
|
|
|
- pub fn is_unique_local(&self) -> bool {
|
|
|
- (self.0[0] & 0b1111_1110) == 0xfc
|
|
|
+ fn is_global_unicast(&self) -> bool {
|
|
|
+ (self.octets()[0] >> 5) == 0b001
|
|
|
}
|
|
|
|
|
|
- /// Query whether the IPv6 address is the [loopback address].
|
|
|
- ///
|
|
|
- /// [loopback address]: https://tools.ietf.org/html/rfc4291#section-2.5.3
|
|
|
- pub fn is_loopback(&self) -> bool {
|
|
|
- *self == Self::LOOPBACK
|
|
|
+ fn is_link_local(&self) -> bool {
|
|
|
+ self.octets()[0..8] == [0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
|
|
|
}
|
|
|
|
|
|
- /// Query whether the IPv6 address is an [IPv4 mapped IPv6 address].
|
|
|
- ///
|
|
|
- /// [IPv4 mapped IPv6 address]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
|
|
|
- pub fn is_ipv4_mapped(&self) -> bool {
|
|
|
- self.0[..IPV4_MAPPED_PREFIX_SIZE] == Self::IPV4_MAPPED_PREFIX
|
|
|
- }
|
|
|
-
|
|
|
- #[cfg(feature = "proto-ipv4")]
|
|
|
- /// Convert an IPv4 mapped IPv6 address to an IPv4 address.
|
|
|
- pub fn as_ipv4(&self) -> Option<ipv4::Address> {
|
|
|
- if self.is_ipv4_mapped() {
|
|
|
- Some(ipv4::Address::from_bytes(
|
|
|
- &self.0[IPV4_MAPPED_PREFIX_SIZE..],
|
|
|
- ))
|
|
|
- } else {
|
|
|
- None
|
|
|
- }
|
|
|
+ fn x_is_unique_local(&self) -> bool {
|
|
|
+ (self.octets()[0] & 0b1111_1110) == 0xfc
|
|
|
}
|
|
|
|
|
|
- /// Helper function used to mask an address given a prefix.
|
|
|
- ///
|
|
|
- /// # Panics
|
|
|
- /// This function panics if `mask` is greater than 128.
|
|
|
- pub(super) fn mask(&self, mask: u8) -> [u8; ADDR_SIZE] {
|
|
|
+ fn mask(&self, mask: u8) -> [u8; ADDR_SIZE] {
|
|
|
assert!(mask <= 128);
|
|
|
let mut bytes = [0u8; ADDR_SIZE];
|
|
|
let idx = (mask as usize) / 8;
|
|
|
let modulus = (mask as usize) % 8;
|
|
|
- let (first, second) = self.0.split_at(idx);
|
|
|
+ let octets = self.octets();
|
|
|
+ let (first, second) = octets.split_at(idx);
|
|
|
bytes[0..idx].copy_from_slice(first);
|
|
|
if idx < ADDR_SIZE {
|
|
|
let part = second[0];
|
|
@@ -274,28 +168,23 @@ impl Address {
|
|
|
bytes
|
|
|
}
|
|
|
|
|
|
- /// The solicited node for the given unicast address.
|
|
|
- ///
|
|
|
- /// # Panics
|
|
|
- /// This function panics if the given address is not
|
|
|
- /// unicast.
|
|
|
- pub fn solicited_node(&self) -> Address {
|
|
|
- assert!(self.is_unicast());
|
|
|
- Address([
|
|
|
- 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF,
|
|
|
- self.0[13], self.0[14], self.0[15],
|
|
|
+ fn solicited_node(&self) -> Address {
|
|
|
+ assert!(self.x_is_unicast());
|
|
|
+ let o = self.octets();
|
|
|
+ Address::from([
|
|
|
+ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, o[13],
|
|
|
+ o[14], o[15],
|
|
|
])
|
|
|
}
|
|
|
|
|
|
- /// Return the scope of the address.
|
|
|
- pub(crate) fn multicast_scope(&self) -> MulticastScope {
|
|
|
+ fn x_multicast_scope(&self) -> MulticastScope {
|
|
|
if self.is_multicast() {
|
|
|
- return MulticastScope::from(self.as_bytes()[1] & 0b1111);
|
|
|
+ return MulticastScope::from(self.octets()[1] & 0b1111);
|
|
|
}
|
|
|
|
|
|
if self.is_link_local() {
|
|
|
MulticastScope::LinkLocal
|
|
|
- } else if self.is_unique_local() || self.is_global_unicast() {
|
|
|
+ } else if self.x_is_unique_local() || self.is_global_unicast() {
|
|
|
// ULA are considered global scope
|
|
|
// https://www.rfc-editor.org/rfc/rfc6724#section-3.1
|
|
|
MulticastScope::Global
|
|
@@ -304,162 +193,34 @@ impl Address {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /// Convert to an `IpAddress`.
|
|
|
- ///
|
|
|
- /// Same as `.into()`, but works in `const`.
|
|
|
- pub const fn into_address(self) -> super::IpAddress {
|
|
|
- super::IpAddress::Ipv6(self)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl From<::core::net::Ipv6Addr> for Address {
|
|
|
- fn from(x: ::core::net::Ipv6Addr) -> Address {
|
|
|
- Address(x.octets())
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl From<Address> for ::core::net::Ipv6Addr {
|
|
|
- fn from(Address(x): Address) -> ::core::net::Ipv6Addr {
|
|
|
- x.into()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl fmt::Display for Address {
|
|
|
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
- if self.is_ipv4_mapped() {
|
|
|
- return write!(
|
|
|
- f,
|
|
|
- "::ffff:{}.{}.{}.{}",
|
|
|
- self.0[IPV4_MAPPED_PREFIX_SIZE + 0],
|
|
|
- self.0[IPV4_MAPPED_PREFIX_SIZE + 1],
|
|
|
- self.0[IPV4_MAPPED_PREFIX_SIZE + 2],
|
|
|
- self.0[IPV4_MAPPED_PREFIX_SIZE + 3]
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- // The string representation of an IPv6 address should
|
|
|
- // collapse a series of 16 bit sections that evaluate
|
|
|
- // to 0 to "::"
|
|
|
- //
|
|
|
- // See https://tools.ietf.org/html/rfc4291#section-2.2
|
|
|
- // for details.
|
|
|
- enum State {
|
|
|
- Head,
|
|
|
- HeadBody,
|
|
|
- Tail,
|
|
|
- TailBody,
|
|
|
- }
|
|
|
- let mut words = [0u16; 8];
|
|
|
- self.write_parts(&mut words);
|
|
|
- let mut state = State::Head;
|
|
|
- for word in words.iter() {
|
|
|
- state = match (*word, &state) {
|
|
|
- // Once a u16 equal to zero write a double colon and
|
|
|
- // skip to the next non-zero u16.
|
|
|
- (0, &State::Head) | (0, &State::HeadBody) => {
|
|
|
- write!(f, "::")?;
|
|
|
- State::Tail
|
|
|
- }
|
|
|
- // Continue iterating without writing any characters until
|
|
|
- // we hit a non-zero value.
|
|
|
- (0, &State::Tail) => State::Tail,
|
|
|
- // When the state is Head or Tail write a u16 in hexadecimal
|
|
|
- // without the leading colon if the value is not 0.
|
|
|
- (_, &State::Head) => {
|
|
|
- write!(f, "{word:x}")?;
|
|
|
- State::HeadBody
|
|
|
- }
|
|
|
- (_, &State::Tail) => {
|
|
|
- write!(f, "{word:x}")?;
|
|
|
- State::TailBody
|
|
|
- }
|
|
|
- // Write the u16 with a leading colon when parsing a value
|
|
|
- // that isn't the first in a section
|
|
|
- (_, &State::HeadBody) | (_, &State::TailBody) => {
|
|
|
- write!(f, ":{word:x}")?;
|
|
|
- state
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- Ok(())
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(feature = "defmt")]
|
|
|
-impl defmt::Format for Address {
|
|
|
- fn format(&self, f: defmt::Formatter) {
|
|
|
- if self.is_ipv4_mapped() {
|
|
|
- return defmt::write!(
|
|
|
- f,
|
|
|
- "::ffff:{}.{}.{}.{}",
|
|
|
- self.0[IPV4_MAPPED_PREFIX_SIZE + 0],
|
|
|
- self.0[IPV4_MAPPED_PREFIX_SIZE + 1],
|
|
|
- self.0[IPV4_MAPPED_PREFIX_SIZE + 2],
|
|
|
- self.0[IPV4_MAPPED_PREFIX_SIZE + 3]
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- // The string representation of an IPv6 address should
|
|
|
- // collapse a series of 16 bit sections that evaluate
|
|
|
- // to 0 to "::"
|
|
|
- //
|
|
|
- // See https://tools.ietf.org/html/rfc4291#section-2.2
|
|
|
- // for details.
|
|
|
- enum State {
|
|
|
- Head,
|
|
|
- HeadBody,
|
|
|
- Tail,
|
|
|
- TailBody,
|
|
|
- }
|
|
|
- let mut words = [0u16; 8];
|
|
|
- self.write_parts(&mut words);
|
|
|
- let mut state = State::Head;
|
|
|
- for word in words.iter() {
|
|
|
- state = match (*word, &state) {
|
|
|
- // Once a u16 equal to zero write a double colon and
|
|
|
- // skip to the next non-zero u16.
|
|
|
- (0, &State::Head) | (0, &State::HeadBody) => {
|
|
|
- defmt::write!(f, "::");
|
|
|
- State::Tail
|
|
|
- }
|
|
|
- // Continue iterating without writing any characters until
|
|
|
- // we hit a non-zero value.
|
|
|
- (0, &State::Tail) => State::Tail,
|
|
|
- // When the state is Head or Tail write a u16 in hexadecimal
|
|
|
- // without the leading colon if the value is not 0.
|
|
|
- (_, &State::Head) => {
|
|
|
- defmt::write!(f, "{:x}", word);
|
|
|
- State::HeadBody
|
|
|
- }
|
|
|
- (_, &State::Tail) => {
|
|
|
- defmt::write!(f, "{:x}", word);
|
|
|
- State::TailBody
|
|
|
- }
|
|
|
- // Write the u16 with a leading colon when parsing a value
|
|
|
- // that isn't the first in a section
|
|
|
- (_, &State::HeadBody) | (_, &State::TailBody) => {
|
|
|
- defmt::write!(f, ":{:x}", word);
|
|
|
- state
|
|
|
+ fn prefix_len(&self) -> Option<u8> {
|
|
|
+ let mut ones = true;
|
|
|
+ let mut prefix_len = 0;
|
|
|
+ for byte in self.octets() {
|
|
|
+ let mut mask = 0x80;
|
|
|
+ for _ in 0..8 {
|
|
|
+ let one = byte & mask != 0;
|
|
|
+ if ones {
|
|
|
+ // Expect 1s until first 0
|
|
|
+ if one {
|
|
|
+ prefix_len += 1;
|
|
|
+ } else {
|
|
|
+ ones = false;
|
|
|
+ }
|
|
|
+ } else if one {
|
|
|
+ // 1 where 0 was expected
|
|
|
+ return None;
|
|
|
}
|
|
|
+ mask >>= 1;
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(feature = "proto-ipv4")]
|
|
|
-/// Convert the given IPv4 address into a IPv4-mapped IPv6 address
|
|
|
-impl From<ipv4::Address> for Address {
|
|
|
- fn from(address: ipv4::Address) -> Self {
|
|
|
- let mut b = [0_u8; ADDR_SIZE];
|
|
|
- b[..Self::IPV4_MAPPED_PREFIX.len()].copy_from_slice(&Self::IPV4_MAPPED_PREFIX);
|
|
|
- b[Self::IPV4_MAPPED_PREFIX.len()..].copy_from_slice(&address.0);
|
|
|
- Self(b)
|
|
|
+ Some(prefix_len)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// A specification of an IPv6 CIDR block, containing an address and a variable-length
|
|
|
/// subnet masking prefix length.
|
|
|
-#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
|
|
|
+#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
|
|
pub struct Cidr {
|
|
|
address: Address,
|
|
|
prefix_len: u8,
|
|
@@ -470,10 +231,7 @@ impl Cidr {
|
|
|
///
|
|
|
/// [solicited node prefix]: https://tools.ietf.org/html/rfc4291#section-2.7.1
|
|
|
pub const SOLICITED_NODE_PREFIX: Cidr = Cidr {
|
|
|
- address: Address([
|
|
|
- 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00,
|
|
|
- 0x00, 0x00,
|
|
|
- ]),
|
|
|
+ address: Address::new(0xff02, 0, 0, 0, 0, 1, 0xff00, 0),
|
|
|
prefix_len: 104,
|
|
|
};
|
|
|
|
|
@@ -763,14 +521,14 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
|
|
|
#[inline]
|
|
|
pub fn set_src_addr(&mut self, value: Address) {
|
|
|
let data = self.buffer.as_mut();
|
|
|
- data[field::SRC_ADDR].copy_from_slice(value.as_bytes());
|
|
|
+ data[field::SRC_ADDR].copy_from_slice(&value.octets());
|
|
|
}
|
|
|
|
|
|
/// Set the destination address field.
|
|
|
#[inline]
|
|
|
pub fn set_dst_addr(&mut self, value: Address) {
|
|
|
let data = self.buffer.as_mut();
|
|
|
- data[field::DST_ADDR].copy_from_slice(value.as_bytes());
|
|
|
+ data[field::DST_ADDR].copy_from_slice(&value.octets());
|
|
|
}
|
|
|
|
|
|
/// Return a mutable pointer to the payload.
|
|
@@ -904,26 +662,17 @@ impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
|
|
|
|
|
|
#[cfg(test)]
|
|
|
pub(crate) mod test {
|
|
|
- use super::Error;
|
|
|
- use super::{Address, Cidr};
|
|
|
- use super::{Packet, Protocol, Repr};
|
|
|
+ use super::*;
|
|
|
use crate::wire::pretty_print::PrettyPrinter;
|
|
|
|
|
|
- #[cfg(feature = "proto-ipv4")]
|
|
|
- use crate::wire::ipv4::Address as Ipv4Address;
|
|
|
-
|
|
|
#[allow(unused)]
|
|
|
- pub(crate) const MOCK_IP_ADDR_1: Address =
|
|
|
- Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
|
|
|
+ pub(crate) const MOCK_IP_ADDR_1: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
|
|
|
#[allow(unused)]
|
|
|
- pub(crate) const MOCK_IP_ADDR_2: Address =
|
|
|
- Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2]);
|
|
|
+ pub(crate) const MOCK_IP_ADDR_2: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2);
|
|
|
#[allow(unused)]
|
|
|
- pub(crate) const MOCK_IP_ADDR_3: Address =
|
|
|
- Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3]);
|
|
|
+ pub(crate) const MOCK_IP_ADDR_3: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 3);
|
|
|
#[allow(unused)]
|
|
|
- pub(crate) const MOCK_IP_ADDR_4: Address =
|
|
|
- Address([0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4]);
|
|
|
+ pub(crate) const MOCK_IP_ADDR_4: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 4);
|
|
|
#[allow(unused)]
|
|
|
pub(crate) const MOCK_UNSPECIFIED: Address = Address::UNSPECIFIED;
|
|
|
|
|
@@ -933,18 +682,18 @@ pub(crate) mod test {
|
|
|
|
|
|
#[test]
|
|
|
fn test_basic_multicast() {
|
|
|
- assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_unspecified());
|
|
|
- assert!(Address::LINK_LOCAL_ALL_ROUTERS.is_multicast());
|
|
|
- assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_link_local());
|
|
|
- assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_loopback());
|
|
|
- assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_unique_local());
|
|
|
- assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_global_unicast());
|
|
|
- assert!(!Address::LINK_LOCAL_ALL_NODES.is_unspecified());
|
|
|
- assert!(Address::LINK_LOCAL_ALL_NODES.is_multicast());
|
|
|
- assert!(!Address::LINK_LOCAL_ALL_NODES.is_link_local());
|
|
|
- assert!(!Address::LINK_LOCAL_ALL_NODES.is_loopback());
|
|
|
- assert!(!Address::LINK_LOCAL_ALL_NODES.is_unique_local());
|
|
|
- assert!(!Address::LINK_LOCAL_ALL_NODES.is_global_unicast());
|
|
|
+ assert!(!LINK_LOCAL_ALL_ROUTERS.is_unspecified());
|
|
|
+ assert!(LINK_LOCAL_ALL_ROUTERS.is_multicast());
|
|
|
+ assert!(!LINK_LOCAL_ALL_ROUTERS.is_link_local());
|
|
|
+ assert!(!LINK_LOCAL_ALL_ROUTERS.is_loopback());
|
|
|
+ assert!(!LINK_LOCAL_ALL_ROUTERS.x_is_unique_local());
|
|
|
+ assert!(!LINK_LOCAL_ALL_ROUTERS.is_global_unicast());
|
|
|
+ assert!(!LINK_LOCAL_ALL_NODES.is_unspecified());
|
|
|
+ assert!(LINK_LOCAL_ALL_NODES.is_multicast());
|
|
|
+ assert!(!LINK_LOCAL_ALL_NODES.is_link_local());
|
|
|
+ assert!(!LINK_LOCAL_ALL_NODES.is_loopback());
|
|
|
+ assert!(!LINK_LOCAL_ALL_NODES.x_is_unique_local());
|
|
|
+ assert!(!LINK_LOCAL_ALL_NODES.is_global_unicast());
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
@@ -953,18 +702,18 @@ pub(crate) mod test {
|
|
|
assert!(!LINK_LOCAL_ADDR.is_multicast());
|
|
|
assert!(LINK_LOCAL_ADDR.is_link_local());
|
|
|
assert!(!LINK_LOCAL_ADDR.is_loopback());
|
|
|
- assert!(!LINK_LOCAL_ADDR.is_unique_local());
|
|
|
+ assert!(!LINK_LOCAL_ADDR.x_is_unique_local());
|
|
|
assert!(!LINK_LOCAL_ADDR.is_global_unicast());
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
fn test_basic_loopback() {
|
|
|
- assert!(!Address::LOOPBACK.is_unspecified());
|
|
|
- assert!(!Address::LOOPBACK.is_multicast());
|
|
|
- assert!(!Address::LOOPBACK.is_link_local());
|
|
|
- assert!(Address::LOOPBACK.is_loopback());
|
|
|
- assert!(!Address::LOOPBACK.is_unique_local());
|
|
|
- assert!(!Address::LOOPBACK.is_global_unicast());
|
|
|
+ assert!(!Address::LOCALHOST.is_unspecified());
|
|
|
+ assert!(!Address::LOCALHOST.is_multicast());
|
|
|
+ assert!(!Address::LOCALHOST.is_link_local());
|
|
|
+ assert!(Address::LOCALHOST.is_loopback());
|
|
|
+ assert!(!Address::LOCALHOST.x_is_unique_local());
|
|
|
+ assert!(!Address::LOCALHOST.is_global_unicast());
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
@@ -973,7 +722,7 @@ pub(crate) mod test {
|
|
|
assert!(!UNIQUE_LOCAL_ADDR.is_multicast());
|
|
|
assert!(!UNIQUE_LOCAL_ADDR.is_link_local());
|
|
|
assert!(!UNIQUE_LOCAL_ADDR.is_loopback());
|
|
|
- assert!(UNIQUE_LOCAL_ADDR.is_unique_local());
|
|
|
+ assert!(UNIQUE_LOCAL_ADDR.x_is_unique_local());
|
|
|
assert!(!UNIQUE_LOCAL_ADDR.is_global_unicast());
|
|
|
}
|
|
|
|
|
@@ -983,87 +732,10 @@ pub(crate) mod test {
|
|
|
assert!(!GLOBAL_UNICAST_ADDR.is_multicast());
|
|
|
assert!(!GLOBAL_UNICAST_ADDR.is_link_local());
|
|
|
assert!(!GLOBAL_UNICAST_ADDR.is_loopback());
|
|
|
- assert!(!GLOBAL_UNICAST_ADDR.is_unique_local());
|
|
|
+ assert!(!GLOBAL_UNICAST_ADDR.x_is_unique_local());
|
|
|
assert!(GLOBAL_UNICAST_ADDR.is_global_unicast());
|
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
- fn test_address_format() {
|
|
|
- assert_eq!("ff02::1", format!("{}", Address::LINK_LOCAL_ALL_NODES));
|
|
|
- assert_eq!("fe80::1", format!("{LINK_LOCAL_ADDR}"));
|
|
|
- assert_eq!(
|
|
|
- "fe80::7f00:0:1",
|
|
|
- format!(
|
|
|
- "{}",
|
|
|
- Address::new(0xfe80, 0, 0, 0, 0, 0x7f00, 0x0000, 0x0001)
|
|
|
- )
|
|
|
- );
|
|
|
- assert_eq!("::", format!("{}", Address::UNSPECIFIED));
|
|
|
- assert_eq!("::1", format!("{}", Address::LOOPBACK));
|
|
|
-
|
|
|
- #[cfg(feature = "proto-ipv4")]
|
|
|
- assert_eq!(
|
|
|
- "::ffff:192.168.1.1",
|
|
|
- format!("{}", Address::from(Ipv4Address::new(192, 168, 1, 1)))
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- #[test]
|
|
|
- fn test_new() {
|
|
|
- assert_eq!(
|
|
|
- Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1),
|
|
|
- Address::LINK_LOCAL_ALL_NODES
|
|
|
- );
|
|
|
- assert_eq!(
|
|
|
- Address::new(0xff02, 0, 0, 0, 0, 0, 0, 2),
|
|
|
- Address::LINK_LOCAL_ALL_ROUTERS
|
|
|
- );
|
|
|
- assert_eq!(Address::new(0, 0, 0, 0, 0, 0, 0, 1), Address::LOOPBACK);
|
|
|
- assert_eq!(Address::new(0, 0, 0, 0, 0, 0, 0, 0), Address::UNSPECIFIED);
|
|
|
- assert_eq!(Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1), LINK_LOCAL_ADDR);
|
|
|
- }
|
|
|
-
|
|
|
- #[test]
|
|
|
- fn test_from_parts() {
|
|
|
- assert_eq!(
|
|
|
- Address::from_parts(&[0xff02, 0, 0, 0, 0, 0, 0, 1]),
|
|
|
- Address::LINK_LOCAL_ALL_NODES
|
|
|
- );
|
|
|
- assert_eq!(
|
|
|
- Address::from_parts(&[0xff02, 0, 0, 0, 0, 0, 0, 2]),
|
|
|
- Address::LINK_LOCAL_ALL_ROUTERS
|
|
|
- );
|
|
|
- assert_eq!(
|
|
|
- Address::from_parts(&[0, 0, 0, 0, 0, 0, 0, 1]),
|
|
|
- Address::LOOPBACK
|
|
|
- );
|
|
|
- assert_eq!(
|
|
|
- Address::from_parts(&[0, 0, 0, 0, 0, 0, 0, 0]),
|
|
|
- Address::UNSPECIFIED
|
|
|
- );
|
|
|
- assert_eq!(
|
|
|
- Address::from_parts(&[0xfe80, 0, 0, 0, 0, 0, 0, 1]),
|
|
|
- LINK_LOCAL_ADDR
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- #[test]
|
|
|
- fn test_write_parts() {
|
|
|
- let mut bytes = [0u16; 8];
|
|
|
- {
|
|
|
- Address::LOOPBACK.write_parts(&mut bytes);
|
|
|
- assert_eq!(Address::LOOPBACK, Address::from_parts(&bytes));
|
|
|
- }
|
|
|
- {
|
|
|
- Address::LINK_LOCAL_ALL_ROUTERS.write_parts(&mut bytes);
|
|
|
- assert_eq!(Address::LINK_LOCAL_ALL_ROUTERS, Address::from_parts(&bytes));
|
|
|
- }
|
|
|
- {
|
|
|
- LINK_LOCAL_ADDR.write_parts(&mut bytes);
|
|
|
- assert_eq!(LINK_LOCAL_ADDR, Address::from_parts(&bytes));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
#[test]
|
|
|
fn test_mask() {
|
|
|
let addr = Address::new(0x0123, 0x4567, 0x89ab, 0, 0, 0, 0, 1);
|
|
@@ -1089,35 +761,6 @@ pub(crate) mod test {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- #[cfg(feature = "proto-ipv4")]
|
|
|
- #[test]
|
|
|
- fn test_is_ipv4_mapped() {
|
|
|
- assert!(!Address::UNSPECIFIED.is_ipv4_mapped());
|
|
|
- assert!(Address::from(Ipv4Address::new(192, 168, 1, 1)).is_ipv4_mapped());
|
|
|
- }
|
|
|
-
|
|
|
- #[cfg(feature = "proto-ipv4")]
|
|
|
- #[test]
|
|
|
- fn test_as_ipv4() {
|
|
|
- assert_eq!(None, Address::UNSPECIFIED.as_ipv4());
|
|
|
-
|
|
|
- let ipv4 = Ipv4Address::new(192, 168, 1, 1);
|
|
|
- assert_eq!(Some(ipv4), Address::from(ipv4).as_ipv4());
|
|
|
- }
|
|
|
-
|
|
|
- #[cfg(feature = "proto-ipv4")]
|
|
|
- #[test]
|
|
|
- fn test_from_ipv4_address() {
|
|
|
- assert_eq!(
|
|
|
- Address([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 168, 1, 1]),
|
|
|
- Address::from(Ipv4Address::new(192, 168, 1, 1))
|
|
|
- );
|
|
|
- assert_eq!(
|
|
|
- Address([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 222, 1, 41, 90]),
|
|
|
- Address::from(Ipv4Address::new(222, 1, 41, 90))
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
#[test]
|
|
|
fn test_cidr() {
|
|
|
// fe80::1/56
|
|
@@ -1241,16 +884,19 @@ pub(crate) mod test {
|
|
|
assert!(!cidr.contains_addr(&addr));
|
|
|
}
|
|
|
|
|
|
- for subnet in subnets.iter().map(|&(a, p)| Cidr::new(Address(a), p)) {
|
|
|
+ for subnet in subnets.iter().map(|&(a, p)| Cidr::new(Address::from(a), p)) {
|
|
|
assert!(cidr.contains_subnet(&subnet));
|
|
|
}
|
|
|
|
|
|
- for subnet in not_subnets.iter().map(|&(a, p)| Cidr::new(Address(a), p)) {
|
|
|
+ for subnet in not_subnets
|
|
|
+ .iter()
|
|
|
+ .map(|&(a, p)| Cidr::new(Address::from(a), p))
|
|
|
+ {
|
|
|
assert!(!cidr.contains_subnet(&subnet));
|
|
|
}
|
|
|
|
|
|
let cidr_without_prefix = Cidr::new(LINK_LOCAL_ADDR, 0);
|
|
|
- assert!(cidr_without_prefix.contains_addr(&Address::LOOPBACK));
|
|
|
+ assert!(cidr_without_prefix.contains_addr(&Address::LOCALHOST));
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
@@ -1259,56 +905,56 @@ pub(crate) mod test {
|
|
|
let _ = Address::from_bytes(&[0u8; 15]);
|
|
|
}
|
|
|
|
|
|
- #[test]
|
|
|
- #[should_panic(expected = "data.len() >= 8")]
|
|
|
- fn test_from_parts_too_long() {
|
|
|
- let _ = Address::from_parts(&[0u16; 7]);
|
|
|
- }
|
|
|
-
|
|
|
#[test]
|
|
|
fn test_scope() {
|
|
|
use super::*;
|
|
|
assert_eq!(
|
|
|
- Address::new(0xff01, 0, 0, 0, 0, 0, 0, 1).multicast_scope(),
|
|
|
+ Address::new(0xff01, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
|
|
|
MulticastScope::InterfaceLocal
|
|
|
);
|
|
|
assert_eq!(
|
|
|
- Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1).multicast_scope(),
|
|
|
+ Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
|
|
|
MulticastScope::LinkLocal
|
|
|
);
|
|
|
assert_eq!(
|
|
|
- Address::new(0xff03, 0, 0, 0, 0, 0, 0, 1).multicast_scope(),
|
|
|
+ Address::new(0xff03, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
|
|
|
MulticastScope::Unknown
|
|
|
);
|
|
|
assert_eq!(
|
|
|
- Address::new(0xff04, 0, 0, 0, 0, 0, 0, 1).multicast_scope(),
|
|
|
+ Address::new(0xff04, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
|
|
|
MulticastScope::AdminLocal
|
|
|
);
|
|
|
assert_eq!(
|
|
|
- Address::new(0xff05, 0, 0, 0, 0, 0, 0, 1).multicast_scope(),
|
|
|
+ Address::new(0xff05, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
|
|
|
MulticastScope::SiteLocal
|
|
|
);
|
|
|
assert_eq!(
|
|
|
- Address::new(0xff08, 0, 0, 0, 0, 0, 0, 1).multicast_scope(),
|
|
|
+ Address::new(0xff08, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
|
|
|
MulticastScope::OrganizationLocal
|
|
|
);
|
|
|
assert_eq!(
|
|
|
- Address::new(0xff0e, 0, 0, 0, 0, 0, 0, 1).multicast_scope(),
|
|
|
+ Address::new(0xff0e, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
|
|
|
MulticastScope::Global
|
|
|
);
|
|
|
|
|
|
assert_eq!(
|
|
|
- Address::LINK_LOCAL_ALL_NODES.multicast_scope(),
|
|
|
+ LINK_LOCAL_ALL_NODES.x_multicast_scope(),
|
|
|
MulticastScope::LinkLocal
|
|
|
);
|
|
|
|
|
|
// For source address selection, unicast addresses also have a scope:
|
|
|
- assert_eq!(LINK_LOCAL_ADDR.multicast_scope(), MulticastScope::LinkLocal);
|
|
|
assert_eq!(
|
|
|
- GLOBAL_UNICAST_ADDR.multicast_scope(),
|
|
|
+ LINK_LOCAL_ADDR.x_multicast_scope(),
|
|
|
+ MulticastScope::LinkLocal
|
|
|
+ );
|
|
|
+ assert_eq!(
|
|
|
+ GLOBAL_UNICAST_ADDR.x_multicast_scope(),
|
|
|
+ MulticastScope::Global
|
|
|
+ );
|
|
|
+ assert_eq!(
|
|
|
+ UNIQUE_LOCAL_ADDR.x_multicast_scope(),
|
|
|
MulticastScope::Global
|
|
|
);
|
|
|
- assert_eq!(UNIQUE_LOCAL_ADDR.multicast_scope(), MulticastScope::Global);
|
|
|
}
|
|
|
|
|
|
static REPR_PACKET_BYTES: [u8; 52] = [
|
|
@@ -1323,11 +969,8 @@ pub(crate) mod test {
|
|
|
|
|
|
const fn packet_repr() -> Repr {
|
|
|
Repr {
|
|
|
- src_addr: Address([
|
|
|
- 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
- 0x00, 0x01,
|
|
|
- ]),
|
|
|
- dst_addr: Address::LINK_LOCAL_ALL_NODES,
|
|
|
+ src_addr: Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
|
|
|
+ dst_addr: LINK_LOCAL_ALL_NODES,
|
|
|
next_header: Protocol::Udp,
|
|
|
payload_len: 12,
|
|
|
hop_limit: 64,
|
|
@@ -1345,14 +988,8 @@ pub(crate) mod test {
|
|
|
assert_eq!(packet.payload_len() as usize, REPR_PAYLOAD_BYTES.len());
|
|
|
assert_eq!(packet.next_header(), Protocol::Udp);
|
|
|
assert_eq!(packet.hop_limit(), 0x40);
|
|
|
- assert_eq!(
|
|
|
- packet.src_addr(),
|
|
|
- Address([
|
|
|
- 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
- 0x00, 0x01
|
|
|
- ])
|
|
|
- );
|
|
|
- assert_eq!(packet.dst_addr(), Address::LINK_LOCAL_ALL_NODES);
|
|
|
+ assert_eq!(packet.src_addr(), Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1));
|
|
|
+ assert_eq!(packet.dst_addr(), LINK_LOCAL_ALL_NODES);
|
|
|
assert_eq!(packet.payload(), &REPR_PAYLOAD_BYTES[..]);
|
|
|
}
|
|
|
|
|
@@ -1374,8 +1011,8 @@ pub(crate) mod test {
|
|
|
packet.set_payload_len(0xc);
|
|
|
packet.set_next_header(Protocol::Udp);
|
|
|
packet.set_hop_limit(0xfe);
|
|
|
- packet.set_src_addr(Address::LINK_LOCAL_ALL_ROUTERS);
|
|
|
- packet.set_dst_addr(Address::LINK_LOCAL_ALL_NODES);
|
|
|
+ packet.set_src_addr(LINK_LOCAL_ALL_ROUTERS);
|
|
|
+ packet.set_dst_addr(LINK_LOCAL_ALL_NODES);
|
|
|
packet
|
|
|
.payload_mut()
|
|
|
.copy_from_slice(&REPR_PAYLOAD_BYTES[..]);
|