1use 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#[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#[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#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
41pub enum NonZeroNdpLifetime {
42 Finite(NonZeroDuration),
50
51 Infinite,
53}
54
55impl NonZeroNdpLifetime {
56 pub fn from_u32_with_infinite(lifetime: u32) -> Option<NonZeroNdpLifetime> {
59 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 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
92pub type Options<B> = packet::records::options::Options<B, options::NdpOptionsImpl>;
98
99pub type OptionSequenceBuilder<'a, I> =
105 packet::records::options::OptionSequenceBuilder<options::NdpOptionBuilder<'a>, I>;
106
107#[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#[allow(missing_docs)]
132#[derive(Copy, Clone, Debug, PartialEq, Eq)]
133pub enum RoutePreference {
134 High,
140 Medium,
141 Low,
142}
143
144impl Default for RoutePreference {
145 fn default() -> RoutePreference {
146 RoutePreference::Medium
156 }
157}
158
159impl From<RoutePreference> for u8 {
160 fn from(v: RoutePreference) -> u8 {
161 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 match v {
192 0b01 => Ok(RoutePreference::High),
193 0b00 => Ok(RoutePreference::Medium),
194 0b11 => Ok(RoutePreference::Low),
195 _ => Err(()),
196 }
197 }
198}
199
200#[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 const MANAGED_FLAG: u8 = 0x80;
224
225 const OTHER_CONFIGURATION_FLAG: u8 = 0x40;
231
232 const DEFAULT_ROUTER_PREFERENCE_SHIFT: u8 = 3;
256 const DEFAULT_ROUTER_PREFERENCE_MASK: u8 = 0b11 << Self::DEFAULT_ROUTER_PREFERENCE_SHIFT;
257
258 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 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 pub fn current_hop_limit(&self) -> Option<NonZeroU8> {
316 NonZeroU8::new(self.current_hop_limit)
317 }
318
319 pub fn router_lifetime(&self) -> Option<NonZeroDuration> {
324 NonZeroDuration::new(Duration::from_secs(self.router_lifetime.get().into()))
327 }
328
329 pub fn reachable_time(&self) -> Option<NonZeroDuration> {
333 NonZeroDuration::new(Duration::from_millis(self.reachable_time.get().into()))
336 }
337
338 pub fn retransmit_timer(&self) -> Option<NonZeroDuration> {
342 NonZeroDuration::new(Duration::from_millis(self.retransmit_timer.get().into()))
345 }
346}
347
348#[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 pub fn new(target_address: Ipv6Addr) -> Self {
364 Self { _reserved: [0; 4], target_address }
365 }
366
367 pub fn target_address(&self) -> &Ipv6Addr {
369 &self.target_address
370 }
371}
372
373#[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 const FLAG_ROUTER: u8 = 0x80;
393
394 const FLAG_SOLICITED: u8 = 0x40;
402
403 const FLAG_OVERRIDE: u8 = 0x20;
414
415 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 pub fn target_address(&self) -> &Ipv6Addr {
442 &self.target_address
443 }
444
445 pub fn router_flag(&self) -> bool {
447 (self.flags_rso & Self::FLAG_ROUTER) != 0
448 }
449
450 pub fn solicited_flag(&self) -> bool {
452 (self.flags_rso & Self::FLAG_SOLICITED) != 0
453 }
454
455 pub fn override_flag(&self) -> bool {
457 (self.flags_rso & Self::FLAG_OVERRIDE) != 0
458 }
459}
460
461#[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
474pub 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 pub const INFINITE_LIFETIME_SECONDS: u32 = u32::MAX;
494
495 pub const INFINITE_LIFETIME: NonZeroDuration =
498 NonZeroDuration::from_secs(INFINITE_LIFETIME_SECONDS as u64).unwrap();
499
500 const REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH: usize = 6;
507
508 const MTU_OPTION_LENGTH: usize = 6;
514
515 const MTU_OPTION_RESERVED_BYTES_LENGTH: usize = 2;
522
523 pub const MIN_NONCE_LENGTH: usize = 6;
529
530 const MIN_RECURSIVE_DNS_SERVER_OPTION_LENGTH: usize = 22;
540
541 const RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH: usize = 2;
548
549 const ROUTE_INFORMATION_PREFERENCE_RESERVED_BITS_RIGHT: u8 = 3;
555
556 const ROUTE_INFORMATION_PREFERENCE_MASK: u8 = 0x18;
562
563 const OPTION_BYTES_PER_LENGTH_UNIT: usize = 8;
569
570 #[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 pub const INFINITE_LIFETIME: u32 = INFINITE_LIFETIME_SECONDS;
584
585 pub fn new(lifetime: u32, addresses: &'a [Ipv6Addr]) -> RecursiveDnsServer<'a> {
587 RecursiveDnsServer { lifetime, addresses }
588 }
589
590 pub fn lifetime(&self) -> Option<NonZeroDuration> {
596 NonZeroDuration::new(Duration::from_secs(self.lifetime.into()))
597 }
598
599 pub fn iter_addresses(&self) -> &'a [Ipv6Addr] {
601 self.addresses
602 }
603
604 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 let (_, data) = data.split_at(RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH);
614
615 let (lifetime, data) = Ref::<_, U32>::from_prefix(data).map_err(|_| OptionParseErr)?;
618
619 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 if !addresses.iter().all(UnicastAddress::is_unicast) {
629 return Err(OptionParseErr);
630 }
631
632 Ok(Self::new(lifetime.get(), addresses))
633 }
634 }
635
636 #[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 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 #[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 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 pub fn prefix(&self) -> &Subnet<Ipv6Addr> {
717 &self.prefix
718 }
719
720 pub fn preference(&self) -> super::RoutePreference {
722 self.preference
723 }
724
725 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 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 const PREFIX_INFORMATION_OPTION_LENGTH: usize = 30;
781
782 #[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 const ON_LINK_FLAG: u8 = 0x80;
807
808 const AUTONOMOUS_ADDRESS_CONFIGURATION_FLAG: u8 = 0x40;
815
816 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 pub fn prefix_length(&self) -> u8 {
847 self.prefix_length
848 }
849
850 pub fn on_link_flag(&self) -> bool {
857 (self.flags_la & Self::ON_LINK_FLAG) != 0
858 }
859
860 pub fn autonomous_address_configuration_flag(&self) -> bool {
862 (self.flags_la & Self::AUTONOMOUS_ADDRESS_CONFIGURATION_FLAG) != 0
863 }
864
865 pub fn valid_lifetime(&self) -> Option<NonZeroNdpLifetime> {
871 NonZeroNdpLifetime::from_u32_with_infinite(self.valid_lifetime.get())
872 }
873
874 pub fn preferred_lifetime(&self) -> Option<NonZeroNdpLifetime> {
880 NonZeroNdpLifetime::from_u32_with_infinite(self.preferred_lifetime.get())
881 }
882
883 pub fn prefix(&self) -> &Ipv6Addr {
890 &self.prefix
891 }
892
893 pub fn subnet(&self) -> Result<Subnet<Ipv6Addr>, SubnetError> {
895 Subnet::new(self.prefix, self.prefix_length)
896 }
897 }
898
899 pub mod option_types {
901 pub const PREFIX_INFORMATION: u8 = 3;
903
904 pub const RECURSIVE_DNS_SERVER: u8 = 25;
906
907 pub const DNS_SEARCH_LIST: u8 = 31;
909
910 pub const SIXLOWPAN_CONTEXT: u8 = 34;
912
913 pub const CAPTIVE_PORTAL: u8 = 37;
915
916 pub const PREF64: u8 = 38;
918
919 pub fn debug_name(option_type: u8) -> Option<&'static str> {
921 match option_type {
924 super::option_types::PREFIX_INFORMATION => Some("PREFIX_INFORMATION"),
925 super::option_types::RECURSIVE_DNS_SERVER => Some("RECURSIVE_DNS_SERVER"),
926 super::option_types::DNS_SEARCH_LIST => Some("DNS_SEARCH_LIST"),
927 super::option_types::SIXLOWPAN_CONTEXT => Some("SIXLOWPAN_CONTEXT"),
928 super::option_types::CAPTIVE_PORTAL => Some("CAPTIVE_PORTAL"),
929 super::option_types::PREF64 => Some("PREF64"),
930 _ => None,
931 }
932 }
933 }
934
935 use option_types::{PREFIX_INFORMATION, RECURSIVE_DNS_SERVER};
936
937 create_protocol_enum!(
938 #[allow(missing_docs)]
940 pub enum NdpOptionType: u8 {
941 SourceLinkLayerAddress, 1, "Source Link-Layer Address";
942 TargetLinkLayerAddress, 2, "Target Link-Layer Address";
943 PrefixInformation, PREFIX_INFORMATION, "Prefix Information";
944 RedirectedHeader, 4, "Redirected Header";
945 Mtu, 5, "MTU";
946 Nonce, 14, "Nonce";
947 RouteInformation, 24, "Route Information";
948 RecursiveDnsServer, RECURSIVE_DNS_SERVER, "Recursive DNS Server";
949 }
950 );
951
952 #[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)]
959 pub struct NdpNonce<B: SplitByteSlice> {
960 nonce: B,
961 }
962
963 impl<B: SplitByteSlice> NdpNonce<B> {
964 pub fn bytes(&self) -> &[u8] {
966 let Self { nonce } = self;
967 nonce.deref()
968 }
969
970 pub fn new(value: B) -> Result<Self, InvalidNonceError> {
973 let bytes = value.deref();
974 let nonce_option_length_bytes = bytes.len() + 2;
978 if nonce_option_length_bytes % 8 != 0 {
979 return Err(InvalidNonceError::ResultsInNonMultipleOf8);
980 }
981
982 let nonce_option_length_in_groups_of_8_bytes = nonce_option_length_bytes / 8;
983
984 match u8::try_from(nonce_option_length_in_groups_of_8_bytes) {
987 Ok(_) => (),
988 Err(_) => return Err(InvalidNonceError::TooLong),
989 };
990
991 Ok(Self { nonce: value })
992 }
993 }
994
995 impl<B: SplitByteSlice> AsRef<[u8]> for NdpNonce<B> {
996 fn as_ref(&self) -> &[u8] {
997 self.bytes()
998 }
999 }
1000
1001 impl<'a> From<&'a [u8; MIN_NONCE_LENGTH]> for NdpNonce<&'a [u8]> {
1004 fn from(value: &'a [u8; MIN_NONCE_LENGTH]) -> Self {
1005 Self { nonce: &value[..] }
1006 }
1007 }
1008
1009 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
1011 pub enum InvalidNonceError {
1012 ResultsInNonMultipleOf8,
1015 TooLong,
1017 }
1018
1019 #[allow(missing_docs)]
1021 #[derive(Debug, PartialEq, Eq)]
1022 pub enum NdpOption<'a> {
1023 SourceLinkLayerAddress(&'a [u8]),
1024 TargetLinkLayerAddress(&'a [u8]),
1025 PrefixInformation(&'a PrefixInformation),
1026
1027 RedirectedHeader { original_packet: &'a [u8] },
1028
1029 Mtu(u32),
1030 Nonce(NdpNonce<&'a [u8]>),
1031
1032 RecursiveDnsServer(RecursiveDnsServer<'a>),
1033 RouteInformation(RouteInformation),
1034 }
1035
1036 impl<'a> NdpOption<'a> {
1037 pub fn nonce(self) -> Option<NdpNonce<&'a [u8]>> {
1039 match self {
1040 NdpOption::Nonce(nonce) => Some(nonce),
1041 _ => None,
1042 }
1043 }
1044
1045 pub fn source_link_layer_address(self) -> Option<&'a [u8]> {
1047 match self {
1048 NdpOption::SourceLinkLayerAddress(a) => Some(a),
1049 _ => None,
1050 }
1051 }
1052
1053 pub fn target_link_layer_address(self) -> Option<&'a [u8]> {
1055 match self {
1056 NdpOption::TargetLinkLayerAddress(a) => Some(a),
1057 _ => None,
1058 }
1059 }
1060 }
1061
1062 #[derive(Debug)]
1064 pub struct NdpOptionsImpl;
1065
1066 impl<'a> OptionLayout for NdpOptionsImpl {
1067 type KindLenField = u8;
1068
1069 const LENGTH_ENCODING: LengthEncoding = LengthEncoding::TypeLengthValue {
1071 option_len_multiplier: NonZeroUsize::new(8).unwrap(),
1072 };
1073 }
1074
1075 impl OptionParseLayout for NdpOptionsImpl {
1076 type Error = OptionParseErr;
1078
1079 const END_OF_OPTIONS: Option<u8> = None;
1081 const NOP: Option<u8> = None;
1082 }
1083
1084 impl OptionsImpl for NdpOptionsImpl {
1085 type Option<'a> = NdpOption<'a>;
1086
1087 fn parse<'a>(
1088 kind: u8,
1089 mut data: &'a [u8],
1090 ) -> Result<Option<NdpOption<'a>>, OptionParseErr> {
1091 let kind = if let Ok(k) = NdpOptionType::try_from(kind) {
1092 k
1093 } else {
1094 return Ok(None);
1095 };
1096
1097 let opt = match kind {
1098 NdpOptionType::SourceLinkLayerAddress => NdpOption::SourceLinkLayerAddress(data),
1099 NdpOptionType::TargetLinkLayerAddress => NdpOption::TargetLinkLayerAddress(data),
1100 NdpOptionType::PrefixInformation => {
1101 let data = Ref::<_, PrefixInformation>::from_bytes(data)
1102 .map_err(|_| OptionParseErr)?;
1103 NdpOption::PrefixInformation(Ref::into_ref(data))
1104 }
1105 NdpOptionType::RedirectedHeader => NdpOption::RedirectedHeader {
1106 original_packet: &data[REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH..],
1107 },
1108 NdpOptionType::Mtu => NdpOption::Mtu(NetworkEndian::read_u32(
1109 &data[MTU_OPTION_RESERVED_BYTES_LENGTH..],
1110 )),
1111 NdpOptionType::Nonce => NdpOption::Nonce(
1112 NdpNonce::new(data).map_err(|_: InvalidNonceError| OptionParseErr)?,
1113 ),
1114 NdpOptionType::RecursiveDnsServer => {
1115 NdpOption::RecursiveDnsServer(RecursiveDnsServer::parse(data)?)
1116 }
1117 NdpOptionType::RouteInformation => {
1118 #[derive(KnownLayout, FromBytes, Immutable, Unaligned)]
1121 #[repr(C)]
1122 struct RouteInfoFixed {
1123 prefix_length: u8,
1124 preference_raw: u8,
1125 route_lifetime_seconds: U32,
1126 }
1127
1128 let mut buf = &mut data;
1129
1130 let fixed = buf.take_obj_front::<RouteInfoFixed>().ok_or(OptionParseErr)?;
1131
1132 let preference = super::RoutePreference::try_from(
1134 (fixed.preference_raw & ROUTE_INFORMATION_PREFERENCE_MASK)
1135 >> ROUTE_INFORMATION_PREFERENCE_RESERVED_BITS_RIGHT,
1136 )
1137 .map_err(|()| OptionParseErr)?;
1138
1139 let buf_len = buf.len();
1151 if buf_len % OPTION_BYTES_PER_LENGTH_UNIT != 0 {
1152 return Err(OptionParseErr);
1153 }
1154 let length = buf_len / OPTION_BYTES_PER_LENGTH_UNIT;
1155 match (fixed.prefix_length, length) {
1156 (65..=128, 2) => {}
1157 (1..=64, 1 | 2) => {}
1158 (0, 0 | 1 | 2) => {}
1159 _ => return Err(OptionParseErr),
1160 }
1161
1162 let mut prefix_buf = [0; 16];
1163 prefix_buf[..buf_len].copy_from_slice(&buf);
1165 let prefix = Ipv6Addr::from_bytes(prefix_buf);
1166
1167 NdpOption::RouteInformation(RouteInformation::new(
1168 Subnet::new(prefix, fixed.prefix_length).map_err(|_| OptionParseErr)?,
1169 fixed.route_lifetime_seconds.get(),
1170 preference,
1171 ))
1172 }
1173 };
1174
1175 Ok(Some(opt))
1176 }
1177 }
1178
1179 #[allow(missing_docs)]
1181 #[derive(Debug)]
1182 pub enum NdpOptionBuilder<'a> {
1183 SourceLinkLayerAddress(&'a [u8]),
1184 TargetLinkLayerAddress(&'a [u8]),
1185 PrefixInformation(PrefixInformation),
1186
1187 RedirectedHeader { original_packet: &'a [u8] },
1188
1189 Mtu(u32),
1190 Nonce(NdpNonce<&'a [u8]>),
1191
1192 RouteInformation(RouteInformation),
1193 RecursiveDnsServer(RecursiveDnsServer<'a>),
1194 }
1195
1196 impl<'a> From<&NdpOptionBuilder<'a>> for NdpOptionType {
1197 fn from(v: &NdpOptionBuilder<'a>) -> Self {
1198 match v {
1199 NdpOptionBuilder::SourceLinkLayerAddress(_) => {
1200 NdpOptionType::SourceLinkLayerAddress
1201 }
1202 NdpOptionBuilder::TargetLinkLayerAddress(_) => {
1203 NdpOptionType::TargetLinkLayerAddress
1204 }
1205 NdpOptionBuilder::PrefixInformation(_) => NdpOptionType::PrefixInformation,
1206 NdpOptionBuilder::RedirectedHeader { .. } => NdpOptionType::RedirectedHeader,
1207 NdpOptionBuilder::Mtu { .. } => NdpOptionType::Mtu,
1208 NdpOptionBuilder::Nonce(_) => NdpOptionType::Nonce,
1209 NdpOptionBuilder::RouteInformation(_) => NdpOptionType::RouteInformation,
1210 NdpOptionBuilder::RecursiveDnsServer(_) => NdpOptionType::RecursiveDnsServer,
1211 }
1212 }
1213 }
1214
1215 impl<'a> OptionBuilder for NdpOptionBuilder<'a> {
1216 type Layout = NdpOptionsImpl;
1217
1218 fn serialized_len(&self) -> usize {
1219 match self {
1220 NdpOptionBuilder::SourceLinkLayerAddress(data)
1221 | NdpOptionBuilder::TargetLinkLayerAddress(data) => data.len(),
1222 NdpOptionBuilder::PrefixInformation(_) => PREFIX_INFORMATION_OPTION_LENGTH,
1223 NdpOptionBuilder::RedirectedHeader { original_packet } => {
1224 REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH + original_packet.len()
1225 }
1226 NdpOptionBuilder::Mtu(_) => MTU_OPTION_LENGTH,
1227 NdpOptionBuilder::Nonce(NdpNonce { nonce }) => nonce.len(),
1228 NdpOptionBuilder::RouteInformation(o) => o.serialized_len(),
1229 NdpOptionBuilder::RecursiveDnsServer(RecursiveDnsServer {
1230 lifetime,
1231 addresses,
1232 }) => {
1233 RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH
1234 + core::mem::size_of_val(lifetime)
1235 + core::mem::size_of_val(*addresses)
1236 }
1237 }
1238 }
1239
1240 fn option_kind(&self) -> u8 {
1241 NdpOptionType::from(self).into()
1242 }
1243
1244 fn serialize_into(&self, buffer: &mut [u8]) {
1245 match self {
1246 NdpOptionBuilder::SourceLinkLayerAddress(data)
1247 | NdpOptionBuilder::TargetLinkLayerAddress(data) => buffer.copy_from_slice(data),
1248 NdpOptionBuilder::PrefixInformation(pfx_info) => {
1249 buffer.copy_from_slice(pfx_info.as_bytes());
1250 }
1251 NdpOptionBuilder::RedirectedHeader { original_packet } => {
1252 let (reserved_bytes, original_packet_bytes) =
1256 buffer.split_at_mut(REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH);
1257 reserved_bytes
1258 .copy_from_slice(&[0; REDIRECTED_HEADER_OPTION_RESERVED_BYTES_LENGTH]);
1259 original_packet_bytes.copy_from_slice(original_packet);
1260 }
1261 NdpOptionBuilder::Mtu(mtu) => {
1262 let (reserved_bytes, mtu_bytes) =
1265 buffer.split_at_mut(MTU_OPTION_RESERVED_BYTES_LENGTH);
1266 reserved_bytes.copy_from_slice(&[0; MTU_OPTION_RESERVED_BYTES_LENGTH]);
1267 mtu_bytes.copy_from_slice(U32::new(*mtu).as_bytes());
1268 }
1269 NdpOptionBuilder::Nonce(NdpNonce { nonce }) => {
1270 buffer.copy_from_slice(nonce);
1271 }
1272 NdpOptionBuilder::RouteInformation(p) => p.serialize(buffer),
1273 NdpOptionBuilder::RecursiveDnsServer(RecursiveDnsServer {
1274 lifetime,
1275 addresses,
1276 }) => {
1277 let (reserved_bytes, buffer) =
1280 buffer.split_at_mut(RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH);
1281 reserved_bytes
1282 .copy_from_slice(&[0; RECURSIVE_DNS_SERVER_OPTION_RESERVED_BYTES_LENGTH]);
1283
1284 let (lifetime_bytes, addresses_bytes) =
1288 buffer.split_at_mut(core::mem::size_of_val(lifetime));
1289 lifetime_bytes.copy_from_slice(U32::new(*lifetime).as_bytes());
1290 addresses_bytes.copy_from_slice(addresses.as_bytes());
1291 }
1292 }
1293 }
1294 }
1295}
1296
1297#[cfg(test)]
1298mod tests {
1299 use byteorder::{ByteOrder, NetworkEndian};
1300 use net_types::ip::{Ip, IpAddress, Subnet};
1301 use packet::{EmptyBuf, InnerPacketBuilder, PacketBuilder, ParseBuffer, Serializer};
1302 use test_case::test_case;
1303 use zerocopy::Ref;
1304
1305 use super::*;
1306 use crate::icmp::{IcmpPacketBuilder, IcmpParseArgs};
1307 use crate::ipv6::{Ipv6Header, Ipv6Packet};
1308
1309 #[test]
1310 fn parse_serialize_redirected_header() {
1311 let expected_packet = [1, 2, 3, 4, 5, 6, 7, 8];
1312 let options =
1313 &[options::NdpOptionBuilder::RedirectedHeader { original_packet: &expected_packet }];
1314 let serialized = OptionSequenceBuilder::new(options.iter())
1315 .into_serializer()
1316 .serialize_vec_outer()
1317 .unwrap();
1318 let mut expected = [0; 16];
1320 (&mut expected[..2]).copy_from_slice(&[4, 2]);
1325 (&mut expected[8..]).copy_from_slice(&expected_packet);
1326 assert_eq!(serialized.as_ref(), expected);
1327
1328 let parsed = Options::parse(&expected[..]).unwrap();
1329 let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1330 assert_eq!(parsed.len(), 1);
1331 assert_eq!(
1332 options::NdpOption::RedirectedHeader { original_packet: &expected_packet },
1333 parsed[0]
1334 );
1335 }
1336
1337 #[test]
1338 fn parse_serialize_mtu_option() {
1339 let expected_mtu = 5781;
1340 let options = &[options::NdpOptionBuilder::Mtu(expected_mtu)];
1341 let serialized = OptionSequenceBuilder::new(options.iter())
1342 .into_serializer()
1343 .serialize_vec_outer()
1344 .unwrap();
1345 let mut expected = [5, 1, 0, 0, 0, 0, 0, 0];
1350 NetworkEndian::write_u32(&mut expected[4..], expected_mtu);
1351 assert_eq!(serialized.as_ref(), expected);
1352
1353 let parsed = Options::parse(&expected[..]).unwrap();
1354 let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1355 assert_eq!(parsed.len(), 1);
1356 assert_eq!(options::NdpOption::Mtu(expected_mtu), parsed[0]);
1357 }
1358
1359 #[test_case(
1360 options::MIN_NONCE_LENGTH - 1 =>
1361 matches Err(options::InvalidNonceError::ResultsInNonMultipleOf8);
1362 "resulting nonce option length must be multiple of 8")]
1363 #[test_case(
1364 options::MIN_NONCE_LENGTH => matches Ok(_);
1365 "MIN_NONCE_LENGTH must validate successfully")]
1366 #[test_case(
1367 usize::from(u8::MAX) * 8 - 2 => matches Ok(_);
1368 "maximum possible nonce length must validate successfully")]
1369 #[test_case(
1370 usize::from(u8::MAX) * 8 - 2 + 8 =>
1371 matches Err(options::InvalidNonceError::TooLong);
1372 "nonce option's length must fit in u8")]
1373 fn nonce_length_validation(
1374 length: usize,
1375 ) -> Result<options::NdpNonce<&'static [u8]>, options::InvalidNonceError> {
1376 const LEN: usize = (u8::MAX as usize + 1) * 8;
1377 const BYTES: [u8; LEN] = [0u8; LEN];
1378 options::NdpNonce::new(&BYTES[..length])
1379 }
1380
1381 #[test]
1382 fn parse_serialize_nonce_option() {
1383 let expected_nonce: [u8; 6] = [1, 2, 3, 4, 5, 6];
1384 let nonce = options::NdpNonce::new(&expected_nonce[..]).expect("should be valid nonce");
1385 let options = &[options::NdpOptionBuilder::Nonce(nonce)];
1386 let serialized = OptionSequenceBuilder::new(options.iter())
1387 .into_serializer()
1388 .serialize_vec_outer()
1389 .unwrap();
1390
1391 let mut expected_bytes: [u8; 8] = [14, 1, 0, 0, 0, 0, 0, 0];
1394 expected_bytes[2..].copy_from_slice(&expected_nonce);
1395
1396 assert_eq!(serialized.as_ref(), expected_bytes);
1397
1398 let parsed = Options::parse(&expected_bytes[..]).unwrap();
1399 let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1400 assert_eq!(parsed.len(), 1);
1401 assert_eq!(parsed[0], options::NdpOption::Nonce(nonce));
1402 }
1403
1404 #[test]
1405 fn parse_serialize_prefix_option() {
1406 let expected_prefix_info = options::PrefixInformation::new(
1407 120,
1408 true,
1409 false,
1410 100,
1411 100,
1412 Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 168, 0, 0]),
1413 );
1414 let options = &[options::NdpOptionBuilder::PrefixInformation(expected_prefix_info.clone())];
1415 let serialized = OptionSequenceBuilder::new(options.iter())
1416 .into_serializer()
1417 .serialize_vec_outer()
1418 .unwrap();
1419 let mut expected = [0; 32];
1424 expected[0] = 3;
1425 expected[1] = 4;
1426 (&mut expected[2..]).copy_from_slice(expected_prefix_info.as_bytes());
1427 assert_eq!(serialized.as_ref(), expected);
1428
1429 let parsed = Options::parse(&expected[..]).unwrap();
1430 let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1431 assert_eq!(parsed.len(), 1);
1432 assert_eq!(options::NdpOption::PrefixInformation(&expected_prefix_info), parsed[0]);
1433 }
1434
1435 #[test]
1436 fn parse_serialize_rdnss_option() {
1437 let test = |addrs: &[Ipv6Addr]| {
1438 let lifetime = 120;
1439 let expected_rdnss = options::RecursiveDnsServer::new(lifetime, addrs);
1440 let options = &[options::NdpOptionBuilder::RecursiveDnsServer(expected_rdnss.clone())];
1441 let serialized = OptionSequenceBuilder::new(options.iter())
1442 .into_serializer()
1443 .serialize_vec_outer()
1444 .unwrap();
1445 let mut expected = vec![0; 8 + addrs.len() * usize::from(Ipv6Addr::BYTES)];
1448 (&mut expected[..4]).copy_from_slice(&[
1453 25,
1454 1 + u8::try_from(addrs.len()).unwrap() * 2,
1455 0,
1456 0,
1457 ]);
1458 NetworkEndian::write_u32(&mut expected[4..8], lifetime);
1460 (&mut expected[8..]).copy_from_slice(addrs.as_bytes());
1462 assert_eq!(serialized.as_ref(), expected.as_slice());
1463
1464 let parsed = Options::parse(&expected[..])
1465 .expect("should have parsed a valid recursive dns erver option");
1466 let parsed = parsed.iter().collect::<Vec<options::NdpOption<'_>>>();
1467 assert_eq!(parsed.len(), 1);
1468
1469 assert_eq!(
1471 options::RecursiveDnsServer::parse(&expected[2..]).expect("parsing should succeed"),
1472 expected_rdnss
1473 );
1474
1475 assert_eq!(options::NdpOption::RecursiveDnsServer(expected_rdnss), parsed[0]);
1476 };
1477 test(&[Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])]);
1478 test(&[
1479 Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
1480 Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17]),
1481 ]);
1482 }
1483
1484 #[test]
1485 fn parse_serialize_rdnss_option_error() {
1486 let addrs = [
1487 Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
1488 Ipv6Addr::from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17]),
1489 ];
1490 let lifetime = 120;
1491 let mut buf = vec![0; 8 + addrs.len() * usize::from(Ipv6Addr::BYTES)];
1494 (&mut buf[..4]).copy_from_slice(&[25, 1 + u8::try_from(addrs.len()).unwrap() * 2, 0, 0]);
1499 NetworkEndian::write_u32(&mut buf[4..8], lifetime);
1501 (&mut buf[8..]).copy_from_slice(addrs.as_bytes());
1503
1504 let _parsed = Options::parse(&buf[..])
1506 .expect("should have parsed a valid recursive dns erver option");
1507
1508 let _err = Options::parse(&buf[..8]).expect_err(
1510 "should not have parsed a recursive dns server option that has no addresses",
1511 );
1512
1513 let _err = Options::parse(&buf[..buf.len()-1])
1515 .expect_err("should not have parsed a recursive dns server option that cuts off in the middle of an address");
1516
1517 (&mut buf[8..8 + usize::from(Ipv6Addr::BYTES)])
1519 .copy_from_slice(Ipv6::UNSPECIFIED_ADDRESS.as_bytes());
1520 let _parsed = Options::parse(&buf[..]).expect_err(
1521 "should not have parsed a recursive dns erver option with an unspecified address",
1522 );
1523
1524 (&mut buf[8..8 + usize::from(Ipv6Addr::BYTES)])
1526 .copy_from_slice(Ipv6::ALL_NODES_LINK_LOCAL_MULTICAST_ADDRESS.as_bytes());
1527 let _parsed = Options::parse(&buf[..]).expect_err(
1528 "should not have parsed a recursive dns erver option with a multicast address",
1529 );
1530 }
1531
1532 #[test]
1533 fn parse_neighbor_solicitation() {
1534 use crate::icmp::testdata::ndp_neighbor::*;
1535 let mut buf = SOLICITATION_IP_PACKET_BYTES;
1536 let ip = buf.parse::<Ipv6Packet<_>>().unwrap();
1537 let ipv6_builder = ip.builder();
1538 let (src_ip, dst_ip) = (ip.src_ip(), ip.dst_ip());
1539 let icmp = buf
1540 .parse_with::<_, IcmpPacket<_, _, NeighborSolicitation>>(IcmpParseArgs::new(
1541 src_ip, dst_ip,
1542 ))
1543 .unwrap();
1544
1545 assert_eq!(icmp.message().target_address.ipv6_bytes(), TARGET_ADDRESS);
1546 let collected = icmp.ndp_options().iter().collect::<Vec<options::NdpOption<'_>>>();
1547 for option in collected.iter() {
1548 match option {
1549 options::NdpOption::SourceLinkLayerAddress(address) => {
1550 assert_eq!(address, &SOURCE_LINK_LAYER_ADDRESS);
1551 }
1552 o => panic!("Found unexpected option: {:?}", o),
1553 }
1554 }
1555 let option_builders =
1556 [options::NdpOptionBuilder::SourceLinkLayerAddress(&SOURCE_LINK_LAYER_ADDRESS)];
1557 let serialized = OptionSequenceBuilder::new(option_builders.iter())
1558 .into_serializer()
1559 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
1560 src_ip,
1561 dst_ip,
1562 IcmpZeroCode,
1563 *icmp.message(),
1564 ))
1565 .wrap_in(ipv6_builder)
1566 .serialize_vec_outer()
1567 .unwrap()
1568 .as_ref()
1569 .to_vec();
1570 assert_eq!(&serialized, &SOLICITATION_IP_PACKET_BYTES)
1571 }
1572
1573 #[test]
1574 fn parse_neighbor_advertisement() {
1575 use crate::icmp::testdata::ndp_neighbor::*;
1576 let mut buf = ADVERTISEMENT_IP_PACKET_BYTES;
1577 let ip = buf.parse::<Ipv6Packet<_>>().unwrap();
1578 let ipv6_builder = ip.builder();
1579 let (src_ip, dst_ip) = (ip.src_ip(), ip.dst_ip());
1580 let icmp = buf
1581 .parse_with::<_, IcmpPacket<_, _, NeighborAdvertisement>>(IcmpParseArgs::new(
1582 src_ip, dst_ip,
1583 ))
1584 .unwrap();
1585 assert_eq!(icmp.message().target_address.ipv6_bytes(), TARGET_ADDRESS);
1586 assert_eq!(icmp.ndp_options().iter().count(), 0);
1587
1588 let serialized = EmptyBuf
1589 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
1590 src_ip,
1591 dst_ip,
1592 IcmpZeroCode,
1593 *icmp.message(),
1594 ))
1595 .wrap_in(ipv6_builder)
1596 .serialize_vec_outer()
1597 .unwrap()
1598 .as_ref()
1599 .to_vec();
1600 assert_eq!(&serialized, &ADVERTISEMENT_IP_PACKET_BYTES);
1601 }
1602
1603 #[test]
1604 fn parse_router_advertisement() {
1605 use crate::icmp::ndp::options::RouteInformation;
1606 use crate::icmp::testdata::ndp_router::*;
1607
1608 let mut buf = ADVERTISEMENT_IP_PACKET_BYTES;
1609 let ip = buf.parse::<Ipv6Packet<_>>().unwrap();
1610 let ipv6_builder = ip.builder();
1611 let (src_ip, dst_ip) = (ip.src_ip(), ip.dst_ip());
1612 let icmp = buf
1613 .parse_with::<_, IcmpPacket<_, _, RouterAdvertisement>>(IcmpParseArgs::new(
1614 src_ip, dst_ip,
1615 ))
1616 .unwrap();
1617 assert_eq!(icmp.message().current_hop_limit(), HOP_LIMIT);
1618 assert_eq!(icmp.message().router_lifetime(), LIFETIME);
1619 assert_eq!(icmp.message().reachable_time(), REACHABLE_TIME);
1620 assert_eq!(icmp.message().retransmit_timer(), RETRANS_TIMER);
1621
1622 assert_eq!(icmp.ndp_options().iter().count(), 5);
1623
1624 let collected = icmp.ndp_options().iter().collect::<Vec<options::NdpOption<'_>>>();
1625 for option in collected.iter() {
1626 match option {
1627 options::NdpOption::SourceLinkLayerAddress(address) => {
1628 assert_eq!(address, &SOURCE_LINK_LAYER_ADDRESS);
1629 }
1630 options::NdpOption::PrefixInformation(info) => {
1631 assert_eq!(info.on_link_flag(), PREFIX_INFO_ON_LINK_FLAG);
1632 assert_eq!(
1633 info.autonomous_address_configuration_flag(),
1634 PREFIX_INFO_AUTONOMOUS_ADDRESS_CONFIGURATION_FLAG
1635 );
1636 assert_eq!(
1637 info.valid_lifetime(),
1638 NonZeroNdpLifetime::from_u32_with_infinite(
1639 PREFIX_INFO_VALID_LIFETIME_SECONDS
1640 )
1641 );
1642 assert_eq!(
1643 info.preferred_lifetime(),
1644 NonZeroNdpLifetime::from_u32_with_infinite(
1645 PREFIX_INFO_PREFERRED_LIFETIME_SECONDS
1646 )
1647 );
1648 assert_eq!(info.prefix_length(), PREFIX_INFO_PREFIX.prefix());
1649 assert_eq!(info.prefix(), &PREFIX_INFO_PREFIX.network());
1650 }
1651 options::NdpOption::RouteInformation(_) => {
1652 }
1654 o => panic!("Found unexpected option: {:?}", o),
1655 }
1656 }
1657
1658 let mut route_information_options = collected
1659 .iter()
1660 .filter_map(|o| match o {
1661 options::NdpOption::RouteInformation(info) => Some(info),
1662 _ => None,
1663 })
1664 .collect::<Vec<&RouteInformation>>();
1665 route_information_options.sort_by_key(|o| o.prefix().prefix());
1670 assert_eq!(
1671 route_information_options,
1672 [
1673 &options::RouteInformation::new(
1674 ROUTE_INFO_LOW_PREF_PREFIX,
1675 ROUTE_INFO_LOW_PREF_VALID_LIFETIME_SECONDS,
1676 ROUTE_INFO_LOW_PREF,
1677 ),
1678 &options::RouteInformation::new(
1679 ROUTE_INFO_MEDIUM_PREF_PREFIX,
1680 ROUTE_INFO_MEDIUM_PREF_VALID_LIFETIME_SECONDS,
1681 ROUTE_INFO_MEDIUM_PREF,
1682 ),
1683 &options::RouteInformation::new(
1684 ROUTE_INFO_HIGH_PREF_PREFIX,
1685 ROUTE_INFO_HIGH_PREF_VALID_LIFETIME_SECONDS,
1686 ROUTE_INFO_HIGH_PREF,
1687 )
1688 ]
1689 );
1690
1691 let option_builders = [
1692 options::NdpOptionBuilder::SourceLinkLayerAddress(&SOURCE_LINK_LAYER_ADDRESS),
1693 options::NdpOptionBuilder::PrefixInformation(options::PrefixInformation::new(
1694 PREFIX_INFO_PREFIX.prefix(),
1695 PREFIX_INFO_ON_LINK_FLAG,
1696 PREFIX_INFO_AUTONOMOUS_ADDRESS_CONFIGURATION_FLAG,
1697 PREFIX_INFO_VALID_LIFETIME_SECONDS,
1698 PREFIX_INFO_PREFERRED_LIFETIME_SECONDS,
1699 PREFIX_INFO_PREFIX.network(),
1700 )),
1701 options::NdpOptionBuilder::RouteInformation(options::RouteInformation::new(
1702 ROUTE_INFO_HIGH_PREF_PREFIX,
1703 ROUTE_INFO_HIGH_PREF_VALID_LIFETIME_SECONDS,
1704 ROUTE_INFO_HIGH_PREF,
1705 )),
1706 options::NdpOptionBuilder::RouteInformation(options::RouteInformation::new(
1707 ROUTE_INFO_MEDIUM_PREF_PREFIX,
1708 ROUTE_INFO_MEDIUM_PREF_VALID_LIFETIME_SECONDS,
1709 ROUTE_INFO_MEDIUM_PREF,
1710 )),
1711 options::NdpOptionBuilder::RouteInformation(options::RouteInformation::new(
1712 ROUTE_INFO_LOW_PREF_PREFIX,
1713 ROUTE_INFO_LOW_PREF_VALID_LIFETIME_SECONDS,
1714 ROUTE_INFO_LOW_PREF,
1715 )),
1716 ];
1717 let serialized = OptionSequenceBuilder::new(option_builders.iter())
1718 .into_serializer()
1719 .wrap_in(IcmpPacketBuilder::<Ipv6, _>::new(
1720 src_ip,
1721 dst_ip,
1722 IcmpZeroCode,
1723 *icmp.message(),
1724 ))
1725 .wrap_in(ipv6_builder)
1726 .serialize_vec_outer()
1727 .unwrap()
1728 .as_ref()
1729 .to_vec();
1730 assert_eq!(&serialized, &ADVERTISEMENT_IP_PACKET_BYTES);
1731 }
1732
1733 struct SerializeRATest {
1734 hop_limit: u8,
1735 managed_flag: bool,
1736 other_config_flag: bool,
1737 preference: RoutePreference,
1738 router_lifetime_seconds: u16,
1739 reachable_time_seconds: u32,
1740 retransmit_timer_seconds: u32,
1741 }
1742
1743 #[test_case(
1744 SerializeRATest{
1745 hop_limit: 1,
1746 managed_flag: true,
1747 other_config_flag: false,
1748 preference: RoutePreference::High,
1749 router_lifetime_seconds: 1_000,
1750 reachable_time_seconds: 1_000_000,
1751 retransmit_timer_seconds: 5,
1752 }; "test_1")]
1753 #[test_case(
1754 SerializeRATest{
1755 hop_limit: 64,
1756 managed_flag: false,
1757 other_config_flag: true,
1758 preference: RoutePreference::Low,
1759 router_lifetime_seconds: 5,
1760 reachable_time_seconds: 23425621,
1761 retransmit_timer_seconds: 13252521,
1762 }; "test_2")]
1763 fn serialize_router_advertisement(test: SerializeRATest) {
1764 let SerializeRATest {
1765 hop_limit,
1766 managed_flag,
1767 other_config_flag,
1768 preference,
1769 router_lifetime_seconds,
1770 reachable_time_seconds,
1771 retransmit_timer_seconds,
1772 } = test;
1773
1774 const SRC_IP: Ipv6Addr =
1775 Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
1776 const DST_IP: Ipv6Addr =
1777 Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17]);
1778 let icmp = IcmpPacketBuilder::<Ipv6, _>::new(
1779 SRC_IP,
1780 DST_IP,
1781 IcmpZeroCode,
1782 RouterAdvertisement::with_prf(
1783 hop_limit,
1784 managed_flag,
1785 other_config_flag,
1786 preference,
1787 router_lifetime_seconds,
1788 reachable_time_seconds,
1789 retransmit_timer_seconds,
1790 ),
1791 );
1792 let serialized = icmp.wrap_body(EmptyBuf).serialize_vec_outer().unwrap();
1793
1794 const RA_LEN: u32 = 16;
1816 let mut expected = [0; RA_LEN as usize];
1817 expected[0] = 134;
1818 expected[4] = hop_limit;
1819 if managed_flag {
1820 expected[5] |= 1 << 7;
1821 }
1822 if other_config_flag {
1823 expected[5] |= 1 << 6;
1824 }
1825 expected[5] |= u8::from(preference) << 3;
1826 let (mut router_lifetime, _rest) = Ref::<_, U16>::from_prefix(&mut expected[6..]).unwrap();
1827 router_lifetime.set(router_lifetime_seconds);
1828 let (mut reachable_time, _rest) = Ref::<_, U32>::from_prefix(&mut expected[8..]).unwrap();
1829 reachable_time.set(reachable_time_seconds);
1830 let (mut retransmit_timer, _rest) =
1831 Ref::<_, U32>::from_prefix(&mut expected[12..]).unwrap();
1832 retransmit_timer.set(retransmit_timer_seconds);
1833
1834 let mut c = internet_checksum::Checksum::new();
1835 c.add_bytes(SRC_IP.bytes());
1837 c.add_bytes(DST_IP.bytes());
1838 c.add_bytes(U32::new(RA_LEN).as_bytes());
1839 c.add_bytes(&[0, crate::ip::Ipv6Proto::Icmpv6.into()]);
1840 c.add_bytes(&expected[..]);
1842 expected[2..4].copy_from_slice(&c.checksum()[..]);
1843
1844 assert_eq!(serialized.as_ref(), &expected[..]);
1845 }
1846
1847 struct SerializeRioTest {
1848 prefix_length: u8,
1849 route_lifetime_seconds: u32,
1850 preference: RoutePreference,
1851 expected_option_length: u8,
1852 }
1853
1854 #[test_case(
1864 SerializeRioTest{
1865 prefix_length: 0,
1866 route_lifetime_seconds: 1,
1867 preference: RoutePreference::High,
1868 expected_option_length: 8,
1869 }; "prefix_length_0")]
1870 #[test_case(
1871 SerializeRioTest{
1872 prefix_length: 1,
1873 route_lifetime_seconds: 1000,
1874 preference: RoutePreference::Medium,
1875 expected_option_length: 16,
1876 }; "prefix_length_1")]
1877 #[test_case(
1878 SerializeRioTest{
1879 prefix_length: 64,
1880 route_lifetime_seconds: 100000,
1881 preference: RoutePreference::Low,
1882 expected_option_length: 16,
1883 }; "prefix_length_64")]
1884 #[test_case(
1885 SerializeRioTest{
1886 prefix_length: 65,
1887 route_lifetime_seconds: 1000000,
1888 preference: RoutePreference::Medium,
1889 expected_option_length: 24,
1890 }; "prefix_length_65")]
1891 #[test_case(
1892 SerializeRioTest{
1893 prefix_length: 128,
1894 route_lifetime_seconds: 10000000,
1895 preference: RoutePreference::Medium,
1896 expected_option_length: 24,
1897 }; "prefix_length_128")]
1898 fn serialize_route_information_option(test: SerializeRioTest) {
1899 const IPV6ADDR: Ipv6Addr =
1900 Ipv6Addr::new([0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
1901
1902 let SerializeRioTest {
1903 prefix_length,
1904 route_lifetime_seconds,
1905 preference,
1906 expected_option_length,
1907 } = test;
1908 let prefix = IPV6ADDR.mask(prefix_length);
1909
1910 let option_builders =
1911 [options::NdpOptionBuilder::RouteInformation(options::RouteInformation::new(
1912 Subnet::new(prefix, prefix_length).unwrap(),
1913 route_lifetime_seconds,
1914 preference,
1915 ))];
1916
1917 let serialized = OptionSequenceBuilder::new(option_builders.iter())
1918 .into_serializer()
1919 .serialize_vec_outer()
1920 .unwrap();
1921
1922 let mut expected = [0; 24];
1950 expected[0] = 24;
1951 expected[1] = expected_option_length / 8;
1952 expected[2] = prefix_length;
1953 expected[3] = u8::from(preference) << 3;
1954 let (mut lifetime_seconds, _rest) = Ref::<_, U32>::from_prefix(&mut expected[4..]).unwrap();
1955 lifetime_seconds.set(route_lifetime_seconds);
1956 expected[8..].copy_from_slice(prefix.bytes());
1957
1958 assert_eq!(serialized.as_ref(), &expected[..expected_option_length.into()]);
1959 }
1960
1961 #[test_case(0, None)]
1962 #[test_case(
1963 1,
1964 Some(NonZeroNdpLifetime::Finite(NonZeroDuration::new(
1965 Duration::from_secs(1),
1966 ).unwrap()))
1967 )]
1968 #[test_case(
1969 u32::MAX - 1,
1970 Some(NonZeroNdpLifetime::Finite(NonZeroDuration::new(
1971 Duration::from_secs(u64::from(u32::MAX) - 1),
1972 ).unwrap()))
1973 )]
1974 #[test_case(u32::MAX, Some(NonZeroNdpLifetime::Infinite))]
1975 fn non_zero_ndp_lifetime_non_zero_or_max_u32_from_u32_with_infinite(
1976 t: u32,
1977 expected: Option<NonZeroNdpLifetime>,
1978 ) {
1979 assert_eq!(NonZeroNdpLifetime::from_u32_with_infinite(t), expected)
1980 }
1981
1982 const MIN_NON_ZERO_DURATION: Duration = Duration::new(0, 1);
1983 #[test_case(
1984 NonZeroNdpLifetime::Infinite,
1985 NonZeroDuration::new(MIN_NON_ZERO_DURATION).unwrap(),
1986 NonZeroDuration::new(MIN_NON_ZERO_DURATION).unwrap()
1987 )]
1988 #[test_case(
1989 NonZeroNdpLifetime::Infinite,
1990 NonZeroDuration::new(Duration::MAX).unwrap(),
1991 NonZeroDuration::new(Duration::MAX).unwrap()
1992 )]
1993 #[test_case(
1994 NonZeroNdpLifetime::Finite(NonZeroDuration::new(
1995 Duration::from_secs(2)).unwrap()
1996 ),
1997 NonZeroDuration::new(Duration::from_secs(1)).unwrap(),
1998 NonZeroDuration::new(Duration::from_secs(1)).unwrap()
1999 )]
2000 #[test_case(
2001 NonZeroNdpLifetime::Finite(NonZeroDuration::new(
2002 Duration::from_secs(3)).unwrap()
2003 ),
2004 NonZeroDuration::new(Duration::from_secs(4)).unwrap(),
2005 NonZeroDuration::new(Duration::from_secs(3)).unwrap()
2006 )]
2007 fn non_zero_ndp_lifetime_min_finite_duration(
2008 lifetime: NonZeroNdpLifetime,
2009 duration: NonZeroDuration,
2010 expected: NonZeroDuration,
2011 ) {
2012 assert_eq!(lifetime.min_finite_duration(duration), expected)
2013 }
2014}