Skip to main content

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