packet_formats/icmp/
ndp.rs

1// Copyright 2018 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
5//! Messages used for NDP (ICMPv6).
6
7use core::num::NonZeroU8;
8use core::time::Duration;
9
10use net_types::ip::{Ipv6, Ipv6Addr};
11use zerocopy::byteorder::network_endian::{U16, U32};
12use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitByteSlice, Unaligned};
13
14use crate::icmp::{IcmpIpExt, IcmpPacket, IcmpPacketRaw, IcmpZeroCode};
15use crate::utils::NonZeroDuration;
16
17/// An ICMPv6 packet with an NDP message.
18#[allow(missing_docs)]
19#[derive(Debug)]
20pub enum NdpPacket<B: SplitByteSlice> {
21    RouterSolicitation(IcmpPacket<Ipv6, B, RouterSolicitation>),
22    RouterAdvertisement(IcmpPacket<Ipv6, B, RouterAdvertisement>),
23    NeighborSolicitation(IcmpPacket<Ipv6, B, NeighborSolicitation>),
24    NeighborAdvertisement(IcmpPacket<Ipv6, B, NeighborAdvertisement>),
25    Redirect(IcmpPacket<Ipv6, B, Redirect>),
26}
27
28/// A raw ICMPv6 packet with an NDP message.
29#[allow(missing_docs)]
30#[derive(Debug)]
31pub enum NdpPacketRaw<B: SplitByteSlice> {
32    RouterSolicitation(IcmpPacketRaw<Ipv6, B, RouterSolicitation>),
33    RouterAdvertisement(IcmpPacketRaw<Ipv6, B, RouterAdvertisement>),
34    NeighborSolicitation(IcmpPacketRaw<Ipv6, B, NeighborSolicitation>),
35    NeighborAdvertisement(IcmpPacketRaw<Ipv6, B, NeighborAdvertisement>),
36    Redirect(IcmpPacketRaw<Ipv6, B, Redirect>),
37}
38
39/// A non-zero lifetime conveyed through NDP.
40#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
41pub enum NonZeroNdpLifetime {
42    /// A finite lifetime greater than zero.
43    ///
44    /// Note that the finite lifetime is not statically guaranteed to be less
45    /// than the infinite value representation of a field. E.g. for Prefix
46    /// Information option lifetime 32-bit fields, infinity is represented as
47    /// all 1s but it is possible for this variant to hold a value representing
48    /// X seconds where X is >= 2^32.
49    Finite(NonZeroDuration),
50
51    /// An infinite lifetime.
52    Infinite,
53}
54
55impl NonZeroNdpLifetime {
56    /// Returns a `Some(NonZeroNdpLifetime)` if the passed lifetime is non-zero;
57    /// otherwise `None`.
58    pub fn from_u32_with_infinite(lifetime: u32) -> Option<NonZeroNdpLifetime> {
59        // Per RFC 4861 section 4.6.2,
60        //
61        //   Valid Lifetime
62        //                  32-bit unsigned integer.  The length of time in
63        //                  seconds (relative to the time the packet is sent)
64        //                  that the prefix is valid for the purpose of on-link
65        //                  determination.  A value of all one bits
66        //                  (0xffffffff) represents infinity.  The Valid
67        //                  Lifetime is also used by [ADDRCONF].
68        //
69        //   Preferred Lifetime
70        //                  32-bit unsigned integer.  The length of time in
71        //                  seconds (relative to the time the packet is sent)
72        //                  that addresses generated from the prefix via
73        //                  stateless address autoconfiguration remain
74        //                  preferred [ADDRCONF].  A value of all one bits
75        //                  (0xffffffff) represents infinity.  See [ADDRCONF].
76        match lifetime {
77            u32::MAX => Some(NonZeroNdpLifetime::Infinite),
78            finite => NonZeroDuration::new(Duration::from_secs(finite.into()))
79                .map(NonZeroNdpLifetime::Finite),
80        }
81    }
82
83    /// Returns the minimum finite duration.
84    pub fn min_finite_duration(self, other: NonZeroDuration) -> NonZeroDuration {
85        match self {
86            NonZeroNdpLifetime::Finite(lifetime) => core::cmp::min(lifetime, other),
87            NonZeroNdpLifetime::Infinite => other,
88        }
89    }
90}
91
92/// A records parser for NDP options.
93///
94/// See [`Options`] for more details.
95///
96/// [`Options`]: packet::records::options::Options
97pub type Options<B> = packet::records::options::Options<B, options::NdpOptionsImpl>;
98
99/// A builder for a sequence of NDP options.
100///
101/// See [`OptionSequenceBuilder`] for more details.
102///
103/// [`OptionSequenceBuilder`]: packet::records::options::OptionSequenceBuilder
104pub type OptionSequenceBuilder<'a, I> =
105    packet::records::options::OptionSequenceBuilder<options::NdpOptionBuilder<'a>, I>;
106
107/// An NDP Router Solicitation.
108#[derive(
109    Copy,
110    Clone,
111    Default,
112    Debug,
113    KnownLayout,
114    FromBytes,
115    IntoBytes,
116    Immutable,
117    Unaligned,
118    PartialEq,
119    Eq,
120)]
121#[repr(C)]
122pub struct RouterSolicitation {
123    _reserved: [u8; 4],
124}
125
126impl_icmp_message!(Ipv6, RouterSolicitation, RouterSolicitation, IcmpZeroCode, Options<B>);
127
128/// The preference for a route as defined by [RFC 4191 section 2.1].
129///
130/// [RFC 4191 section 2.1]: https://datatracker.ietf.org/doc/html/rfc4191#section-2.1
131#[allow(missing_docs)]
132#[derive(Copy, Clone, Debug, PartialEq, Eq)]
133pub enum RoutePreference {
134    // We don't want to store invalid states like Reserved, as this MUST NOT be sent nor processed.
135    // From RFC 4191 section 2.1:
136    //   10      Reserved - MUST NOT be sent
137    //   ...
138    //   If the Reserved (10) value is received, the Route Information Option MUST be ignored.
139    High,
140    Medium,
141    Low,
142}
143
144impl Default for RoutePreference {
145    fn default() -> RoutePreference {
146        // As per RFC 4191 section 2.1,
147        //
148        //   Preference values are encoded as a two-bit signed integer, as
149        //   follows:
150        //
151        //      01      High
152        //      00      Medium (default)
153        //      11      Low
154        //      10      Reserved - MUST NOT be sent
155        RoutePreference::Medium
156    }
157}
158
159impl From<RoutePreference> for u8 {
160    fn from(v: RoutePreference) -> u8 {
161        // As per RFC 4191 section 2.1,
162        //
163        //   Preference values are encoded as a two-bit signed integer, as
164        //   follows:
165        //
166        //      01      High
167        //      00      Medium (default)
168        //      11      Low
169        //      10      Reserved - MUST NOT be sent
170        match v {
171            RoutePreference::High => 0b01,
172            RoutePreference::Medium => 0b00,
173            RoutePreference::Low => 0b11,
174        }
175    }
176}
177
178impl TryFrom<u8> for RoutePreference {
179    type Error = ();
180
181    fn try_from(v: u8) -> Result<Self, Self::Error> {
182        // As per RFC 4191 section 2.1,
183        //
184        //   Preference values are encoded as a two-bit signed integer, as
185        //   follows:
186        //
187        //      01      High
188        //      00      Medium (default)
189        //      11      Low
190        //      10      Reserved - MUST NOT be sent
191        match v {
192            0b01 => Ok(RoutePreference::High),
193            0b00 => Ok(RoutePreference::Medium),
194            0b11 => Ok(RoutePreference::Low),
195            _ => Err(()),
196        }
197    }
198}
199
200/// An NDP Router Advertisement.
201#[derive(
202    Copy, Clone, Debug, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq, Eq,
203)]
204#[repr(C)]
205pub struct RouterAdvertisement {
206    current_hop_limit: u8,
207    configuration_mo: u8,
208    router_lifetime: U16,
209    reachable_time: U32,
210    retransmit_timer: U32,
211}
212
213impl_icmp_message!(Ipv6, RouterAdvertisement, RouterAdvertisement, IcmpZeroCode, Options<B>);
214
215impl RouterAdvertisement {
216    /// Managed address configuration flag.
217    ///
218    /// When set, it indicates that addresses are available via Dynamic Host Configuration Protocol
219    /// (DHCPv6).
220    ///
221    /// If set, the "Pther configuration" flag is redundant and can be ignored because DHCPv6 will
222    /// return all available configuration information.
223    const MANAGED_FLAG: u8 = 0x80;
224
225    /// Other configuration flag.
226    ///
227    /// When set, it indicates that other configuration information is available via DHCPv6.
228    /// Examples of such information are DNS-related information or information on other servers
229    /// within the network.
230    const OTHER_CONFIGURATION_FLAG: u8 = 0x40;
231
232    // As per RFC 4191 section 2.2,
233    //
234    //      0                   1                   2                   3
235    //      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
236    //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
237    //     |     Type      |     Code      |          Checksum             |
238    //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
239    //     | Cur Hop Limit |M|O|H|Prf|Resvd|       Router Lifetime         |
240    //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
241    //     |                         Reachable Time                        |
242    //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
243    //     |                          Retrans Timer                        |
244    //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
245    //
246    //  Fields:
247    //
248    //   Prf (Default Router Preference)
249    //            2-bit signed integer.  Indicates whether to prefer this
250    //            router over other default routers.  If the Router Lifetime
251    //            is zero, the preference value MUST be set to (00) by the
252    //            sender and MUST be ignored by the receiver.  If the Reserved
253    //            (10) value is received, the receiver MUST treat the value as
254    //            if it were (00).
255    const DEFAULT_ROUTER_PREFERENCE_SHIFT: u8 = 3;
256    const DEFAULT_ROUTER_PREFERENCE_MASK: u8 = 0b11 << Self::DEFAULT_ROUTER_PREFERENCE_SHIFT;
257
258    /// Creates a new Router Advertisement with the specified field values.
259    ///
260    /// Equivalent to calling `with_prf` with a default preference value.
261    pub fn new(
262        current_hop_limit: u8,
263        managed_flag: bool,
264        other_config_flag: bool,
265        router_lifetime: u16,
266        reachable_time: u32,
267        retransmit_timer: u32,
268    ) -> Self {
269        Self::with_prf(
270            current_hop_limit,
271            managed_flag,
272            other_config_flag,
273            RoutePreference::default(),
274            router_lifetime,
275            reachable_time,
276            retransmit_timer,
277        )
278    }
279
280    /// Creates a new Router Advertisement with the specified field values.
281    pub fn with_prf(
282        current_hop_limit: u8,
283        managed_flag: bool,
284        other_config_flag: bool,
285        preference: RoutePreference,
286        router_lifetime: u16,
287        reachable_time: u32,
288        retransmit_timer: u32,
289    ) -> Self {
290        let mut configuration_mo = 0;
291
292        if managed_flag {
293            configuration_mo |= Self::MANAGED_FLAG;
294        }
295
296        if other_config_flag {
297            configuration_mo |= Self::OTHER_CONFIGURATION_FLAG;
298        }
299
300        configuration_mo |= (u8::from(preference) << Self::DEFAULT_ROUTER_PREFERENCE_SHIFT)
301            & Self::DEFAULT_ROUTER_PREFERENCE_MASK;
302
303        Self {
304            current_hop_limit,
305            configuration_mo,
306            router_lifetime: U16::new(router_lifetime),
307            reachable_time: U32::new(reachable_time),
308            retransmit_timer: U32::new(retransmit_timer),
309        }
310    }
311
312    /// Returns the current hop limit field.
313    ///
314    /// A value of `None` means unspecified by the source of the Router Advertisement.
315    pub fn current_hop_limit(&self) -> Option<NonZeroU8> {
316        NonZeroU8::new(self.current_hop_limit)
317    }
318
319    /// Returns the router lifetime.
320    ///
321    /// A value of `None` indicates that the router is not a default router and SHOULD
322    /// NOT appear in the default router list.
323    pub fn router_lifetime(&self) -> Option<NonZeroDuration> {
324        // As per RFC 4861 section 4.2, the Router Lifetime field is held in units
325        // of seconds.
326        NonZeroDuration::new(Duration::from_secs(self.router_lifetime.get().into()))
327    }
328
329    /// Returns the reachable time.
330    ///
331    /// A value of `None` means unspecified by the source of the Router Advertisement.
332    pub fn reachable_time(&self) -> Option<NonZeroDuration> {
333        // As per RFC 4861 section 4.2, the Reachable Time field is held in units
334        // of milliseconds.
335        NonZeroDuration::new(Duration::from_millis(self.reachable_time.get().into()))
336    }
337
338    /// Returns the retransmit timer.
339    ///
340    /// A value of `None` means unspecified by the source of the Router Advertisement.
341    pub fn retransmit_timer(&self) -> Option<NonZeroDuration> {
342        // As per RFC 4861 section 4.2, the Retransmit Timer field is held in units
343        // of milliseconds
344        NonZeroDuration::new(Duration::from_millis(self.retransmit_timer.get().into()))
345    }
346}
347
348/// An NDP Neighbor Solicitation.
349#[derive(
350    Copy, Clone, Debug, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq, Eq,
351)]
352#[repr(C)]
353pub struct NeighborSolicitation {
354    _reserved: [u8; 4],
355    target_address: Ipv6Addr,
356}
357
358impl_icmp_message!(Ipv6, NeighborSolicitation, NeighborSolicitation, IcmpZeroCode, Options<B>);
359
360impl NeighborSolicitation {
361    /// Creates a new neighbor solicitation message with the provided
362    /// `target_address`.
363    pub fn new(target_address: Ipv6Addr) -> Self {
364        Self { _reserved: [0; 4], target_address }
365    }
366
367    /// Get the target address in neighbor solicitation message.
368    pub fn target_address(&self) -> &Ipv6Addr {
369        &self.target_address
370    }
371}
372
373/// An NDP Neighbor Advertisement.
374#[derive(
375    Copy, Clone, Debug, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq, Eq,
376)]
377#[repr(C)]
378pub struct NeighborAdvertisement {
379    flags_rso: u8,
380    _reserved: [u8; 3],
381    target_address: Ipv6Addr,
382}
383
384impl_icmp_message!(Ipv6, NeighborAdvertisement, NeighborAdvertisement, IcmpZeroCode, Options<B>);
385
386impl NeighborAdvertisement {
387    /// Router flag.
388    ///
389    /// When set, the R-bit indicates that the sender is a router. The R-bit is
390    /// used by Neighbor Unreachability Detection to detect a router that
391    /// changes to a host.
392    const FLAG_ROUTER: u8 = 0x80;
393
394    /// Solicited flag.
395    ///
396    /// When set, the S-bit indicates that the advertisement was sent in
397    /// response to a Neighbor Solicitation from the Destination address. The
398    /// S-bit is used as a reachability confirmation for Neighbor Unreachability
399    /// Detection.  It MUST NOT be set in multicast advertisements or in
400    /// unsolicited unicast advertisements.
401    const FLAG_SOLICITED: u8 = 0x40;
402
403    /// Override flag.
404    ///
405    /// When set, the O-bit indicates that the advertisement should override an
406    /// existing cache entry and update the cached link-layer address. When it
407    /// is not set the advertisement will not update a cached link-layer address
408    /// though it will update an existing Neighbor Cache entry for which no
409    /// link-layer address is known.  It SHOULD NOT be set in solicited
410    /// advertisements for anycast addresses and in solicited proxy
411    /// advertisements. It SHOULD be set in other solicited advertisements and
412    /// in unsolicited advertisements.
413    const FLAG_OVERRIDE: u8 = 0x20;
414
415    /// Creates a new neighbor advertisement message with the provided
416    /// `router_flag`, `solicited_flag`, `override_flag` and `target_address`.
417    pub fn new(
418        router_flag: bool,
419        solicited_flag: bool,
420        override_flag: bool,
421        target_address: Ipv6Addr,
422    ) -> Self {
423        let mut flags_rso = 0;
424
425        if router_flag {
426            flags_rso |= Self::FLAG_ROUTER;
427        }
428
429        if solicited_flag {
430            flags_rso |= Self::FLAG_SOLICITED;
431        }
432
433        if override_flag {
434            flags_rso |= Self::FLAG_OVERRIDE;
435        }
436
437        Self { flags_rso, _reserved: [0; 3], target_address }
438    }
439
440    /// Returns the target_address of an NA message.
441    pub fn target_address(&self) -> &Ipv6Addr {
442        &self.target_address
443    }
444
445    /// Returns the router flag.
446    pub fn router_flag(&self) -> bool {
447        (self.flags_rso & Self::FLAG_ROUTER) != 0
448    }
449
450    /// Returns the solicited flag.
451    pub fn solicited_flag(&self) -> bool {
452        (self.flags_rso & Self::FLAG_SOLICITED) != 0
453    }
454
455    /// Returns the override flag.
456    pub fn override_flag(&self) -> bool {
457        (self.flags_rso & Self::FLAG_OVERRIDE) != 0
458    }
459}
460
461/// An ICMPv6 Redirect Message.
462#[derive(
463    Copy, Clone, Debug, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq, Eq,
464)]
465#[repr(C)]
466pub struct Redirect {
467    _reserved: [u8; 4],
468    target_address: Ipv6Addr,
469    destination_address: Ipv6Addr,
470}
471
472impl_icmp_message!(Ipv6, Redirect, Redirect, IcmpZeroCode, Options<B>);
473
474/// Parsing and serialization of NDP options.
475pub mod options {
476    use core::num::NonZeroUsize;
477    use core::time::Duration;
478
479    use byteorder::{ByteOrder, NetworkEndian};
480    use net_types::ip::{IpAddress as _, Ipv6Addr, Subnet, SubnetError};
481    use net_types::UnicastAddress;
482    use packet::records::options::{
483        LengthEncoding, OptionBuilder, OptionLayout, OptionParseErr, OptionParseLayout, OptionsImpl,
484    };
485    use packet::BufferView as _;
486    use zerocopy::byteorder::network_endian::U32;
487    use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, Unaligned};
488
489    use super::NonZeroNdpLifetime;
490    use crate::utils::NonZeroDuration;
491
492    /// A `u32` value representing an infinite lifetime for various NDP options' lifetime fields.
493    pub const INFINITE_LIFETIME_SECONDS: u32 = u32::MAX;
494
495    /// A value representing an infinite lifetime for various NDP options'
496    /// lifetime fields.
497    pub const INFINITE_LIFETIME: NonZeroDuration =
498        NonZeroDuration::from_secs(INFINITE_LIFETIME_SECONDS as u64).unwrap();
499
500    /// The number of reserved bytes immediately following the kind and length
501    /// bytes in a Redirected Header option.
502    ///
503    /// See [RFC 4861 section 4.6.3] for more information.
504    ///
505    /// [RFC 4861 section 4.6.3]: https://tools.ietf.org/html/rfc4861#section-4.6.3
506    const REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH: usize = 6;
507
508    /// The length of an NDP MTU option, excluding the first 2 bytes (kind and length bytes).
509    ///
510    /// See [RFC 4861 section 4.6.3] for more information.
511    ///
512    /// [RFC 4861 section 4.6.3]: https://tools.ietf.org/html/rfc4861#section-4.6.3
513    const MTU_OPTION_LENGTH: usize = 6;
514
515    /// The number of reserved bytes immediately following the kind and length
516    /// bytes in an MTU option.
517    ///
518    /// See [RFC 4861 section 4.6.4] for more information.
519    ///
520    /// [RFC 4861 section 4.6.4]: https://tools.ietf.org/html/rfc4861#section-4.6.4
521    const MTU_OPTION_RESERVED_BYTES_LENGTH: usize = 2;
522
523    /// Minimum number of bytes in a Nonce option, excluding the kind and length bytes.
524    ///
525    /// See [RFC 3971 section 5.3.2] for more information.
526    ///
527    /// [RFC 3971 section 5.3.2]: https://tools.ietf.org/html/rfc3971#section-5.3.2
528    pub const MIN_NONCE_LENGTH: usize = 6;
529
530    /// Minimum number of bytes in a Recursive DNS Server option, excluding the
531    /// kind and length bytes.
532    ///
533    /// This guarantees that a valid Recurisve DNS Server option holds at least
534    /// 1 address.
535    ///
536    /// See [RFC 8106 section 5.3.1] for more information.
537    ///
538    /// [RFC 8106 section 5.3.1]: https://tools.ietf.org/html/rfc8106#section-5.1
539    const MIN_RECURSIVE_DNS_SERVER_OPTION_LENGTH: usize = 22;
540
541    /// The number of reserved bytes immediately following the kind and length
542    /// bytes in a Recursive DNS Server option.
543    ///
544    /// See [RFC 8106 section 5.3.1] for more information.
545    ///
546    /// [RFC 8106 section 5.3.1]: https://tools.ietf.org/html/rfc8106#section-5.1
547    const RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH: usize = 2;
548
549    /// The number of reserved bits immediately following (on the right of) the preference.
550    ///
551    /// See [RFC 4191 section 2.3] for more information.
552    ///
553    /// [RFC 4191 section 2.3]: https://tools.ietf.org/html/rfc4191#section-2.3
554    const ROUTE_INFORMATION_PREFERENCE_RESERVED_BITS_RIGHT: u8 = 3;
555
556    /// A mask to keep only the valid bits for the preference in the Route Information option.
557    ///
558    /// See [RFC 4191 section 2.3] for more information.
559    ///
560    /// [RFC 4191 section 2.3]: https://tools.ietf.org/html/rfc4191#section-2.3
561    const ROUTE_INFORMATION_PREFERENCE_MASK: u8 = 0x18;
562
563    /// The length of an NDP option is specified in units of 8 octets.
564    ///
565    /// See [RFC 4861 section 4.6] for more information.
566    ///
567    /// [RFC 4861 section 4.6]: https://tools.ietf.org/html/rfc4861#section-4.6
568    const OPTION_BYTES_PER_LENGTH_UNIT: usize = 8;
569
570    /// Recursive DNS Server that is advertised by a router in Router Advertisements.
571    ///
572    /// See [RFC 8106 section 5.1].
573    ///
574    /// [RFC 8106 section 5.1]: https://tools.ietf.org/html/rfc8106#section-5.1
575    #[derive(Debug, PartialEq, Eq, Clone)]
576    pub struct RecursiveDnsServer<'a> {
577        lifetime: u32,
578        addresses: &'a [Ipv6Addr],
579    }
580
581    impl<'a> RecursiveDnsServer<'a> {
582        /// The `u32` value representing an infinite lifetime for a RecursiveDnsServer option.
583        pub const INFINITE_LIFETIME: u32 = INFINITE_LIFETIME_SECONDS;
584
585        /// Returns a new `RecursiveDnsServer`.
586        pub fn new(lifetime: u32, addresses: &'a [Ipv6Addr]) -> RecursiveDnsServer<'a> {
587            RecursiveDnsServer { lifetime, addresses }
588        }
589
590        /// Returns the length of time (relative to the time the packet is sent) that
591        /// the DNS servers are valid for name resolution.
592        ///
593        /// A value of [`INFINITE_LIFETIME`] represents infinity; a value of `None`
594        /// means that the servers MUST no longer be used.
595        pub fn lifetime(&self) -> Option<NonZeroDuration> {
596            NonZeroDuration::new(Duration::from_secs(self.lifetime.into()))
597        }
598
599        /// Returns the recursive DNS server addresses.
600        pub fn iter_addresses(&self) -> &'a [Ipv6Addr] {
601            self.addresses
602        }
603
604        /// Parses a Recursive DNS Server option from raw bytes (starting immediately
605        /// after the kind and length bytes).
606        pub fn parse(data: &'a [u8]) -> Result<Self, OptionParseErr> {
607            if data.len() < MIN_RECURSIVE_DNS_SERVER_OPTION_LENGTH {
608                return Err(OptionParseErr);
609            }
610
611            // Skip the reserved bytes which immediately follow the kind and length
612            // bytes.
613            let (_, data) = data.split_at(RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH);
614
615            // As per RFC 8106 section 5.1, the 32 bit lifetime field immediately
616            // follows the reserved field.
617            let (lifetime, data) = Ref::<_, U32>::from_prefix(data).map_err(|_| OptionParseErr)?;
618
619            // As per RFC 8106 section 5.1, the list of addresses immediately
620            // follows the lifetime field.
621            let addresses = Ref::into_ref(
622                Ref::<_, [Ipv6Addr]>::from_bytes(data)
623                    .map_err(Into::into)
624                    .map_err(|_: zerocopy::SizeError<_, _>| OptionParseErr)?,
625            );
626
627            // As per RFC 8106 section 5.3.1, the addresses should all be unicast.
628            if !addresses.iter().all(UnicastAddress::is_unicast) {
629                return Err(OptionParseErr);
630            }
631
632            Ok(Self::new(lifetime.get(), addresses))
633        }
634    }
635
636    /// The first 6 bytes of the Route Information option following the Type and
637    /// Length fields.
638    ///
639    /// As per [RFC 4191 section 2.3],
640    ///
641    /// ```text
642    ///   Route Information Option
643    ///
644    ///      0                   1                   2                   3
645    ///       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
646    ///      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
647    ///      |     Type      |    Length     | Prefix Length |Resvd|Prf|Resvd|
648    ///      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
649    ///      |                        Route Lifetime                         |
650    ///      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
651    ///      |                   Prefix (Variable Length)                    |
652    ///      .                                                               .
653    ///      .                                                               .
654    ///      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
655    /// ```
656    ///
657    /// [RFC 4191 section 2.3]: https://datatracker.ietf.org/doc/html/rfc4191#section-2.3
658    #[derive(KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
659    #[repr(C)]
660    struct RouteInformationHeader {
661        prefix_length: u8,
662        flags: u8,
663        route_lifetime: U32,
664    }
665
666    impl RouteInformationHeader {
667        // As per RFC 4191 section 2.3,
668        //
669        //   Route Information Option
670        //
671        //      0                   1                   2                   3
672        //       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
673        //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
674        //      |     Type      |    Length     | Prefix Length |Resvd|Prf|Resvd|
675        //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
676        //      |                        Route Lifetime                         |
677        //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
678        //      |                   Prefix (Variable Length)                    |
679        //      .                                                               .
680        //      .                                                               .
681        //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
682        const PREFERENCE_SHIFT: u8 = 3;
683        const PREFERENCE_MASK: u8 = 0b11 << Self::PREFERENCE_SHIFT;
684
685        fn set_preference(&mut self, preference: super::RoutePreference) {
686            let preference: u8 = preference.into();
687
688            self.flags &= !Self::PREFERENCE_MASK;
689            self.flags |= (preference << Self::PREFERENCE_SHIFT) & Self::PREFERENCE_MASK;
690        }
691    }
692
693    /// Builder for a Route Information option.
694    ///
695    /// See [RFC 4191 section 2.3].
696    ///
697    /// [RFC 4191 section 2.3]: https://datatracker.ietf.org/doc/html/rfc4191#section-2.3
698    #[derive(Debug, PartialEq, Eq)]
699    pub struct RouteInformation {
700        prefix: Subnet<Ipv6Addr>,
701        route_lifetime_seconds: u32,
702        preference: super::RoutePreference,
703    }
704
705    impl RouteInformation {
706        /// Returns a new Route Information option builder.
707        pub fn new(
708            prefix: Subnet<Ipv6Addr>,
709            route_lifetime_seconds: u32,
710            preference: super::RoutePreference,
711        ) -> Self {
712            Self { prefix, route_lifetime_seconds, preference }
713        }
714
715        /// The prefix represented as a [`Subnet`].
716        pub fn prefix(&self) -> &Subnet<Ipv6Addr> {
717            &self.prefix
718        }
719
720        /// The preference of the route.
721        pub fn preference(&self) -> super::RoutePreference {
722            self.preference
723        }
724
725        /// Returns the lifetime of the route.
726        pub fn route_lifetime(&self) -> Option<NonZeroNdpLifetime> {
727            NonZeroNdpLifetime::from_u32_with_infinite(self.route_lifetime_seconds)
728        }
729
730        fn prefix_bytes_len(&self) -> usize {
731            let RouteInformation { prefix, route_lifetime_seconds: _, preference: _ } = self;
732
733            let prefix_length = prefix.prefix();
734            // As per RFC 4191 section 2.3,
735            //
736            //    Length     8-bit unsigned integer.  The length of the option
737            //               (including the Type and Length fields) in units of 8
738            //               octets.  The Length field is 1, 2, or 3 depending on the
739            //               Prefix Length.  If Prefix Length is greater than 64, then
740            //               Length must be 3.  If Prefix Length is greater than 0,
741            //               then Length must be 2 or 3.  If Prefix Length is zero,
742            //               then Length must be 1, 2, or 3.
743            //
744            // This function only returns the length of the prefix bytes in units of
745            // 1 octet.
746            if prefix_length == 0 {
747                0
748            } else if prefix_length <= 64 {
749                core::mem::size_of::<Ipv6Addr>() / 2
750            } else {
751                core::mem::size_of::<Ipv6Addr>()
752            }
753        }
754
755        fn serialized_len(&self) -> usize {
756            core::mem::size_of::<RouteInformationHeader>() + self.prefix_bytes_len()
757        }
758
759        fn serialize(&self, buffer: &mut [u8]) {
760            let (mut hdr, buffer) = Ref::<_, RouteInformationHeader>::from_prefix(buffer)
761                .expect("expected buffer to hold enough bytes for serialization");
762
763            let prefix_bytes_len = self.prefix_bytes_len();
764            let RouteInformation { prefix, route_lifetime_seconds, preference } = self;
765
766            hdr.prefix_length = prefix.prefix();
767            hdr.set_preference(*preference);
768            hdr.route_lifetime.set(*route_lifetime_seconds);
769            buffer[..prefix_bytes_len]
770                .copy_from_slice(&prefix.network().bytes()[..prefix_bytes_len])
771        }
772    }
773
774    /// Number of bytes in a Prefix Information option, excluding the kind
775    /// and length bytes.
776    ///
777    /// See [RFC 4861 section 4.6.2] for more information.
778    ///
779    /// [RFC 4861 section 4.6.2]: https://tools.ietf.org/html/rfc4861#section-4.6.2
780    const PREFIX_INFORMATION_OPTION_LENGTH: usize = 30;
781
782    /// Prefix information that is advertised by a router in Router Advertisements.
783    ///
784    /// See [RFC 4861 section 4.6.2].
785    ///
786    /// [RFC 4861 section 4.6.2]: https://tools.ietf.org/html/rfc4861#section-4.6.2
787    #[derive(
788        Debug, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq, Eq, Clone,
789    )]
790    #[repr(C)]
791    pub struct PrefixInformation {
792        prefix_length: u8,
793        flags_la: u8,
794        valid_lifetime: U32,
795        preferred_lifetime: U32,
796        _reserved: [u8; 4],
797        prefix: Ipv6Addr,
798    }
799
800    impl PrefixInformation {
801        /// The on-link flag within the 4th byte in the prefix information buffer.
802        ///
803        /// See [RFC 4861 section 4.6.2] for more information.
804        ///
805        /// [RFC 4861 section 4.6.2]: https://tools.ietf.org/html/rfc4861#section-4.6.2
806        const ON_LINK_FLAG: u8 = 0x80;
807
808        /// The autonomous address configuration flag within the 4th byte in the
809        /// prefix information buffer
810        ///
811        /// See [RFC 4861 section 4.6.2] for more information.
812        ///
813        /// [RFC 4861 section 4.6.2]: https://tools.ietf.org/html/rfc4861#section-4.6.2
814        const AUTONOMOUS_ADDRESS_CONFIGURATION_FLAG: u8 = 0x40;
815
816        /// Create a new `PrefixInformation`.
817        pub fn new(
818            prefix_length: u8,
819            on_link_flag: bool,
820            autonomous_address_configuration_flag: bool,
821            valid_lifetime: u32,
822            preferred_lifetime: u32,
823            prefix: Ipv6Addr,
824        ) -> Self {
825            let mut flags_la = 0;
826
827            if on_link_flag {
828                flags_la |= Self::ON_LINK_FLAG;
829            }
830
831            if autonomous_address_configuration_flag {
832                flags_la |= Self::AUTONOMOUS_ADDRESS_CONFIGURATION_FLAG;
833            }
834
835            Self {
836                prefix_length,
837                flags_la,
838                valid_lifetime: U32::new(valid_lifetime),
839                preferred_lifetime: U32::new(preferred_lifetime),
840                _reserved: [0; 4],
841                prefix,
842            }
843        }
844
845        /// The number of leading bits in the prefix that are valid.
846        pub fn prefix_length(&self) -> u8 {
847            self.prefix_length
848        }
849
850        /// Is this prefix on the link?
851        ///
852        /// Returns `true` if the prefix is on-link. `false` means that
853        /// no statement is made about on or off-link properties of the
854        /// prefix; nodes MUST NOT conclude that an address derived
855        /// from this prefix is off-link if `false`.
856        pub fn on_link_flag(&self) -> bool {
857            (self.flags_la & Self::ON_LINK_FLAG) != 0
858        }
859
860        /// Can this prefix be used for stateless address configuration?
861        pub fn autonomous_address_configuration_flag(&self) -> bool {
862            (self.flags_la & Self::AUTONOMOUS_ADDRESS_CONFIGURATION_FLAG) != 0
863        }
864
865        /// Get the length of time (relative to the time the packet is sent) that
866        /// the prefix is valid for the purpose of on-link determination and SLAAC.
867        ///
868        /// `None` indicates that the prefix has no valid lifetime and should
869        /// not be considered valid.
870        pub fn valid_lifetime(&self) -> Option<NonZeroNdpLifetime> {
871            NonZeroNdpLifetime::from_u32_with_infinite(self.valid_lifetime.get())
872        }
873
874        /// Get the length of time (relative to the time the packet is sent) that
875        /// addresses generated from the prefix via SLAAC remains preferred.
876        ///
877        /// `None` indicates that the prefix has no preferred lifetime and
878        /// should not be considered preferred.
879        pub fn preferred_lifetime(&self) -> Option<NonZeroNdpLifetime> {
880            NonZeroNdpLifetime::from_u32_with_infinite(self.preferred_lifetime.get())
881        }
882
883        /// An IPv6 address or a prefix of an IPv6 address.
884        ///
885        /// The number of valid leading bits in this prefix is available
886        /// from [`PrefixInformation::prefix_length`];
887        // TODO(https://fxbug.dev/42173363): Consider merging prefix and prefix_length and return a
888        // Subnet.
889        pub fn prefix(&self) -> &Ipv6Addr {
890            &self.prefix
891        }
892
893        /// Gets the prefix as a [`Subnet`].
894        pub fn subnet(&self) -> Result<Subnet<Ipv6Addr>, SubnetError> {
895            Subnet::new(self.prefix, self.prefix_length)
896        }
897    }
898
899    create_protocol_enum!(
900        /// The types of NDP options that may be found in NDP messages.
901        #[allow(missing_docs)]
902        pub enum NdpOptionType: u8 {
903            SourceLinkLayerAddress, 1, "Source Link-Layer Address";
904            TargetLinkLayerAddress, 2, "Target Link-Layer Address";
905            PrefixInformation, 3, "Prefix Information";
906            RedirectedHeader, 4, "Redirected Header";
907            Mtu, 5, "MTU";
908            Nonce, 14, "Nonce";
909            RouteInformation, 24, "Route Information";
910            RecursiveDnsServer, 25, "Recursive DNS Server";
911        }
912    );
913
914    /// Nonce option used to make sure an advertisement is a fresh response to
915    /// a solicitation sent earlier.
916    ///
917    /// See [RFC 3971 section 5.3.2].
918    ///
919    /// [RFC 3971 section 5.3.2]: https://tools.ietf.org/html/rfc3971#section-5.3.2
920    #[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
921    pub struct NdpNonce<B: SplitByteSlice> {
922        nonce: B,
923    }
924
925    impl<B: SplitByteSlice> NdpNonce<B> {
926        /// The bytes of the nonce.
927        pub fn bytes(&self) -> &[u8] {
928            let Self { nonce } = self;
929            nonce.deref()
930        }
931
932        /// Constructs an `NdpNonce` from a `B: SplitByteSlice`, returning an error
933        /// if the resulting nonce would not have a valid length.
934        pub fn new(value: B) -> Result<Self, InvalidNonceError> {
935            let bytes = value.deref();
936            // As per RFC 3971 section 5.3.2, the length of the random number
937            // must be selected such that the length of the Nonce option
938            // (including the type and length bytes) is a multiple of 8 octets.
939            let nonce_option_length_bytes = bytes.len() + 2;
940            if nonce_option_length_bytes % 8 != 0 {
941                return Err(InvalidNonceError::ResultsInNonMultipleOf8);
942            }
943
944            let nonce_option_length_in_groups_of_8_bytes = nonce_option_length_bytes / 8;
945
946            // The nonce options's length (in terms of groups of 8 octets) would
947            // be too large to fit in a `u8`.
948            match u8::try_from(nonce_option_length_in_groups_of_8_bytes) {
949                Ok(_) => (),
950                Err(_) => return Err(InvalidNonceError::TooLong),
951            };
952
953            Ok(Self { nonce: value })
954        }
955    }
956
957    impl<B: SplitByteSlice> AsRef<[u8]> for NdpNonce<B> {
958        fn as_ref(&self) -> &[u8] {
959            self.bytes()
960        }
961    }
962
963    // Provide a `From` implementation for `[u8; MIN_NONCE_LENGTH]` since this
964    // is a common conversion and is convenient to make infallible.
965    impl<'a> From<&'a [u8; MIN_NONCE_LENGTH]> for NdpNonce<&'a [u8]> {
966        fn from(value: &'a [u8; MIN_NONCE_LENGTH]) -> Self {
967            Self { nonce: &value[..] }
968        }
969    }
970
971    /// Errors that may occur when constructing a Nonce option.
972    #[derive(Debug, PartialEq, Eq, Copy, Clone)]
973    pub enum InvalidNonceError {
974        /// The nonce's length is such that the nonce option's length would not
975        /// be a multiple of 8 octets.
976        ResultsInNonMultipleOf8,
977        /// The nonce is too long.
978        TooLong,
979    }
980
981    /// NDP options that may be found in NDP messages.
982    #[allow(missing_docs)]
983    #[derive(Debug, PartialEq, Eq)]
984    pub enum NdpOption<'a> {
985        SourceLinkLayerAddress(&'a [u8]),
986        TargetLinkLayerAddress(&'a [u8]),
987        PrefixInformation(&'a PrefixInformation),
988
989        RedirectedHeader { original_packet: &'a [u8] },
990
991        Mtu(u32),
992        Nonce(NdpNonce<&'a [u8]>),
993
994        RecursiveDnsServer(RecursiveDnsServer<'a>),
995        RouteInformation(RouteInformation),
996    }
997
998    impl<'a> NdpOption<'a> {
999        /// Accessor for the `Nonce` case.
1000        pub fn nonce(self) -> Option<NdpNonce<&'a [u8]>> {
1001            match self {
1002                NdpOption::Nonce(nonce) => Some(nonce),
1003                _ => None,
1004            }
1005        }
1006
1007        /// Accessor for the `SourceLinkLayerAddress` case.
1008        pub fn source_link_layer_address(self) -> Option<&'a [u8]> {
1009            match self {
1010                NdpOption::SourceLinkLayerAddress(a) => Some(a),
1011                _ => None,
1012            }
1013        }
1014
1015        /// Accessor for the `TargetLinkLayerAddress` case.
1016        pub fn target_link_layer_address(self) -> Option<&'a [u8]> {
1017            match self {
1018                NdpOption::TargetLinkLayerAddress(a) => Some(a),
1019                _ => None,
1020            }
1021        }
1022    }
1023
1024    /// An implementation of [`OptionsImpl`] for NDP options.
1025    #[derive(Debug)]
1026    pub struct NdpOptionsImpl;
1027
1028    impl<'a> OptionLayout for NdpOptionsImpl {
1029        type KindLenField = u8;
1030
1031        // For NDP options the length should be multiplied by 8.
1032        const LENGTH_ENCODING: LengthEncoding = LengthEncoding::TypeLengthValue {
1033            option_len_multiplier: NonZeroUsize::new(8).unwrap(),
1034        };
1035    }
1036
1037    impl OptionParseLayout for NdpOptionsImpl {
1038        // TODO(https://fxbug.dev/42129573): Return more verbose logs on parsing errors.
1039        type Error = OptionParseErr;
1040
1041        // NDP options don't have END_OF_OPTIONS or NOP.
1042        const END_OF_OPTIONS: Option<u8> = None;
1043        const NOP: Option<u8> = None;
1044    }
1045
1046    impl OptionsImpl for NdpOptionsImpl {
1047        type Option<'a> = NdpOption<'a>;
1048
1049        fn parse<'a>(
1050            kind: u8,
1051            mut data: &'a [u8],
1052        ) -> Result<Option<NdpOption<'a>>, OptionParseErr> {
1053            let kind = if let Ok(k) = NdpOptionType::try_from(kind) {
1054                k
1055            } else {
1056                return Ok(None);
1057            };
1058
1059            let opt = match kind {
1060                NdpOptionType::SourceLinkLayerAddress => NdpOption::SourceLinkLayerAddress(data),
1061                NdpOptionType::TargetLinkLayerAddress => NdpOption::TargetLinkLayerAddress(data),
1062                NdpOptionType::PrefixInformation => {
1063                    let data = Ref::<_, PrefixInformation>::from_bytes(data)
1064                        .map_err(|_| OptionParseErr)?;
1065                    NdpOption::PrefixInformation(Ref::into_ref(data))
1066                }
1067                NdpOptionType::RedirectedHeader => NdpOption::RedirectedHeader {
1068                    original_packet: &data[REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH..],
1069                },
1070                NdpOptionType::Mtu => NdpOption::Mtu(NetworkEndian::read_u32(
1071                    &data[MTU_OPTION_RESERVED_BYTES_LENGTH..],
1072                )),
1073                NdpOptionType::Nonce => NdpOption::Nonce(
1074                    NdpNonce::new(data).map_err(|_: InvalidNonceError| OptionParseErr)?,
1075                ),
1076                NdpOptionType::RecursiveDnsServer => {
1077                    NdpOption::RecursiveDnsServer(RecursiveDnsServer::parse(data)?)
1078                }
1079                NdpOptionType::RouteInformation => {
1080                    // RouteInfoFixed represents the part of the RouteInformation option
1081                    // with a known and fixed length. See RFC 4191 section 2.3.
1082                    #[derive(KnownLayout, FromBytes, Immutable, Unaligned)]
1083                    #[repr(C)]
1084                    struct RouteInfoFixed {
1085                        prefix_length: u8,
1086                        preference_raw: u8,
1087                        route_lifetime_seconds: U32,
1088                    }
1089
1090                    let mut buf = &mut data;
1091
1092                    let fixed = buf.take_obj_front::<RouteInfoFixed>().ok_or(OptionParseErr)?;
1093
1094                    // The preference is preceded and followed by two 3-bit reserved fields.
1095                    let preference = super::RoutePreference::try_from(
1096                        (fixed.preference_raw & ROUTE_INFORMATION_PREFERENCE_MASK)
1097                            >> ROUTE_INFORMATION_PREFERENCE_RESERVED_BITS_RIGHT,
1098                    )
1099                    .map_err(|()| OptionParseErr)?;
1100
1101                    // We need to check whether the remaining buffer length storing the prefix is
1102                    // valid.
1103                    // From RFC 4191 section 2.3:
1104                    //   The length of the option (including the Type and Length fields) in units
1105                    //   of 8 octets.  The Length field is 1, 2, or 3 depending on the Prefix
1106                    //   Length.  If Prefix Length is greater than 64, then Length must be 3.  If
1107                    //   Prefix Length is greater than 0, then Length must be 2 or 3.  If Prefix
1108                    //   Length is zero, then Length must be 1, 2, or 3.
1109                    // The RFC refers to the length of the body which is Route Lifetime + Prefix,
1110                    // i.e. the prefix contained in the buffer can have a length from 0 to 2
1111                    // (included) octets i.e. 0 to 16 bytes.
1112                    let buf_len = buf.len();
1113                    if buf_len % OPTION_BYTES_PER_LENGTH_UNIT != 0 {
1114                        return Err(OptionParseErr);
1115                    }
1116                    let length = buf_len / OPTION_BYTES_PER_LENGTH_UNIT;
1117                    match (fixed.prefix_length, length) {
1118                        (65..=128, 2) => {}
1119                        (1..=64, 1 | 2) => {}
1120                        (0, 0 | 1 | 2) => {}
1121                        _ => return Err(OptionParseErr),
1122                    }
1123
1124                    let mut prefix_buf = [0; 16];
1125                    // It is safe to copy because we validated the remaining length of the buffer.
1126                    prefix_buf[..buf_len].copy_from_slice(&buf);
1127                    let prefix = Ipv6Addr::from_bytes(prefix_buf);
1128
1129                    NdpOption::RouteInformation(RouteInformation::new(
1130                        Subnet::new(prefix, fixed.prefix_length).map_err(|_| OptionParseErr)?,
1131                        fixed.route_lifetime_seconds.get(),
1132                        preference,
1133                    ))
1134                }
1135            };
1136
1137            Ok(Some(opt))
1138        }
1139    }
1140
1141    /// Builder for NDP options that may be found in NDP messages.
1142    #[allow(missing_docs)]
1143    #[derive(Debug)]
1144    pub enum NdpOptionBuilder<'a> {
1145        SourceLinkLayerAddress(&'a [u8]),
1146        TargetLinkLayerAddress(&'a [u8]),
1147        PrefixInformation(PrefixInformation),
1148
1149        RedirectedHeader { original_packet: &'a [u8] },
1150
1151        Mtu(u32),
1152        Nonce(NdpNonce<&'a [u8]>),
1153
1154        RouteInformation(RouteInformation),
1155        RecursiveDnsServer(RecursiveDnsServer<'a>),
1156    }
1157
1158    impl<'a> From<&NdpOptionBuilder<'a>> for NdpOptionType {
1159        fn from(v: &NdpOptionBuilder<'a>) -> Self {
1160            match v {
1161                NdpOptionBuilder::SourceLinkLayerAddress(_) => {
1162                    NdpOptionType::SourceLinkLayerAddress
1163                }
1164                NdpOptionBuilder::TargetLinkLayerAddress(_) => {
1165                    NdpOptionType::TargetLinkLayerAddress
1166                }
1167                NdpOptionBuilder::PrefixInformation(_) => NdpOptionType::PrefixInformation,
1168                NdpOptionBuilder::RedirectedHeader { .. } => NdpOptionType::RedirectedHeader,
1169                NdpOptionBuilder::Mtu { .. } => NdpOptionType::Mtu,
1170                NdpOptionBuilder::Nonce(_) => NdpOptionType::Nonce,
1171                NdpOptionBuilder::RouteInformation(_) => NdpOptionType::RouteInformation,
1172                NdpOptionBuilder::RecursiveDnsServer(_) => NdpOptionType::RecursiveDnsServer,
1173            }
1174        }
1175    }
1176
1177    impl<'a> OptionBuilder for NdpOptionBuilder<'a> {
1178        type Layout = NdpOptionsImpl;
1179
1180        fn serialized_len(&self) -> usize {
1181            match self {
1182                NdpOptionBuilder::SourceLinkLayerAddress(data)
1183                | NdpOptionBuilder::TargetLinkLayerAddress(data) => data.len(),
1184                NdpOptionBuilder::PrefixInformation(_) => PREFIX_INFORMATION_OPTION_LENGTH,
1185                NdpOptionBuilder::RedirectedHeader { original_packet } => {
1186                    REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH + original_packet.len()
1187                }
1188                NdpOptionBuilder::Mtu(_) => MTU_OPTION_LENGTH,
1189                NdpOptionBuilder::Nonce(NdpNonce { nonce }) => nonce.len(),
1190                NdpOptionBuilder::RouteInformation(o) => o.serialized_len(),
1191                NdpOptionBuilder::RecursiveDnsServer(RecursiveDnsServer {
1192                    lifetime,
1193                    addresses,
1194                }) => {
1195                    RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH
1196                        + core::mem::size_of_val(lifetime)
1197                        + core::mem::size_of_val(*addresses)
1198                }
1199            }
1200        }
1201
1202        fn option_kind(&self) -> u8 {
1203            NdpOptionType::from(self).into()
1204        }
1205
1206        fn serialize_into(&self, buffer: &mut [u8]) {
1207            match self {
1208                NdpOptionBuilder::SourceLinkLayerAddress(data)
1209                | NdpOptionBuilder::TargetLinkLayerAddress(data) => buffer.copy_from_slice(data),
1210                NdpOptionBuilder::PrefixInformation(pfx_info) => {
1211                    buffer.copy_from_slice(pfx_info.as_bytes());
1212                }
1213                NdpOptionBuilder::RedirectedHeader { original_packet } => {
1214                    // As per RFC 4861 section 4.6.3, the first 6 bytes following the kind and length
1215                    // bytes are reserved so we zero them. The IP header + data field immediately
1216                    // follows.
1217                    let (reserved_bytes, original_packet_bytes) =
1218                        buffer.split_at_mut(REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH);
1219                    reserved_bytes
1220                        .copy_from_slice(&[0; REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH]);
1221                    original_packet_bytes.copy_from_slice(original_packet);
1222                }
1223                NdpOptionBuilder::Mtu(mtu) => {
1224                    // As per RFC 4861 section 4.6.4, the first 2 bytes following the kind and length
1225                    // bytes are reserved so we zero them. The MTU field immediately follows.
1226                    let (reserved_bytes, mtu_bytes) =
1227                        buffer.split_at_mut(MTU_OPTION_RESERVED_BYTES_LENGTH);
1228                    reserved_bytes.copy_from_slice(&[0; MTU_OPTION_RESERVED_BYTES_LENGTH]);
1229                    mtu_bytes.copy_from_slice(U32::new(*mtu).as_bytes());
1230                }
1231                NdpOptionBuilder::Nonce(NdpNonce { nonce }) => {
1232                    buffer.copy_from_slice(nonce);
1233                }
1234                NdpOptionBuilder::RouteInformation(p) => p.serialize(buffer),
1235                NdpOptionBuilder::RecursiveDnsServer(RecursiveDnsServer {
1236                    lifetime,
1237                    addresses,
1238                }) => {
1239                    // As per RFC 8106 section 5.1, the first 2 bytes following the kind and length
1240                    // bytes are reserved so we zero them.
1241                    let (reserved_bytes, buffer) =
1242                        buffer.split_at_mut(RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH);
1243                    reserved_bytes
1244                        .copy_from_slice(&[0; RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH]);
1245
1246                    // As per RFC 8106 section 5.1, the 32 bit lifetime field immediately
1247                    // follows the reserved field, with the list of addresses immediately
1248                    // following the lifetime field.
1249                    let (lifetime_bytes, addresses_bytes) =
1250                        buffer.split_at_mut(core::mem::size_of_val(lifetime));
1251                    lifetime_bytes.copy_from_slice(U32::new(*lifetime).as_bytes());
1252                    addresses_bytes.copy_from_slice(addresses.as_bytes());
1253                }
1254            }
1255        }
1256    }
1257}
1258
1259#[cfg(test)]
1260mod tests {
1261    use byteorder::{ByteOrder, NetworkEndian};
1262    use net_types::ip::{Ip, IpAddress, Subnet};
1263    use packet::serialize::Serializer;
1264    use packet::{InnerPacketBuilder, ParseBuffer};
1265    use test_case::test_case;
1266    use zerocopy::Ref;
1267
1268    use super::*;
1269    use crate::icmp::{IcmpPacketBuilder, IcmpParseArgs};
1270    use crate::ipv6::{Ipv6Header, Ipv6Packet};
1271
1272    #[test]
1273    fn parse_serialize_redirected_header() {
1274        let expected_packet = [1, 2, 3, 4, 5, 6, 7, 8];
1275        let options =
1276            &[options::NdpOptionBuilder::RedirectedHeader { original_packet: &expected_packet }];
1277        let serialized = OptionSequenceBuilder::new(options.iter())
1278            .into_serializer()
1279            .serialize_vec_outer()
1280            .unwrap();
1281        // 8 bytes for the kind, length and reserved byes + the bytes for the packet.
1282        let mut expected = [0; 16];
1283        // The first two bytes are the kind and length bytes, respectively. This is then
1284        // followed by 6 reserved bytes.
1285        //
1286        // NDP options hold the number of bytes in units of 8 bytes.
1287        (&mut expected[..2]).copy_from_slice(&[4, 2]);
1288        (&mut expected[8..]).copy_from_slice(&expected_packet);
1289        assert_eq!(serialized.as_ref(), expected);
1290
1291        let parsed = Options::parse(&expected[..]).unwrap();
1292        let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1293        assert_eq!(parsed.len(), 1);
1294        assert_eq!(
1295            options::NdpOption::RedirectedHeader { original_packet: &expected_packet },
1296            parsed[0]
1297        );
1298    }
1299
1300    #[test]
1301    fn parse_serialize_mtu_option() {
1302        let expected_mtu = 5781;
1303        let options = &[options::NdpOptionBuilder::Mtu(expected_mtu)];
1304        let serialized = OptionSequenceBuilder::new(options.iter())
1305            .into_serializer()
1306            .serialize_vec_outer()
1307            .unwrap();
1308        // An MTU option is exactly 8 bytes.
1309        //
1310        // The first two bytes are the kind and length bytes, respectively. This is then
1311        // followed by 2 reserved bytes.
1312        let mut expected = [5, 1, 0, 0, 0, 0, 0, 0];
1313        NetworkEndian::write_u32(&mut expected[4..], expected_mtu);
1314        assert_eq!(serialized.as_ref(), expected);
1315
1316        let parsed = Options::parse(&expected[..]).unwrap();
1317        let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1318        assert_eq!(parsed.len(), 1);
1319        assert_eq!(options::NdpOption::Mtu(expected_mtu), parsed[0]);
1320    }
1321
1322    #[test_case(
1323        options::MIN_NONCE_LENGTH - 1 =>
1324            matches Err(options::InvalidNonceError::ResultsInNonMultipleOf8);
1325        "resulting nonce option length must be multiple of 8")]
1326    #[test_case(
1327        options::MIN_NONCE_LENGTH => matches Ok(_);
1328        "MIN_NONCE_LENGTH must validate successfully")]
1329    #[test_case(
1330        usize::from(u8::MAX) * 8 - 2 => matches Ok(_);
1331        "maximum possible nonce length must validate successfully")]
1332    #[test_case(
1333        usize::from(u8::MAX) * 8 - 2 + 8 =>
1334            matches Err(options::InvalidNonceError::TooLong);
1335        "nonce option's length must fit in u8")]
1336    fn nonce_length_validation(
1337        length: usize,
1338    ) -> Result<options::NdpNonce<&'static [u8]>, options::InvalidNonceError> {
1339        const LEN: usize = (u8::MAX as usize + 1) * 8;
1340        const BYTES: [u8; LEN] = [0u8; LEN];
1341        options::NdpNonce::new(&BYTES[..length])
1342    }
1343
1344    #[test]
1345    fn parse_serialize_nonce_option() {
1346        let expected_nonce: [u8; 6] = [1, 2, 3, 4, 5, 6];
1347        let nonce = options::NdpNonce::new(&expected_nonce[..]).expect("should be valid nonce");
1348        let options = &[options::NdpOptionBuilder::Nonce(nonce)];
1349        let serialized = OptionSequenceBuilder::new(options.iter())
1350            .into_serializer()
1351            .serialize_vec_outer()
1352            .unwrap();
1353
1354        // The first two bytes are the kind and length bytes, respectively,
1355        // followed by the nonce bytes.
1356        let mut expected_bytes: [u8; 8] = [14, 1, 0, 0, 0, 0, 0, 0];
1357        expected_bytes[2..].copy_from_slice(&expected_nonce);
1358
1359        assert_eq!(serialized.as_ref(), expected_bytes);
1360
1361        let parsed = Options::parse(&expected_bytes[..]).unwrap();
1362        let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1363        assert_eq!(parsed.len(), 1);
1364        assert_eq!(parsed[0], options::NdpOption::Nonce(nonce));
1365    }
1366
1367    #[test]
1368    fn parse_serialize_prefix_option() {
1369        let expected_prefix_info = options::PrefixInformation::new(
1370            120,
1371            true,
1372            false,
1373            100,
1374            100,
1375            Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 0, 0]),
1376        );
1377        let options = &[options::NdpOptionBuilder::PrefixInformation(expected_prefix_info.clone())];
1378        let serialized = OptionSequenceBuilder::new(options.iter())
1379            .into_serializer()
1380            .serialize_vec_outer()
1381            .unwrap();
1382        // A Prefix Information option is exactly 32 bytes.
1383        //
1384        // The first two bytes are the kind and length bytes, respectively. This is then
1385        // immediately followed by the prefix information fields.
1386        let mut expected = [0; 32];
1387        expected[0] = 3;
1388        expected[1] = 4;
1389        (&mut expected[2..]).copy_from_slice(expected_prefix_info.as_bytes());
1390        assert_eq!(serialized.as_ref(), expected);
1391
1392        let parsed = Options::parse(&expected[..]).unwrap();
1393        let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1394        assert_eq!(parsed.len(), 1);
1395        assert_eq!(options::NdpOption::PrefixInformation(&expected_prefix_info), parsed[0]);
1396    }
1397
1398    #[test]
1399    fn parse_serialize_rdnss_option() {
1400        let test = |addrs: &[Ipv6Addr]| {
1401            let lifetime = 120;
1402            let expected_rdnss = options::RecursiveDnsServer::new(lifetime, addrs);
1403            let options = &[options::NdpOptionBuilder::RecursiveDnsServer(expected_rdnss.clone())];
1404            let serialized = OptionSequenceBuilder::new(options.iter())
1405                .into_serializer()
1406                .serialize_vec_outer()
1407                .unwrap();
1408            // 8 bytes for the kind, length, reserved and lifetime bytes + the bytes for
1409            // the addresses.
1410            let mut expected = vec![0; 8 + addrs.len() * usize::from(Ipv6Addr::BYTES)];
1411            // The first two bytes are the kind and length bytes, respectively. This is then
1412            // followed by 2 reserved bytes.
1413            //
1414            // NDP options hold the number of bytes in units of 8 bytes.
1415            (&mut expected[..4]).copy_from_slice(&[
1416                25,
1417                1 + u8::try_from(addrs.len()).unwrap() * 2,
1418                0,
1419                0,
1420            ]);
1421            // The lifetime field.
1422            NetworkEndian::write_u32(&mut expected[4..8], lifetime);
1423            // The list of addressess.
1424            (&mut expected[8..]).copy_from_slice(addrs.as_bytes());
1425            assert_eq!(serialized.as_ref(), expected.as_slice());
1426
1427            let parsed = Options::parse(&expected[..])
1428                .expect("should have parsed a valid recursive dns erver option");
1429            let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1430            assert_eq!(parsed.len(), 1);
1431
1432            // Also check that parsing RDNSS alone works as expected.
1433            assert_eq!(
1434                options::RecursiveDnsServer::parse(&expected[2..]).expect("parsing should succeed"),
1435                expected_rdnss
1436            );
1437
1438            assert_eq!(options::NdpOption::RecursiveDnsServer(expected_rdnss), parsed[0]);
1439        };
1440        test(&[Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])]);
1441        test(&[
1442            Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
1443            Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17]),
1444        ]);
1445    }
1446
1447    #[test]
1448    fn parse_serialize_rdnss_option_error() {
1449        let addrs = [
1450            Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
1451            Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17]),
1452        ];
1453        let lifetime = 120;
1454        // 8 bytes for the kind, length, reserved and lifetime bytes + the bytes for
1455        // the addresses.
1456        let mut buf = vec![0; 8 + addrs.len() * usize::from(Ipv6Addr::BYTES)];
1457        // The first two bytes are the kind and length bytes, respectively. This is then
1458        // followed by 2 reserved bytes.
1459        //
1460        // NDP options hold the number of bytes in units of 8 bytes.
1461        (&mut buf[..4]).copy_from_slice(&[25, 1 + u8::try_from(addrs.len()).unwrap() * 2, 0, 0]);
1462        // The lifetime field.
1463        NetworkEndian::write_u32(&mut buf[4..8], lifetime);
1464        // The list of addressess.
1465        (&mut buf[8..]).copy_from_slice(addrs.as_bytes());
1466
1467        // Sanity check to make sure `buf` is normally valid.
1468        let _parsed = Options::parse(&buf[..])
1469            .expect("should have parsed a valid recursive dns erver option");
1470
1471        // The option must hold at least 1 address.
1472        let _err = Options::parse(&buf[..8]).expect_err(
1473            "should not have parsed a recursive dns server option that has no addresses",
1474        );
1475
1476        // The option must hold full IPv6 addresses.
1477        let _err = Options::parse(&buf[..buf.len()-1])
1478            .expect_err("should not have parsed a recursive dns server option that cuts off in the middle of an address");
1479
1480        // The option must only hold unicast addresses; unspecified is not allowed.
1481        (&mut buf[8..8 + usize::from(Ipv6Addr::BYTES)])
1482            .copy_from_slice(Ipv6::UNSPECIFIED_ADDRESS.as_bytes());
1483        let _parsed = Options::parse(&buf[..]).expect_err(
1484            "should not have parsed a recursive dns erver option with an unspecified address",
1485        );
1486
1487        // The option must only hold unicast addresses; multicast is not allowed.
1488        (&mut buf[8..8 + usize::from(Ipv6Addr::BYTES)])
1489            .copy_from_slice(Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS.as_bytes());
1490        let _parsed = Options::parse(&buf[..]).expect_err(
1491            "should not have parsed a recursive dns erver option with a multicast address",
1492        );
1493    }
1494
1495    #[test]
1496    fn parse_neighbor_solicitation() {
1497        use crate::icmp::testdata::ndp_neighbor::*;
1498        let mut buf = SOLICITATION_IP_PACKET_BYTES;
1499        let ip = buf.parse::<Ipv6Packet<_>>().unwrap();
1500        let ipv6_builder = ip.builder();
1501        let (src_ip, dst_ip) = (ip.src_ip(), ip.dst_ip());
1502        let icmp = buf
1503            .parse_with::<_, IcmpPacket<_, _, NeighborSolicitation>>(IcmpParseArgs::new(
1504                src_ip, dst_ip,
1505            ))
1506            .unwrap();
1507
1508        assert_eq!(icmp.message().target_address.ipv6_bytes(), TARGET_ADDRESS);
1509        let collected = icmp.ndp_options().iter().collect::<Vec<options::NdpOption<'_>>>();
1510        for option in collected.iter() {
1511            match option {
1512                options::NdpOption::SourceLinkLayerAddress(address) => {
1513                    assert_eq!(address, &SOURCE_LINK_LAYER_ADDRESS);
1514                }
1515                o => panic!("Found unexpected option: {:?}", o),
1516            }
1517        }
1518        let option_builders =
1519            [options::NdpOptionBuilder::SourceLinkLayerAddress(&SOURCE_LINK_LAYER_ADDRESS)];
1520        let serialized = OptionSequenceBuilder::new(option_builders.iter())
1521            .into_serializer()
1522            .encapsulate(IcmpPacketBuilder::<Ipv6, _>::new(
1523                src_ip,
1524                dst_ip,
1525                IcmpZeroCode,
1526                *icmp.message(),
1527            ))
1528            .encapsulate(ipv6_builder)
1529            .serialize_vec_outer()
1530            .unwrap()
1531            .as_ref()
1532            .to_vec();
1533        assert_eq!(&serialized, &SOLICITATION_IP_PACKET_BYTES)
1534    }
1535
1536    #[test]
1537    fn parse_neighbor_advertisement() {
1538        use crate::icmp::testdata::ndp_neighbor::*;
1539        let mut buf = ADVERTISEMENT_IP_PACKET_BYTES;
1540        let ip = buf.parse::<Ipv6Packet<_>>().unwrap();
1541        let ipv6_builder = ip.builder();
1542        let (src_ip, dst_ip) = (ip.src_ip(), ip.dst_ip());
1543        let icmp = buf
1544            .parse_with::<_, IcmpPacket<_, _, NeighborAdvertisement>>(IcmpParseArgs::new(
1545                src_ip, dst_ip,
1546            ))
1547            .unwrap();
1548        assert_eq!(icmp.message().target_address.ipv6_bytes(), TARGET_ADDRESS);
1549        assert_eq!(icmp.ndp_options().iter().count(), 0);
1550
1551        let serialized = []
1552            .into_serializer()
1553            .encapsulate(IcmpPacketBuilder::<Ipv6, _>::new(
1554                src_ip,
1555                dst_ip,
1556                IcmpZeroCode,
1557                *icmp.message(),
1558            ))
1559            .encapsulate(ipv6_builder)
1560            .serialize_vec_outer()
1561            .unwrap()
1562            .as_ref()
1563            .to_vec();
1564        assert_eq!(&serialized, &ADVERTISEMENT_IP_PACKET_BYTES);
1565    }
1566
1567    #[test]
1568    fn parse_router_advertisement() {
1569        use crate::icmp::ndp::options::RouteInformation;
1570        use crate::icmp::testdata::ndp_router::*;
1571
1572        let mut buf = ADVERTISEMENT_IP_PACKET_BYTES;
1573        let ip = buf.parse::<Ipv6Packet<_>>().unwrap();
1574        let ipv6_builder = ip.builder();
1575        let (src_ip, dst_ip) = (ip.src_ip(), ip.dst_ip());
1576        let icmp = buf
1577            .parse_with::<_, IcmpPacket<_, _, RouterAdvertisement>>(IcmpParseArgs::new(
1578                src_ip, dst_ip,
1579            ))
1580            .unwrap();
1581        assert_eq!(icmp.message().current_hop_limit(), HOP_LIMIT);
1582        assert_eq!(icmp.message().router_lifetime(), LIFETIME);
1583        assert_eq!(icmp.message().reachable_time(), REACHABLE_TIME);
1584        assert_eq!(icmp.message().retransmit_timer(), RETRANS_TIMER);
1585
1586        assert_eq!(icmp.ndp_options().iter().count(), 5);
1587
1588        let collected = icmp.ndp_options().iter().collect::<Vec<options::NdpOption<'_>>>();
1589        for option in collected.iter() {
1590            match option {
1591                options::NdpOption::SourceLinkLayerAddress(address) => {
1592                    assert_eq!(address, &SOURCE_LINK_LAYER_ADDRESS);
1593                }
1594                options::NdpOption::PrefixInformation(info) => {
1595                    assert_eq!(info.on_link_flag(), PREFIX_INFO_ON_LINK_FLAG);
1596                    assert_eq!(
1597                        info.autonomous_address_configuration_flag(),
1598                        PREFIX_INFO_AUTONOMOUS_ADDRESS_CONFIGURATION_FLAG
1599                    );
1600                    assert_eq!(
1601                        info.valid_lifetime(),
1602                        NonZeroNdpLifetime::from_u32_with_infinite(
1603                            PREFIX_INFO_VALID_LIFETIME_SECONDS
1604                        )
1605                    );
1606                    assert_eq!(
1607                        info.preferred_lifetime(),
1608                        NonZeroNdpLifetime::from_u32_with_infinite(
1609                            PREFIX_INFO_PREFERRED_LIFETIME_SECONDS
1610                        )
1611                    );
1612                    assert_eq!(info.prefix_length(), PREFIX_INFO_PREFIX.prefix());
1613                    assert_eq!(info.prefix(), &PREFIX_INFO_PREFIX.network());
1614                }
1615                options::NdpOption::RouteInformation(_) => {
1616                    // Tested below
1617                }
1618                o => panic!("Found unexpected option: {:?}", o),
1619            }
1620        }
1621
1622        let mut route_information_options = collected
1623            .iter()
1624            .filter_map(|o| match o {
1625                options::NdpOption::RouteInformation(info) => Some(info),
1626                _ => None,
1627            })
1628            .collect::<Vec<&RouteInformation>>();
1629        // We must not make any assumptions on the order of received data, therefore we sort them.
1630        // From RFC 4861 section 4.6.2:
1631        //   Options in Neighbor Discovery packets can appear in any order; receivers MUST be
1632        //   prepared to process them independently of their order.
1633        route_information_options.sort_by_key(|o| o.prefix().prefix());
1634        assert_eq!(
1635            route_information_options,
1636            [
1637                &options::RouteInformation::new(
1638                    ROUTE_INFO_LOW_PREF_PREFIX,
1639                    ROUTE_INFO_LOW_PREF_VALID_LIFETIME_SECONDS,
1640                    ROUTE_INFO_LOW_PREF,
1641                ),
1642                &options::RouteInformation::new(
1643                    ROUTE_INFO_MEDIUM_PREF_PREFIX,
1644                    ROUTE_INFO_MEDIUM_PREF_VALID_LIFETIME_SECONDS,
1645                    ROUTE_INFO_MEDIUM_PREF,
1646                ),
1647                &options::RouteInformation::new(
1648                    ROUTE_INFO_HIGH_PREF_PREFIX,
1649                    ROUTE_INFO_HIGH_PREF_VALID_LIFETIME_SECONDS,
1650                    ROUTE_INFO_HIGH_PREF,
1651                )
1652            ]
1653        );
1654
1655        let option_builders = [
1656            options::NdpOptionBuilder::SourceLinkLayerAddress(&SOURCE_LINK_LAYER_ADDRESS),
1657            options::NdpOptionBuilder::PrefixInformation(options::PrefixInformation::new(
1658                PREFIX_INFO_PREFIX.prefix(),
1659                PREFIX_INFO_ON_LINK_FLAG,
1660                PREFIX_INFO_AUTONOMOUS_ADDRESS_CONFIGURATION_FLAG,
1661                PREFIX_INFO_VALID_LIFETIME_SECONDS,
1662                PREFIX_INFO_PREFERRED_LIFETIME_SECONDS,
1663                PREFIX_INFO_PREFIX.network(),
1664            )),
1665            options::NdpOptionBuilder::RouteInformation(options::RouteInformation::new(
1666                ROUTE_INFO_HIGH_PREF_PREFIX,
1667                ROUTE_INFO_HIGH_PREF_VALID_LIFETIME_SECONDS,
1668                ROUTE_INFO_HIGH_PREF,
1669            )),
1670            options::NdpOptionBuilder::RouteInformation(options::RouteInformation::new(
1671                ROUTE_INFO_MEDIUM_PREF_PREFIX,
1672                ROUTE_INFO_MEDIUM_PREF_VALID_LIFETIME_SECONDS,
1673                ROUTE_INFO_MEDIUM_PREF,
1674            )),
1675            options::NdpOptionBuilder::RouteInformation(options::RouteInformation::new(
1676                ROUTE_INFO_LOW_PREF_PREFIX,
1677                ROUTE_INFO_LOW_PREF_VALID_LIFETIME_SECONDS,
1678                ROUTE_INFO_LOW_PREF,
1679            )),
1680        ];
1681        let serialized = OptionSequenceBuilder::new(option_builders.iter())
1682            .into_serializer()
1683            .encapsulate(IcmpPacketBuilder::<Ipv6, _>::new(
1684                src_ip,
1685                dst_ip,
1686                IcmpZeroCode,
1687                *icmp.message(),
1688            ))
1689            .encapsulate(ipv6_builder)
1690            .serialize_vec_outer()
1691            .unwrap()
1692            .as_ref()
1693            .to_vec();
1694        assert_eq!(&serialized, &ADVERTISEMENT_IP_PACKET_BYTES);
1695    }
1696
1697    struct SerializeRATest {
1698        hop_limit: u8,
1699        managed_flag: bool,
1700        other_config_flag: bool,
1701        preference: RoutePreference,
1702        router_lifetime_seconds: u16,
1703        reachable_time_seconds: u32,
1704        retransmit_timer_seconds: u32,
1705    }
1706
1707    #[test_case(
1708        SerializeRATest{
1709            hop_limit: 1,
1710            managed_flag: true,
1711            other_config_flag: false,
1712            preference: RoutePreference::High,
1713            router_lifetime_seconds: 1_000,
1714            reachable_time_seconds: 1_000_000,
1715            retransmit_timer_seconds: 5,
1716        }; "test_1")]
1717    #[test_case(
1718        SerializeRATest{
1719            hop_limit: 64,
1720            managed_flag: false,
1721            other_config_flag: true,
1722            preference: RoutePreference::Low,
1723            router_lifetime_seconds: 5,
1724            reachable_time_seconds: 23425621,
1725            retransmit_timer_seconds: 13252521,
1726        }; "test_2")]
1727    fn serialize_router_advertisement(test: SerializeRATest) {
1728        let SerializeRATest {
1729            hop_limit,
1730            managed_flag,
1731            other_config_flag,
1732            preference,
1733            router_lifetime_seconds,
1734            reachable_time_seconds,
1735            retransmit_timer_seconds,
1736        } = test;
1737
1738        const SRC_IP: Ipv6Addr =
1739            Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
1740        const DST_IP: Ipv6Addr =
1741            Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17]);
1742        let serialized = packet::EmptyBuf
1743            .encapsulate(IcmpPacketBuilder::<Ipv6, _>::new(
1744                SRC_IP,
1745                DST_IP,
1746                IcmpZeroCode,
1747                RouterAdvertisement::with_prf(
1748                    hop_limit,
1749                    managed_flag,
1750                    other_config_flag,
1751                    preference,
1752                    router_lifetime_seconds,
1753                    reachable_time_seconds,
1754                    retransmit_timer_seconds,
1755                ),
1756            ))
1757            .serialize_vec_outer()
1758            .unwrap();
1759
1760        // As per RFC 4191 section 2.2,
1761        //
1762        //      0                   1                   2                   3
1763        //      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1764        //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1765        //     |     Type      |     Code      |          Checksum             |
1766        //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1767        //     | Cur Hop Limit |M|O|H|Prf|Resvd|       Router Lifetime         |
1768        //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1769        //     |                         Reachable Time                        |
1770        //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1771        //     |                          Retrans Timer                        |
1772        //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1773        //
1774        // As  per RFC 4861 section 4.2,
1775        //
1776        //    ICMP Fields:
1777        //
1778        //      Type           134
1779        //
1780        //      Code           0
1781        const RA_LEN: u32 = 16;
1782        let mut expected = [0; RA_LEN as usize];
1783        expected[0] = 134;
1784        expected[4] = hop_limit;
1785        if managed_flag {
1786            expected[5] |= 1 << 7;
1787        }
1788        if other_config_flag {
1789            expected[5] |= 1 << 6;
1790        }
1791        expected[5] |= u8::from(preference) << 3;
1792        let (mut router_lifetime, _rest) = Ref::<_, U16>::from_prefix(&mut expected[6..]).unwrap();
1793        router_lifetime.set(router_lifetime_seconds);
1794        let (mut reachable_time, _rest) = Ref::<_, U32>::from_prefix(&mut expected[8..]).unwrap();
1795        reachable_time.set(reachable_time_seconds);
1796        let (mut retransmit_timer, _rest) =
1797            Ref::<_, U32>::from_prefix(&mut expected[12..]).unwrap();
1798        retransmit_timer.set(retransmit_timer_seconds);
1799
1800        let mut c = internet_checksum::Checksum::new();
1801        // Checksum pseudo-header.
1802        c.add_bytes(SRC_IP.bytes());
1803        c.add_bytes(DST_IP.bytes());
1804        c.add_bytes(U32::new(RA_LEN).as_bytes());
1805        c.add_bytes(&[0, crate::ip::Ipv6Proto::Icmpv6.into()]);
1806        // Checksum actual message.
1807        c.add_bytes(&expected[..]);
1808        expected[2..4].copy_from_slice(&c.checksum()[..]);
1809
1810        assert_eq!(serialized.as_ref(), &expected[..]);
1811    }
1812
1813    struct SerializeRioTest {
1814        prefix_length: u8,
1815        route_lifetime_seconds: u32,
1816        preference: RoutePreference,
1817        expected_option_length: u8,
1818    }
1819
1820    // As per RFC 4191 section 2.3,
1821    //
1822    //    Length     8-bit unsigned integer.  The length of the option
1823    //               (including the Type and Length fields) in units of 8
1824    //               octets.  The Length field is 1, 2, or 3 depending on the
1825    //               Prefix Length.  If Prefix Length is greater than 64, then
1826    //               Length must be 3.  If Prefix Length is greater than 0,
1827    //               then Length must be 2 or 3.  If Prefix Length is zero,
1828    //               then Length must be 1, 2, or 3.
1829    #[test_case(
1830        SerializeRioTest{
1831            prefix_length: 0,
1832            route_lifetime_seconds: 1,
1833            preference: RoutePreference::High,
1834            expected_option_length: 8,
1835        }; "prefix_length_0")]
1836    #[test_case(
1837        SerializeRioTest{
1838            prefix_length: 1,
1839            route_lifetime_seconds: 1000,
1840            preference: RoutePreference::Medium,
1841            expected_option_length: 16,
1842        }; "prefix_length_1")]
1843    #[test_case(
1844        SerializeRioTest{
1845            prefix_length: 64,
1846            route_lifetime_seconds: 100000,
1847            preference: RoutePreference::Low,
1848            expected_option_length: 16,
1849        }; "prefix_length_64")]
1850    #[test_case(
1851        SerializeRioTest{
1852            prefix_length: 65,
1853            route_lifetime_seconds: 1000000,
1854            preference: RoutePreference::Medium,
1855            expected_option_length: 24,
1856        }; "prefix_length_65")]
1857    #[test_case(
1858        SerializeRioTest{
1859            prefix_length: 128,
1860            route_lifetime_seconds: 10000000,
1861            preference: RoutePreference::Medium,
1862            expected_option_length: 24,
1863        }; "prefix_length_128")]
1864    fn serialize_route_information_option(test: SerializeRioTest) {
1865        const IPV6ADDR: Ipv6Addr =
1866            Ipv6Addr::new([0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
1867
1868        let SerializeRioTest {
1869            prefix_length,
1870            route_lifetime_seconds,
1871            preference,
1872            expected_option_length,
1873        } = test;
1874        let prefix = IPV6ADDR.mask(prefix_length);
1875
1876        let option_builders =
1877            [options::NdpOptionBuilder::RouteInformation(options::RouteInformation::new(
1878                Subnet::new(prefix, prefix_length).unwrap(),
1879                route_lifetime_seconds,
1880                preference,
1881            ))];
1882
1883        let serialized = OptionSequenceBuilder::new(option_builders.iter())
1884            .into_serializer()
1885            .serialize_vec_outer()
1886            .unwrap();
1887
1888        // As per RFC 4191 section 2.3,
1889        //
1890        //   Route Information Option
1891        //
1892        //      0                   1                   2                   3
1893        //       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1894        //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1895        //      |     Type      |    Length     | Prefix Length |Resvd|Prf|Resvd|
1896        //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1897        //      |                        Route Lifetime                         |
1898        //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1899        //      |                   Prefix (Variable Length)                    |
1900        //      .                                                               .
1901        //      .                                                               .
1902        //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1903        //
1904        //   Fields:
1905        //
1906        //   Type        24
1907        //
1908        //   Length      8-bit unsigned integer.  The length of the option
1909        //               (including the Type and Length fields) in units of 8
1910        //               octets.  The Length field is 1, 2, or 3 depending on the
1911        //               Prefix Length.  If Prefix Length is greater than 64, then
1912        //               Length must be 3.  If Prefix Length is greater than 0,
1913        //               then Length must be 2 or 3.  If Prefix Length is zero,
1914        //               then Length must be 1, 2, or 3.
1915        let mut expected = [0; 24];
1916        expected[0] = 24;
1917        expected[1] = expected_option_length / 8;
1918        expected[2] = prefix_length;
1919        expected[3] = u8::from(preference) << 3;
1920        let (mut lifetime_seconds, _rest) = Ref::<_, U32>::from_prefix(&mut expected[4..]).unwrap();
1921        lifetime_seconds.set(route_lifetime_seconds);
1922        expected[8..].copy_from_slice(prefix.bytes());
1923
1924        assert_eq!(serialized.as_ref(), &expected[..expected_option_length.into()]);
1925    }
1926
1927    #[test_case(0, None)]
1928    #[test_case(
1929        1,
1930        Some(NonZeroNdpLifetime::Finite(NonZeroDuration::new(
1931            Duration::from_secs(1),
1932        ).unwrap()))
1933    )]
1934    #[test_case(
1935        u32::MAX - 1,
1936        Some(NonZeroNdpLifetime::Finite(NonZeroDuration::new(
1937            Duration::from_secs(u64::from(u32::MAX) - 1),
1938        ).unwrap()))
1939    )]
1940    #[test_case(u32::MAX, Some(NonZeroNdpLifetime::Infinite))]
1941    fn non_zero_ndp_lifetime_non_zero_or_max_u32_from_u32_with_infinite(
1942        t: u32,
1943        expected: Option<NonZeroNdpLifetime>,
1944    ) {
1945        assert_eq!(NonZeroNdpLifetime::from_u32_with_infinite(t), expected)
1946    }
1947
1948    const MIN_NON_ZERO_DURATION: Duration = Duration::new(0, 1);
1949    #[test_case(
1950        NonZeroNdpLifetime::Infinite,
1951        NonZeroDuration::new(MIN_NON_ZERO_DURATION).unwrap(),
1952        NonZeroDuration::new(MIN_NON_ZERO_DURATION).unwrap()
1953    )]
1954    #[test_case(
1955        NonZeroNdpLifetime::Infinite,
1956        NonZeroDuration::new(Duration::MAX).unwrap(),
1957        NonZeroDuration::new(Duration::MAX).unwrap()
1958    )]
1959    #[test_case(
1960        NonZeroNdpLifetime::Finite(NonZeroDuration::new(
1961            Duration::from_secs(2)).unwrap()
1962        ),
1963        NonZeroDuration::new(Duration::from_secs(1)).unwrap(),
1964        NonZeroDuration::new(Duration::from_secs(1)).unwrap()
1965    )]
1966    #[test_case(
1967        NonZeroNdpLifetime::Finite(NonZeroDuration::new(
1968            Duration::from_secs(3)).unwrap()
1969        ),
1970        NonZeroDuration::new(Duration::from_secs(4)).unwrap(),
1971        NonZeroDuration::new(Duration::from_secs(3)).unwrap()
1972    )]
1973    fn non_zero_ndp_lifetime_min_finite_duration(
1974        lifetime: NonZeroNdpLifetime,
1975        duration: NonZeroDuration,
1976        expected: NonZeroDuration,
1977    ) {
1978        assert_eq!(lifetime.min_finite_duration(duration), expected)
1979    }
1980}