mirror of
https://github.com/smoltcp-rs/smoltcp.git
synced 2025-10-02 15:15:05 +00:00
ipv6: address scope and is_global_unicast
The scope of an address is used when selecting the source IPv6 address based on the destination address. As the scope is then also used for unicast address, I made the scope only public in the crate instead of outside the crate. Not sure if this should be public or not. This commit also adds the `is_global_unicast` query function for IPv6 addresses.
This commit is contained in:
parent
b310e3c366
commit
45f9838ad9
@ -25,6 +25,41 @@ pub const ADDR_SIZE: usize = 16;
|
||||
/// [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
|
||||
|
||||
/// The [scope] of an address.
|
||||
///
|
||||
/// [scope]: https://www.rfc-editor.org/rfc/rfc4291#section-2.7
|
||||
#[repr(u8)]
|
||||
pub(crate) enum Scope {
|
||||
/// Interface Local scope
|
||||
InterfaceLocal = 0x1,
|
||||
/// Link local scope
|
||||
LinkLocal = 0x2,
|
||||
/// Administratively configured
|
||||
AdminLocal = 0x4,
|
||||
/// Single site scope
|
||||
SiteLocal = 0x5,
|
||||
/// Organization scope
|
||||
OrganizationLocal = 0x8,
|
||||
/// Global scope
|
||||
Global = 0xE,
|
||||
/// Unknown scope
|
||||
Unknown = 0xFF,
|
||||
}
|
||||
|
||||
impl From<u8> for Scope {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
0x1 => Self::InterfaceLocal,
|
||||
0x2 => Self::LinkLocal,
|
||||
0x4 => Self::AdminLocal,
|
||||
0x5 => Self::SiteLocal,
|
||||
0x8 => Self::OrganizationLocal,
|
||||
0xE => Self::Global,
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A sixteen-octet IPv6 address.
|
||||
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
|
||||
pub struct Address(pub [u8; ADDR_SIZE]);
|
||||
@ -143,6 +178,13 @@ impl Address {
|
||||
!(self.is_multicast() || self.is_unspecified())
|
||||
}
|
||||
|
||||
/// Query whether the IPv6 address is a [global unicast address].
|
||||
///
|
||||
/// [global unicast address]: https://datatracker.ietf.org/doc/html/rfc3587
|
||||
pub const fn is_global_unicast(&self) -> bool {
|
||||
(self.0[0] >> 5) == 0b001
|
||||
}
|
||||
|
||||
/// Query whether the IPv6 address is a [multicast address].
|
||||
///
|
||||
/// [multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7
|
||||
@ -228,6 +270,22 @@ impl Address {
|
||||
])
|
||||
}
|
||||
|
||||
/// Return the scope of the address.
|
||||
pub(crate) fn scope(&self) -> Scope {
|
||||
if self.is_multicast() {
|
||||
return Scope::from(self.as_bytes()[1] & 0b1111);
|
||||
}
|
||||
|
||||
if self.is_link_local() {
|
||||
Scope::LinkLocal
|
||||
} else if self.is_unique_local() || self.is_global_unicast() {
|
||||
// ULA are considered global scope
|
||||
Scope::Global
|
||||
} else {
|
||||
Scope::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert to an `IpAddress`.
|
||||
///
|
||||
/// Same as `.into()`, but works in `const`.
|
||||
@ -840,6 +898,7 @@ mod test {
|
||||
|
||||
const LINK_LOCAL_ADDR: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
|
||||
const UNIQUE_LOCAL_ADDR: Address = Address::new(0xfd00, 0, 0, 201, 1, 1, 1, 1);
|
||||
const GLOBAL_UNICAST_ADDR: Address = Address::new(0x2001, 0xdb8, 0x3, 0, 0, 0, 0, 1);
|
||||
|
||||
#[test]
|
||||
fn test_basic_multicast() {
|
||||
@ -848,11 +907,13 @@ mod test {
|
||||
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());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -862,6 +923,7 @@ mod test {
|
||||
assert!(LINK_LOCAL_ADDR.is_link_local());
|
||||
assert!(!LINK_LOCAL_ADDR.is_loopback());
|
||||
assert!(!LINK_LOCAL_ADDR.is_unique_local());
|
||||
assert!(!LINK_LOCAL_ADDR.is_global_unicast());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -871,6 +933,7 @@ mod test {
|
||||
assert!(!Address::LOOPBACK.is_link_local());
|
||||
assert!(Address::LOOPBACK.is_loopback());
|
||||
assert!(!Address::LOOPBACK.is_unique_local());
|
||||
assert!(!Address::LOOPBACK.is_global_unicast());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -880,6 +943,17 @@ mod test {
|
||||
assert!(!UNIQUE_LOCAL_ADDR.is_link_local());
|
||||
assert!(!UNIQUE_LOCAL_ADDR.is_loopback());
|
||||
assert!(UNIQUE_LOCAL_ADDR.is_unique_local());
|
||||
assert!(!UNIQUE_LOCAL_ADDR.is_global_unicast());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_global_unicast() {
|
||||
assert!(!GLOBAL_UNICAST_ADDR.is_unspecified());
|
||||
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.is_global_unicast());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -190,6 +190,8 @@ pub use self::ipv4::{
|
||||
Repr as Ipv4Repr, HEADER_LEN as IPV4_HEADER_LEN, MIN_MTU as IPV4_MIN_MTU,
|
||||
};
|
||||
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
pub(crate) use self::ipv6::Scope as Ipv6AddressScope;
|
||||
#[cfg(feature = "proto-ipv6")]
|
||||
pub use self::ipv6::{
|
||||
Address as Ipv6Address, Cidr as Ipv6Cidr, Packet as Ipv6Packet, Repr as Ipv6Repr,
|
||||
|
Loading…
x
Reference in New Issue
Block a user