Skip to main content

openthread/ot/types/
ipv6.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::prelude_internal::*;
6
7use core::fmt::{Debug, Formatter};
8use num_derive::FromPrimitive;
9use std::net::SocketAddrV6;
10
11/// IPv6 Address Type. Functional equivalent of [`otsys::otIp6Address`](crate::otsys::otIp6Address).
12///
13/// ## NOTES ON SAFETY ##
14///
15/// Here we are making the assumption that a [`std::net::Ipv6Addr`] can
16/// be freely and safely transmuted to and from an [`otIp6Address`](crate::otsys::otIp6Address).
17/// Doing this is very convenient. On the face of it, this might seem like a safe assumption:
18/// IPv6 addresses are always 16 bytes long, that ought to be fine, right? And, in my testing,
19/// it does seem to work.
20///
21/// But thinking more carefully about it it seems that this is not *guaranteed* to
22/// be the case. This is supported by the fact that the rust API appears to avoid what
23/// would otherwise be obvious additions, such as a method to return the IPv6 address as
24/// a slice (`octets()` returns a fixed-size array).
25///
26/// As a crutch, I've added static assertions in various places to verify my assumptions.
27/// This effectively eliminates chances of undefined behavior causing problems, but does so
28/// at the expense of failing to compile when those assumptions are not met... So we may
29/// want to revisit this approach in the future if this is a big concern.
30pub type Ip6Address = std::net::Ipv6Addr;
31
32/// Functional equivalent of [`otsys::OT_IP6_PREFIX_BITSIZE`](crate::otsys::OT_IP6_PREFIX_BITSIZE).
33pub const IP6_PREFIX_BITSIZE: u8 = otsys::OT_IP6_PREFIX_BITSIZE as u8;
34
35impl Transparent for std::net::Ipv6Addr {
36    fn from_ot(x: otIp6Address) -> std::net::Ipv6Addr {
37        unsafe { x.mFields.m8.into() }
38    }
39
40    fn into_ot(self) -> otIp6Address {
41        otIp6Address { mFields: otIp6Address__bindgen_ty_1 { m8: self.octets() } }
42    }
43}
44
45unsafe impl OtCastable for std::net::Ipv6Addr {
46    type OtType = otIp6Address;
47
48    fn as_ot_ptr(&self) -> *const otIp6Address {
49        sa::assert_eq_size!(Ip6Address, otIp6Address);
50        sa::assert_eq_align!(Ip6Address, otIp6Address);
51        self as *const Self as *const otIp6Address
52    }
53
54    fn as_ot_mut_ptr(&mut self) -> *mut Self::OtType {
55        self as *mut Self as *mut Self::OtType
56    }
57
58    unsafe fn ref_from_ot_ptr<'a>(ptr: *const otIp6Address) -> Option<&'a Self> {
59        if ptr.is_null() {
60            None
61        } else {
62            sa::assert_eq_size!(Ip6Address, otIp6Address);
63            sa::assert_eq_align!(Ip6Address, otIp6Address);
64
65            // SAFETY: The safety of this dereference is ensured by the above two static assertions.
66            Some(unsafe { &*(ptr as *const Self) })
67        }
68    }
69
70    unsafe fn mut_from_ot_mut_ptr<'a>(ptr: *mut otIp6Address) -> Option<&'a mut Self> {
71        if ptr.is_null() {
72            None
73        } else {
74            sa::assert_eq_size!(Ip6Address, otIp6Address);
75            sa::assert_eq_align!(Ip6Address, otIp6Address);
76
77            // SAFETY: The safety of this dereference is ensured by the above two static assertions.
78            Some(unsafe { &mut *(ptr as *mut Self) })
79        }
80    }
81}
82
83/// Data type representing a 64-bit IPv6 network prefix.
84///
85/// Functional equivalent of [`otsys::otIp6NetworkPrefix`](crate::otsys::otIp6NetworkPrefix).
86#[derive(Default, Clone, Copy)]
87#[repr(transparent)]
88pub struct Ip6NetworkPrefix(pub otIp6NetworkPrefix);
89
90impl_ot_castable!(Ip6NetworkPrefix, otIp6NetworkPrefix);
91
92impl PartialEq for Ip6NetworkPrefix {
93    fn eq(&self, other: &Self) -> bool {
94        self.0.m8 == other.0.m8
95    }
96}
97
98impl Eq for Ip6NetworkPrefix {}
99
100impl Debug for Ip6NetworkPrefix {
101    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
102        std::net::Ipv6Addr::from(*self).fmt(f)?;
103        write!(f, "/64")
104    }
105}
106
107impl std::fmt::Display for Ip6NetworkPrefix {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
109        std::fmt::Debug::fmt(self, f)
110    }
111}
112
113impl Ip6NetworkPrefix {
114    /// Returns this network prefix as a byte slice.
115    pub fn as_slice(&self) -> &[u8] {
116        &self.0.m8
117    }
118
119    /// Returns this network prefix as an 8-byte array by value.
120    pub fn octets(&self) -> [u8; 8] {
121        let mut octets = [0u8; 8];
122        octets.clone_from_slice(self.as_slice());
123        octets
124    }
125
126    /// Returns true is the given address is in this network prefix.
127    pub fn contains(&self, addr: &std::net::Ipv6Addr) -> bool {
128        self.0.m8 == addr.octets()[0..8]
129    }
130
131    /// Get the scope of the prefix
132    pub fn get_scope(&self) -> Scope {
133        let addr: std::net::Ipv6Addr = (*self).into();
134        if addr.is_multicast() {
135            ot::types::ipv6::Scope::from(addr.octets()[1] & 0xf)
136        } else if self.is_link_local() {
137            Scope::LINK_LOCAL
138        } else if addr.is_loopback() {
139            Scope::NODE_LOCAL
140        } else {
141            Scope::GLOBAL
142        }
143    }
144
145    /// Check if this is a link local prefix
146    pub fn is_link_local(&self) -> bool {
147        (self.0.m8[0] == 0xfe) && ((self.0.m8[1] & 0xc0) == 0x80)
148    }
149}
150
151impl From<[u8; 8]> for Ip6NetworkPrefix {
152    fn from(m8: [u8; 8]) -> Self {
153        Self(otIp6NetworkPrefix { m8 })
154    }
155}
156
157impl From<Ip6NetworkPrefix> for std::net::Ipv6Addr {
158    fn from(prefix: Ip6NetworkPrefix) -> Self {
159        let mut octets = [0u8; 16];
160        octets[0..8].clone_from_slice(prefix.as_slice());
161        octets.into()
162    }
163}
164
165impl From<std::net::Ipv6Addr> for Ip6NetworkPrefix {
166    fn from(x: std::net::Ipv6Addr) -> Self {
167        let mut ret = Ip6NetworkPrefix::default();
168        ret.0.m8.clone_from_slice(&x.octets()[0..8]);
169        ret
170    }
171}
172
173/// Data type representing IPv6 address information.
174///
175/// Functional equivalent of [`otsys::otIp6AddressInfo`](crate::otsys::otIp6AddressInfo).
176/// Note that this type has a lifetime because the original OpenThread
177/// type includes a pointer to the IPv6 address.
178#[derive(Default, Clone, Copy)]
179#[repr(transparent)]
180pub struct Ip6AddressInfo<'a>(otIp6AddressInfo, PhantomData<*mut &'a ()>);
181
182impl_ot_castable!(lifetime Ip6AddressInfo<'_>, otIp6AddressInfo, Default::default());
183
184impl Debug for Ip6AddressInfo<'_> {
185    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
186        self.addr().fmt(f)?;
187        write!(f, "/{} {:?}", self.prefix_len(), self.scope())?;
188        if self.is_preferred() {
189            write!(f, " PREFERRED")?;
190        }
191
192        Ok(())
193    }
194}
195
196impl<'a> Ip6AddressInfo<'a> {
197    /// Returns a reference to the `Ip6Address`.
198    pub fn addr(&self) -> &'a Ip6Address {
199        unsafe { Ip6Address::ref_from_ot_ptr(self.0.mAddress).unwrap() }
200    }
201
202    /// Returns true if this address is preferred.
203    pub fn is_preferred(&self) -> bool {
204        self.0.mPreferred()
205    }
206
207    /// Returns the prefix length of this address.
208    pub fn prefix_len(&self) -> u8 {
209        self.0.mPrefixLength
210    }
211
212    /// Returns the scope of this address
213    pub fn scope(&self) -> Scope {
214        Scope(self.0.mScope())
215    }
216
217    /// Returns true if this address is a multicast address.
218    pub fn is_multicast(&self) -> bool {
219        self.addr().is_multicast()
220    }
221}
222
223/// Type representing an IPv6 scope, as represented on IPv6 multicast addresses.
224#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
225#[repr(transparent)]
226pub struct Scope(pub u8);
227
228#[allow(missing_docs)]
229impl Scope {
230    pub const NODE_LOCAL: Scope = Scope(0x0);
231    pub const INTERFACE_LOCAL: Scope = Scope(0x1);
232    pub const LINK_LOCAL: Scope = Scope(0x2);
233    pub const REALM_LOCAL: Scope = Scope(0x3);
234    pub const ADMIN_LOCAL: Scope = Scope(0x4);
235    pub const SITE_LOCAL: Scope = Scope(0x5);
236    pub const ORGANIZATION_LOCAL: Scope = Scope(0x8);
237    pub const GLOBAL: Scope = Scope(0xe);
238}
239
240impl Debug for Scope {
241    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
242        match *self {
243            Self::INTERFACE_LOCAL => write!(f, "Scope::INTERFACE_LOCAL"),
244            Self::LINK_LOCAL => write!(f, "Scope::LINK_LOCAL"),
245            Self::REALM_LOCAL => write!(f, "Scope::REALM_LOCAL"),
246            Self::ADMIN_LOCAL => write!(f, "Scope::ADMIN_LOCAL"),
247            Self::SITE_LOCAL => write!(f, "Scope::SITE_LOCAL"),
248            Self::ORGANIZATION_LOCAL => write!(f, "Scope::ORGANIZATION_LOCAL"),
249            Self::GLOBAL => write!(f, "Scope::GLOBAL"),
250            Scope(x) => write!(f, "Scope({x})"),
251        }
252    }
253}
254
255impl From<Scope> for u8 {
256    fn from(x: Scope) -> Self {
257        x.0
258    }
259}
260
261impl From<u8> for Scope {
262    fn from(x: u8) -> Self {
263        Scope(x)
264    }
265}
266
267impl From<Scope> for u32 {
268    fn from(x: Scope) -> Self {
269        x.0 as u32
270    }
271}
272
273/// Type representing the origin of an address
274#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
275pub struct AddressOrigin(pub u8);
276
277impl AddressOrigin {
278    /// Functional equivalent of
279    /// [`otsys::OT_ADDRESS_ORIGIN_DHCPV6`](crate::otsys::OT_ADDRESS_ORIGIN_DHCPV6).
280    pub const DHCPV6: AddressOrigin = AddressOrigin(OT_ADDRESS_ORIGIN_DHCPV6 as u8);
281
282    /// Functional equivalent of
283    /// [`otsys::OT_ADDRESS_ORIGIN_MANUAL`](crate::otsys::OT_ADDRESS_ORIGIN_MANUAL).
284    pub const MANUAL: AddressOrigin = AddressOrigin(OT_ADDRESS_ORIGIN_MANUAL as u8);
285
286    /// Functional equivalent of
287    /// [`otsys::OT_ADDRESS_ORIGIN_SLAAC`](crate::otsys::OT_ADDRESS_ORIGIN_SLAAC).
288    pub const SLAAC: AddressOrigin = AddressOrigin(OT_ADDRESS_ORIGIN_SLAAC as u8);
289
290    /// Functional equivalent of
291    /// [`otsys::OT_ADDRESS_ORIGIN_THREAD`](crate::otsys::OT_ADDRESS_ORIGIN_THREAD).
292    pub const THREAD: AddressOrigin = AddressOrigin(OT_ADDRESS_ORIGIN_THREAD as u8);
293}
294
295impl Debug for AddressOrigin {
296    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
297        match *self {
298            Self::DHCPV6 => write!(f, "AddressOrigin::DHCPV6"),
299            Self::MANUAL => write!(f, "AddressOrigin::MANUAL"),
300            Self::SLAAC => write!(f, "AddressOrigin::SLAAC"),
301            Self::THREAD => write!(f, "AddressOrigin::THREAD"),
302            AddressOrigin(x) => write!(f, "AddressOrigin({x})"),
303        }
304    }
305}
306
307/// Data type representing IPv6 address from a network interface.
308/// Functional equivalent of [`otsys::otNetifAddress`](crate::otsys::otNetifAddress).
309#[derive(Default, Clone, Copy)]
310#[repr(transparent)]
311pub struct NetifAddress(pub(crate) otNetifAddress);
312
313impl_ot_castable!(NetifAddress, otNetifAddress);
314
315impl Debug for NetifAddress {
316    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
317        self.addr().fmt(f)?;
318        write!(f, "/{} {:?}", self.prefix_len(), self.address_origin())?;
319        if let Some(scope) = self.scope() {
320            write!(f, " {scope:?}")?;
321        }
322        if self.is_valid() {
323            write!(f, " VALID")?;
324        }
325        if self.is_preferred() {
326            write!(f, " PREFERRED")?;
327        }
328        if self.is_rloc() {
329            write!(f, " RLOC")?;
330        }
331        Ok(())
332    }
333}
334
335impl std::fmt::Display for NetifAddress {
336    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
337        std::fmt::Debug::fmt(self, f)
338    }
339}
340
341impl NetifAddress {
342    /// Creates a new instance from an Ipv6 address and prefix length.
343    ///
344    /// The resulting instance will have the `valid` and `preferred` bits set.
345    pub fn new(addr: std::net::Ipv6Addr, prefix_len: u8) -> NetifAddress {
346        let mut ret = NetifAddress(otNetifAddress {
347            mAddress: addr.into_ot(),
348            mPrefixLength: prefix_len,
349            mAddressOrigin: 0,
350            _bitfield_align_1: [],
351            _bitfield_1: Default::default(),
352            mNext: std::ptr::null_mut(),
353        });
354        ret.set_valid(true);
355        ret.set_preferred(true);
356        ret
357    }
358
359    /// Returns a reference to the IPv6 address.
360    pub fn addr(&self) -> &Ip6Address {
361        Ip6Address::ref_from_ot_ref(&self.0.mAddress)
362    }
363
364    /// Returns the prefix length for this address.
365    pub fn prefix_len(&self) -> u8 {
366        self.0.mPrefixLength
367    }
368
369    /// Returns the address origin for this address.
370    pub fn address_origin(&self) -> AddressOrigin {
371        AddressOrigin(self.0.mAddressOrigin)
372    }
373
374    /// Returns the scope override for this address.
375    pub fn scope(&self) -> Option<Scope> {
376        if self.0.mScopeOverrideValid() {
377            Some(Scope(self.0.mScopeOverride().try_into().expect("NetifAddress: invalid scope")))
378        } else {
379            None
380        }
381    }
382
383    /// Sets the scope override for this address.
384    pub fn set_scope(&mut self, scope: Option<Scope>) {
385        if let Some(scope) = scope {
386            self.0.set_mScopeOverrideValid(true);
387            self.0.set_mScopeOverride(scope.into());
388        } else {
389            self.0.set_mScopeOverrideValid(false);
390        }
391    }
392
393    /// Returns true if this address is preferred.
394    pub fn is_preferred(&self) -> bool {
395        self.0.mPreferred()
396    }
397
398    /// Sets the `preferred` bit on this address.
399    pub fn set_preferred(&mut self, x: bool) {
400        self.0.set_mPreferred(x)
401    }
402
403    /// Returns true if this address is an RLOC.
404    pub fn is_rloc(&self) -> bool {
405        self.0.mRloc()
406    }
407
408    /// Sets the `rloc` bit on this address.
409    pub fn set_rloc(&mut self, x: bool) {
410        self.0.set_mRloc(x)
411    }
412
413    /// Returns true if this address is valid.
414    pub fn is_valid(&self) -> bool {
415        self.0.mValid()
416    }
417
418    /// Sets the `valid` bit on this address.
419    pub fn set_valid(&mut self, x: bool) {
420        self.0.set_mValid(x)
421    }
422}
423
424/// IPv6 subnet prefix with an arbitrary prefix length.
425/// Functional equivalent of [`otsys::otIp6Prefix`](crate::otsys::otIp6Prefix).
426#[derive(Default, Clone, Copy)]
427#[repr(transparent)]
428pub struct Ip6Prefix(pub otIp6Prefix);
429
430impl_ot_castable!(Ip6Prefix, otIp6Prefix);
431
432impl PartialEq for Ip6Prefix {
433    fn eq(&self, other: &Self) -> bool {
434        self.addr() == other.addr() && self.prefix_len() == other.prefix_len()
435    }
436}
437
438impl Eq for Ip6Prefix {}
439
440impl Debug for Ip6Prefix {
441    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
442        self.addr().fmt(f)?;
443        write!(f, "/{}", self.prefix_len())
444    }
445}
446
447impl std::fmt::Display for Ip6Prefix {
448    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
449        std::fmt::Debug::fmt(self, f)
450    }
451}
452
453impl Ip6Prefix {
454    /// Creates a new `Ip6Prefix` from an Ipv6 address and prefix length.
455    pub fn new<T: Into<Ip6Address>>(addr: T, prefix_len: u8) -> Ip6Prefix {
456        Ip6Prefix(otIp6Prefix { mPrefix: addr.into().into_ot(), mLength: prefix_len })
457    }
458
459    /// Returns a reference to the IPv6 address.
460    pub fn addr(&self) -> &Ip6Address {
461        Ip6Address::ref_from_ot_ref(&self.0.mPrefix)
462    }
463
464    /// Returns the prefix length.
465    pub fn prefix_len(&self) -> u8 {
466        self.0.mLength
467    }
468}
469
470/// Functional equivalent of [`otsys::otSockAddr`](crate::otsys::otSockAddr).
471#[derive(Default, Clone, Copy)]
472#[repr(transparent)]
473pub struct SockAddr(pub otSockAddr);
474
475impl_ot_castable!(SockAddr, otSockAddr);
476
477impl PartialEq for SockAddr {
478    fn eq(&self, other: &Self) -> bool {
479        self.addr() == other.addr() && self.port() == other.port()
480    }
481}
482
483impl Eq for SockAddr {}
484
485impl Debug for SockAddr {
486    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
487        write!(f, "[")?;
488        self.addr().fmt(f)?;
489        write!(f, "]:{}", self.port())
490    }
491}
492
493impl std::fmt::Display for SockAddr {
494    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
495        std::fmt::Debug::fmt(self, f)
496    }
497}
498
499impl SockAddr {
500    /// Creates a new `ot::SockAddr` from an address and port.
501    pub fn new(addr: Ip6Address, port: u16) -> Self {
502        SockAddr(otSockAddr { mAddress: addr.into_ot(), mPort: port })
503    }
504
505    /// Returns the IPv6 address.
506    pub fn addr(&self) -> Ip6Address {
507        Ip6Address::from_ot(self.0.mAddress)
508    }
509
510    /// Returns the port number.
511    pub fn port(&self) -> u16 {
512        self.0.mPort
513    }
514}
515
516impl From<(Ip6Address, u16)> for SockAddr {
517    fn from(x: (Ip6Address, u16)) -> Self {
518        Self::new(x.0, x.1)
519    }
520}
521
522impl From<Ip6Address> for SockAddr {
523    fn from(x: Ip6Address) -> Self {
524        Self::new(x, 0)
525    }
526}
527
528impl From<std::net::SocketAddrV6> for SockAddr {
529    fn from(x: std::net::SocketAddrV6) -> Self {
530        SockAddr::new(*x.ip(), x.port())
531    }
532}
533
534impl From<SockAddr> for std::net::SocketAddrV6 {
535    fn from(x: SockAddr) -> Self {
536        SocketAddrV6::new(x.addr(), x.port(), 0, 0)
537    }
538}
539
540impl From<SockAddr> for std::net::SocketAddr {
541    fn from(x: SockAddr) -> Self {
542        std::net::SocketAddr::V6(x.into())
543    }
544}
545
546/// This enumeration defines the OpenThread network interface identifiers.
547///
548/// Functional equivalent of [`otsys::otNetifIdentifier`](crate::otsys::otNetifIdentifier).
549#[derive(Debug, Copy, Clone, Eq, Ord, PartialOrd, PartialEq, num_derive::FromPrimitive)]
550#[allow(missing_docs)]
551pub enum NetifIdentifier {
552    /// Functional equivalent of [`otsys::OT_NETIF_BACKBONE`](crate::otsys::OT_NETIF_BACKBONE).
553    Backbone = OT_NETIF_BACKBONE as isize,
554
555    /// Functional equivalent of [`otsys::OT_NETIF_THREAD_HOST`](crate::otsys::OT_NETIF_THREAD_HOST).
556    Thread = OT_NETIF_THREAD_HOST as isize,
557
558    /// Functional equivalent of [`otsys::OT_NETIF_UNSPECIFIED`](crate::otsys::OT_NETIF_UNSPECIFIED).
559    Unspecified = OT_NETIF_UNSPECIFIED as isize,
560}
561
562impl From<otNetifIdentifier> for NetifIdentifier {
563    fn from(x: otNetifIdentifier) -> Self {
564        use num::FromPrimitive;
565        Self::from_u32(x).unwrap_or_else(|| panic!("Unknown otNetifIdentifier value: {x}"))
566    }
567}
568
569impl From<NetifIdentifier> for otNetifIdentifier {
570    fn from(x: NetifIdentifier) -> Self {
571        x as otNetifIdentifier
572    }
573}
574
575/// Represents an entry from the discovered prefix table.
576/// Functional equivalent of [`otsys::otBorderRoutingPrefixTableEntry`](crate::otsys::otBorderRoutingPrefixTableEntry).
577#[derive(Default, Clone, Copy)]
578#[repr(transparent)]
579pub struct BorderRoutingPrefixTableEntry(pub otBorderRoutingPrefixTableEntry);
580
581impl_ot_castable!(BorderRoutingPrefixTableEntry, otBorderRoutingPrefixTableEntry);
582
583impl Debug for BorderRoutingPrefixTableEntry {
584    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
585        f.debug_struct("otBorderRoutingPrefixTableEntry")
586            .field("router_address", &self.router_address())
587            .field("prefix", &self.prefix())
588            .field("is_on_link", &self.is_on_link())
589            .field("msec_since_last_update", &self.msec_since_last_update())
590            .field("valid_lifetime", &self.valid_lifetime())
591            .field("preferred_lifetime", &self.preferred_lifetime())
592            .field("route_preference", &self.route_preference())
593            .finish()
594    }
595}
596
597impl std::fmt::Display for BorderRoutingPrefixTableEntry {
598    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
599        std::fmt::Debug::fmt(self, f)
600    }
601}
602
603impl BorderRoutingPrefixTableEntry {
604    /// Returns a reference to the IPv6 address.
605    pub fn router_address(&self) -> &Ip6Address {
606        Ip6Address::ref_from_ot_ref(&self.0.mRouter.mAddress)
607    }
608
609    /// Returns the prefix.
610    pub fn prefix(&self) -> &Ip6Prefix {
611        Ip6Prefix::ref_from_ot_ref(&self.0.mPrefix)
612    }
613
614    /// Returns true if this prefix is on-link.
615    pub fn is_on_link(&self) -> bool {
616        self.0.mIsOnLink
617    }
618
619    /// Returns the number of milliseconds since the last update
620    pub fn msec_since_last_update(&self) -> u32 {
621        self.0.mMsecSinceLastUpdate
622    }
623
624    /// Returns the valid lifetime of the prefix (in seconds)
625    pub fn valid_lifetime(&self) -> u32 {
626        self.0.mValidLifetime
627    }
628
629    /// Returns the preferred lifetime of the prefix (in seconds)
630    pub fn preferred_lifetime(&self) -> u32 {
631        self.0.mPreferredLifetime
632    }
633
634    /// Returns the route preference
635    pub fn route_preference(&self) -> RoutePreference {
636        RoutePreference::from_isize(self.0.mPreferredLifetime as isize)
637            .unwrap_or(RoutePreference::Medium)
638    }
639}
640
641/// This enumeration represents the state of DHCPv6 Prefix Delegation State.
642///
643/// Functional equivalent of [`otsys::otBorderRoutingDhcp6PdState`](crate::otsys::otBorderRoutingDhcp6PdState).
644#[derive(Debug, Default, Copy, Clone, Eq, Ord, PartialOrd, PartialEq, FromPrimitive)]
645#[allow(missing_docs)]
646pub enum BorderRoutingDhcp6PdState {
647    #[default]
648    /// Functional equivalent of [`otsys::OT_BORDER_ROUTING_DHCP6_PD_STATE_DISABLED`](crate::otsys::OT_BORDER_ROUTING_DHCP6_PD_STATE_DISABLED)
649    Disabled = OT_BORDER_ROUTING_DHCP6_PD_STATE_DISABLED as isize,
650
651    /// Functional equivalent of [`otsys::OT_BORDER_ROUTING_DHCP6_PD_STATE_STOPPED`](crate::otsys::OT_BORDER_ROUTING_DHCP6_PD_STATE_STOPPED)
652    Stopped = OT_BORDER_ROUTING_DHCP6_PD_STATE_STOPPED as isize,
653
654    /// Functional equivalent of [`otsys::OT_BORDER_ROUTING_DHCP6_PD_STATE_RUNNING`](crate::otsys::OT_BORDER_ROUTING_DHCP6_PD_STATE_RUNNING)
655    Running = OT_BORDER_ROUTING_DHCP6_PD_STATE_RUNNING as isize,
656
657    /// Functional equivalent of [`otsys::OT_BORDER_ROUTING_DHCP6_PD_STATE_IDLE`](crate::otsys::OT_BORDER_ROUTING_DHCP6_PD_STATE_IDLE)
658    Idle = OT_BORDER_ROUTING_DHCP6_PD_STATE_IDLE as isize,
659}
660
661impl From<otBorderRoutingDhcp6PdState> for BorderRoutingDhcp6PdState {
662    fn from(x: otBorderRoutingDhcp6PdState) -> Self {
663        use num::FromPrimitive;
664        Self::from_u32(x)
665            .unwrap_or_else(|| panic!("Unknown otBorderRoutingDhcp6PdState value: {x}"))
666    }
667}
668
669impl From<BorderRoutingDhcp6PdState> for otBorderRoutingDhcp6PdState {
670    fn from(x: BorderRoutingDhcp6PdState) -> Self {
671        x as otBorderRoutingDhcp6PdState
672    }
673}