1#![deny(missing_docs)]
2
3use byteorder::{ByteOrder, NetworkEndian};
4use core::fmt;
5
6use super::{Error, Result};
7use crate::wire::ip::pretty_print_ip_payload;
8
9pub use super::IpProtocol as Protocol;
10
11pub const MIN_MTU: usize = 1280;
15
16pub const ADDR_SIZE: usize = 16;
20
21pub const LINK_LOCAL_ALL_NODES: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1);
25
26pub const LINK_LOCAL_ALL_ROUTERS: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 2);
30
31pub const LINK_LOCAL_ALL_MLDV2_ROUTERS: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x16);
35
36pub const LINK_LOCAL_ALL_RPL_NODES: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x1a);
40
41#[repr(u8)]
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub(crate) enum MulticastScope {
47 InterfaceLocal = 0x1,
49 LinkLocal = 0x2,
51 AdminLocal = 0x4,
53 SiteLocal = 0x5,
55 OrganizationLocal = 0x8,
57 Global = 0xE,
59 Unknown = 0xFF,
61}
62
63impl From<u8> for MulticastScope {
64 fn from(value: u8) -> Self {
65 match value {
66 0x1 => Self::InterfaceLocal,
67 0x2 => Self::LinkLocal,
68 0x4 => Self::AdminLocal,
69 0x5 => Self::SiteLocal,
70 0x8 => Self::OrganizationLocal,
71 0xE => Self::Global,
72 _ => Self::Unknown,
73 }
74 }
75}
76
77pub use core::net::Ipv6Addr as Address;
78
79pub(crate) trait AddressExt {
80 fn from_bytes(data: &[u8]) -> Address;
85
86 fn x_is_unicast(&self) -> bool;
92
93 fn is_global_unicast(&self) -> bool;
97
98 fn is_link_local(&self) -> bool;
102
103 fn x_is_unique_local(&self) -> bool;
109
110 fn mask(&self, mask: u8) -> [u8; ADDR_SIZE];
115
116 fn solicited_node(&self) -> Address;
122
123 fn x_multicast_scope(&self) -> MulticastScope;
127
128 fn is_solicited_node_multicast(&self) -> bool;
132
133 fn prefix_len(&self) -> Option<u8>;
136}
137
138impl AddressExt for Address {
139 fn from_bytes(data: &[u8]) -> Address {
140 let mut bytes = [0; ADDR_SIZE];
141 bytes.copy_from_slice(data);
142 Address::from(bytes)
143 }
144
145 fn x_is_unicast(&self) -> bool {
146 !(self.is_multicast() || self.is_unspecified())
147 }
148
149 fn is_global_unicast(&self) -> bool {
150 (self.octets()[0] >> 5) == 0b001
151 }
152
153 fn is_link_local(&self) -> bool {
154 self.octets()[0..8] == [0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
155 }
156
157 fn x_is_unique_local(&self) -> bool {
158 (self.octets()[0] & 0b1111_1110) == 0xfc
159 }
160
161 fn mask(&self, mask: u8) -> [u8; ADDR_SIZE] {
162 assert!(mask <= 128);
163 let mut bytes = [0u8; ADDR_SIZE];
164 let idx = (mask as usize) / 8;
165 let modulus = (mask as usize) % 8;
166 let octets = self.octets();
167 let (first, second) = octets.split_at(idx);
168 bytes[0..idx].copy_from_slice(first);
169 if idx < ADDR_SIZE {
170 let part = second[0];
171 bytes[idx] = part & (!(0xff >> modulus) as u8);
172 }
173 bytes
174 }
175
176 fn solicited_node(&self) -> Address {
177 assert!(self.x_is_unicast());
178 let o = self.octets();
179 Address::from([
180 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, o[13],
181 o[14], o[15],
182 ])
183 }
184
185 fn x_multicast_scope(&self) -> MulticastScope {
186 if self.is_multicast() {
187 return MulticastScope::from(self.octets()[1] & 0b1111);
188 }
189
190 if self.is_link_local() {
191 MulticastScope::LinkLocal
192 } else if self.x_is_unique_local() || self.is_global_unicast() {
193 MulticastScope::Global
196 } else {
197 MulticastScope::Unknown
198 }
199 }
200
201 fn is_solicited_node_multicast(&self) -> bool {
202 self.octets()[0..13]
203 == [
204 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF,
205 ]
206 }
207
208 fn prefix_len(&self) -> Option<u8> {
209 let mut ones = true;
210 let mut prefix_len = 0;
211 for byte in self.octets() {
212 let mut mask = 0x80;
213 for _ in 0..8 {
214 let one = byte & mask != 0;
215 if ones {
216 if one {
218 prefix_len += 1;
219 } else {
220 ones = false;
221 }
222 } else if one {
223 return None;
225 }
226 mask >>= 1;
227 }
228 }
229 Some(prefix_len)
230 }
231}
232
233#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
236pub struct Cidr {
237 address: Address,
238 prefix_len: u8,
239}
240
241impl Cidr {
242 pub const SOLICITED_NODE_PREFIX: Cidr = Cidr {
246 address: Address::new(0xff02, 0, 0, 0, 0, 1, 0xff00, 0),
247 prefix_len: 104,
248 };
249
250 pub const fn new(address: Address, prefix_len: u8) -> Cidr {
255 assert!(prefix_len <= 128);
256 Cidr {
257 address,
258 prefix_len,
259 }
260 }
261
262 pub const fn address(&self) -> Address {
264 self.address
265 }
266
267 pub const fn prefix_len(&self) -> u8 {
269 self.prefix_len
270 }
271
272 pub fn contains_addr(&self, addr: &Address) -> bool {
275 if self.prefix_len == 0 {
277 return true;
278 }
279
280 self.address.mask(self.prefix_len) == addr.mask(self.prefix_len)
281 }
282
283 pub fn contains_subnet(&self, subnet: &Cidr) -> bool {
286 self.prefix_len <= subnet.prefix_len && self.contains_addr(&subnet.address)
287 }
288}
289
290impl fmt::Display for Cidr {
291 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
292 write!(f, "{}/{}", self.address, self.prefix_len)
294 }
295}
296
297#[cfg(feature = "defmt")]
298impl defmt::Format for Cidr {
299 fn format(&self, f: defmt::Formatter) {
300 defmt::write!(f, "{}/{=u8}", self.address, self.prefix_len);
301 }
302}
303
304#[derive(Debug, PartialEq, Eq, Clone)]
306#[cfg_attr(feature = "defmt", derive(defmt::Format))]
307pub struct Packet<T: AsRef<[u8]>> {
308 buffer: T,
309}
310
311mod field {
337 use crate::wire::field::*;
338 pub const VER_TC_FLOW: Field = 0..4;
341 pub const LENGTH: Field = 4..6;
344 pub const NXT_HDR: usize = 6;
347 pub const HOP_LIMIT: usize = 7;
350 pub const SRC_ADDR: Field = 8..24;
352 pub const DST_ADDR: Field = 24..40;
354}
355
356pub const HEADER_LEN: usize = field::DST_ADDR.end;
358
359impl<T: AsRef<[u8]>> Packet<T> {
360 #[inline]
362 pub const fn new_unchecked(buffer: T) -> Packet<T> {
363 Packet { buffer }
364 }
365
366 #[inline]
371 pub fn new_checked(buffer: T) -> Result<Packet<T>> {
372 let packet = Self::new_unchecked(buffer);
373 packet.check_len()?;
374 Ok(packet)
375 }
376
377 #[inline]
384 pub fn check_len(&self) -> Result<()> {
385 let len = self.buffer.as_ref().len();
386 if len < field::DST_ADDR.end || len < self.total_len() {
387 Err(Error)
388 } else {
389 Ok(())
390 }
391 }
392
393 #[inline]
395 pub fn into_inner(self) -> T {
396 self.buffer
397 }
398
399 #[inline]
401 pub const fn header_len(&self) -> usize {
402 field::DST_ADDR.end
405 }
406
407 #[inline]
409 pub fn version(&self) -> u8 {
410 let data = self.buffer.as_ref();
411 data[field::VER_TC_FLOW.start] >> 4
412 }
413
414 #[inline]
416 pub fn traffic_class(&self) -> u8 {
417 let data = self.buffer.as_ref();
418 ((NetworkEndian::read_u16(&data[0..2]) & 0x0ff0) >> 4) as u8
419 }
420
421 #[inline]
423 pub fn flow_label(&self) -> u32 {
424 let data = self.buffer.as_ref();
425 NetworkEndian::read_u24(&data[1..4]) & 0x000fffff
426 }
427
428 #[inline]
430 pub fn payload_len(&self) -> u16 {
431 let data = self.buffer.as_ref();
432 NetworkEndian::read_u16(&data[field::LENGTH])
433 }
434
435 #[inline]
437 pub fn total_len(&self) -> usize {
438 self.header_len() + self.payload_len() as usize
439 }
440
441 #[inline]
443 pub fn next_header(&self) -> Protocol {
444 let data = self.buffer.as_ref();
445 Protocol::from(data[field::NXT_HDR])
446 }
447
448 #[inline]
450 pub fn hop_limit(&self) -> u8 {
451 let data = self.buffer.as_ref();
452 data[field::HOP_LIMIT]
453 }
454
455 #[inline]
457 pub fn src_addr(&self) -> Address {
458 let data = self.buffer.as_ref();
459 Address::from_bytes(&data[field::SRC_ADDR])
460 }
461
462 #[inline]
464 pub fn dst_addr(&self) -> Address {
465 let data = self.buffer.as_ref();
466 Address::from_bytes(&data[field::DST_ADDR])
467 }
468}
469
470impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
471 #[inline]
473 pub fn payload(&self) -> &'a [u8] {
474 let data = self.buffer.as_ref();
475 let range = self.header_len()..self.total_len();
476 &data[range]
477 }
478}
479
480impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
481 #[inline]
483 pub fn set_version(&mut self, value: u8) {
484 let data = self.buffer.as_mut();
485 data[0] = (data[0] & 0x0f) | ((value & 0x0f) << 4);
488 }
489
490 #[inline]
492 pub fn set_traffic_class(&mut self, value: u8) {
493 let data = self.buffer.as_mut();
494 data[0] = (data[0] & 0xf0) | ((value & 0xf0) >> 4);
497 data[1] = (data[1] & 0x0f) | ((value & 0x0f) << 4);
500 }
501
502 #[inline]
504 pub fn set_flow_label(&mut self, value: u32) {
505 let data = self.buffer.as_mut();
506 let raw = (((data[1] & 0xf0) as u32) << 16) | (value & 0x0fffff);
508 NetworkEndian::write_u24(&mut data[1..4], raw);
509 }
510
511 #[inline]
513 pub fn set_payload_len(&mut self, value: u16) {
514 let data = self.buffer.as_mut();
515 NetworkEndian::write_u16(&mut data[field::LENGTH], value);
516 }
517
518 #[inline]
520 pub fn set_next_header(&mut self, value: Protocol) {
521 let data = self.buffer.as_mut();
522 data[field::NXT_HDR] = value.into();
523 }
524
525 #[inline]
527 pub fn set_hop_limit(&mut self, value: u8) {
528 let data = self.buffer.as_mut();
529 data[field::HOP_LIMIT] = value;
530 }
531
532 #[inline]
534 pub fn set_src_addr(&mut self, value: Address) {
535 let data = self.buffer.as_mut();
536 data[field::SRC_ADDR].copy_from_slice(&value.octets());
537 }
538
539 #[inline]
541 pub fn set_dst_addr(&mut self, value: Address) {
542 let data = self.buffer.as_mut();
543 data[field::DST_ADDR].copy_from_slice(&value.octets());
544 }
545
546 #[inline]
548 pub fn payload_mut(&mut self) -> &mut [u8] {
549 let range = self.header_len()..self.total_len();
550 let data = self.buffer.as_mut();
551 &mut data[range]
552 }
553}
554
555impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
556 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
557 match Repr::parse(self) {
558 Ok(repr) => write!(f, "{repr}"),
559 Err(err) => {
560 write!(f, "IPv6 ({err})")?;
561 Ok(())
562 }
563 }
564 }
565}
566
567impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> {
568 fn as_ref(&self) -> &[u8] {
569 self.buffer.as_ref()
570 }
571}
572
573#[derive(Debug, PartialEq, Eq, Clone, Copy)]
575pub struct Repr {
576 pub src_addr: Address,
578 pub dst_addr: Address,
580 pub next_header: Protocol,
582 pub payload_len: usize,
584 pub hop_limit: u8,
586}
587
588impl Repr {
589 pub fn parse<T: AsRef<[u8]> + ?Sized>(packet: &Packet<&T>) -> Result<Repr> {
591 packet.check_len()?;
593 if packet.version() != 6 {
594 return Err(Error);
595 }
596 Ok(Repr {
597 src_addr: packet.src_addr(),
598 dst_addr: packet.dst_addr(),
599 next_header: packet.next_header(),
600 payload_len: packet.payload_len() as usize,
601 hop_limit: packet.hop_limit(),
602 })
603 }
604
605 pub const fn buffer_len(&self) -> usize {
607 field::DST_ADDR.end
609 }
610
611 pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) {
613 packet.set_version(6);
616 packet.set_traffic_class(0);
617 packet.set_flow_label(0);
618 packet.set_payload_len(self.payload_len as u16);
619 packet.set_hop_limit(self.hop_limit);
620 packet.set_next_header(self.next_header);
621 packet.set_src_addr(self.src_addr);
622 packet.set_dst_addr(self.dst_addr);
623 }
624}
625
626impl fmt::Display for Repr {
627 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
628 write!(
629 f,
630 "IPv6 src={} dst={} nxt_hdr={} hop_limit={}",
631 self.src_addr, self.dst_addr, self.next_header, self.hop_limit
632 )
633 }
634}
635
636#[cfg(feature = "defmt")]
637impl defmt::Format for Repr {
638 fn format(&self, fmt: defmt::Formatter) {
639 defmt::write!(
640 fmt,
641 "IPv6 src={} dst={} nxt_hdr={} hop_limit={}",
642 self.src_addr,
643 self.dst_addr,
644 self.next_header,
645 self.hop_limit
646 )
647 }
648}
649
650use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
651
652impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
655 fn pretty_print(
656 buffer: &dyn AsRef<[u8]>,
657 f: &mut fmt::Formatter,
658 indent: &mut PrettyIndent,
659 ) -> fmt::Result {
660 let (ip_repr, payload) = match Packet::new_checked(buffer) {
661 Err(err) => return write!(f, "{indent}({err})"),
662 Ok(ip_packet) => match Repr::parse(&ip_packet) {
663 Err(_) => return Ok(()),
664 Ok(ip_repr) => {
665 write!(f, "{indent}{ip_repr}")?;
666 (ip_repr, ip_packet.payload())
667 }
668 },
669 };
670
671 pretty_print_ip_payload(f, indent, ip_repr, payload)
672 }
673}
674
675#[cfg(test)]
676pub(crate) mod test {
677 use super::*;
678 use crate::wire::pretty_print::PrettyPrinter;
679
680 #[allow(unused)]
681 pub(crate) const MOCK_IP_ADDR_1: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
682 #[allow(unused)]
683 pub(crate) const MOCK_IP_ADDR_2: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 2);
684 #[allow(unused)]
685 pub(crate) const MOCK_IP_ADDR_3: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 3);
686 #[allow(unused)]
687 pub(crate) const MOCK_IP_ADDR_4: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 4);
688 #[allow(unused)]
689 pub(crate) const MOCK_UNSPECIFIED: Address = Address::UNSPECIFIED;
690
691 const LINK_LOCAL_ADDR: Address = Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1);
692 const UNIQUE_LOCAL_ADDR: Address = Address::new(0xfd00, 0, 0, 201, 1, 1, 1, 1);
693 const GLOBAL_UNICAST_ADDR: Address = Address::new(0x2001, 0xdb8, 0x3, 0, 0, 0, 0, 1);
694
695 const TEST_SOL_NODE_MCAST_ADDR: Address = Address::new(0xff02, 0, 0, 0, 0, 1, 0xff01, 101);
696
697 #[test]
698 fn test_basic_multicast() {
699 assert!(!LINK_LOCAL_ALL_ROUTERS.is_unspecified());
700 assert!(LINK_LOCAL_ALL_ROUTERS.is_multicast());
701 assert!(!LINK_LOCAL_ALL_ROUTERS.is_link_local());
702 assert!(!LINK_LOCAL_ALL_ROUTERS.is_loopback());
703 assert!(!LINK_LOCAL_ALL_ROUTERS.x_is_unique_local());
704 assert!(!LINK_LOCAL_ALL_ROUTERS.is_global_unicast());
705 assert!(!LINK_LOCAL_ALL_ROUTERS.is_solicited_node_multicast());
706 assert!(!LINK_LOCAL_ALL_NODES.is_unspecified());
707 assert!(LINK_LOCAL_ALL_NODES.is_multicast());
708 assert!(!LINK_LOCAL_ALL_NODES.is_link_local());
709 assert!(!LINK_LOCAL_ALL_NODES.is_loopback());
710 assert!(!LINK_LOCAL_ALL_NODES.x_is_unique_local());
711 assert!(!LINK_LOCAL_ALL_NODES.is_global_unicast());
712 assert!(!LINK_LOCAL_ALL_NODES.is_solicited_node_multicast());
713 }
714
715 #[test]
716 fn test_basic_link_local() {
717 assert!(!LINK_LOCAL_ADDR.is_unspecified());
718 assert!(!LINK_LOCAL_ADDR.is_multicast());
719 assert!(LINK_LOCAL_ADDR.is_link_local());
720 assert!(!LINK_LOCAL_ADDR.is_loopback());
721 assert!(!LINK_LOCAL_ADDR.x_is_unique_local());
722 assert!(!LINK_LOCAL_ADDR.is_global_unicast());
723 assert!(!LINK_LOCAL_ADDR.is_solicited_node_multicast());
724 }
725
726 #[test]
727 fn test_basic_loopback() {
728 assert!(!Address::LOCALHOST.is_unspecified());
729 assert!(!Address::LOCALHOST.is_multicast());
730 assert!(!Address::LOCALHOST.is_link_local());
731 assert!(Address::LOCALHOST.is_loopback());
732 assert!(!Address::LOCALHOST.x_is_unique_local());
733 assert!(!Address::LOCALHOST.is_global_unicast());
734 assert!(!Address::LOCALHOST.is_solicited_node_multicast());
735 }
736
737 #[test]
738 fn test_unique_local() {
739 assert!(!UNIQUE_LOCAL_ADDR.is_unspecified());
740 assert!(!UNIQUE_LOCAL_ADDR.is_multicast());
741 assert!(!UNIQUE_LOCAL_ADDR.is_link_local());
742 assert!(!UNIQUE_LOCAL_ADDR.is_loopback());
743 assert!(UNIQUE_LOCAL_ADDR.x_is_unique_local());
744 assert!(!UNIQUE_LOCAL_ADDR.is_global_unicast());
745 assert!(!UNIQUE_LOCAL_ADDR.is_solicited_node_multicast());
746 }
747
748 #[test]
749 fn test_global_unicast() {
750 assert!(!GLOBAL_UNICAST_ADDR.is_unspecified());
751 assert!(!GLOBAL_UNICAST_ADDR.is_multicast());
752 assert!(!GLOBAL_UNICAST_ADDR.is_link_local());
753 assert!(!GLOBAL_UNICAST_ADDR.is_loopback());
754 assert!(!GLOBAL_UNICAST_ADDR.x_is_unique_local());
755 assert!(GLOBAL_UNICAST_ADDR.is_global_unicast());
756 assert!(!GLOBAL_UNICAST_ADDR.is_solicited_node_multicast());
757 }
758
759 #[test]
760 fn test_sollicited_node_multicast() {
761 assert!(!TEST_SOL_NODE_MCAST_ADDR.is_unspecified());
762 assert!(TEST_SOL_NODE_MCAST_ADDR.is_multicast());
763 assert!(!TEST_SOL_NODE_MCAST_ADDR.is_link_local());
764 assert!(!TEST_SOL_NODE_MCAST_ADDR.is_loopback());
765 assert!(!TEST_SOL_NODE_MCAST_ADDR.x_is_unique_local());
766 assert!(!TEST_SOL_NODE_MCAST_ADDR.is_global_unicast());
767 assert!(TEST_SOL_NODE_MCAST_ADDR.is_solicited_node_multicast());
768 }
769
770 #[test]
771 fn test_mask() {
772 let addr = Address::new(0x0123, 0x4567, 0x89ab, 0, 0, 0, 0, 1);
773 assert_eq!(
774 addr.mask(11),
775 [0x01, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
776 );
777 assert_eq!(
778 addr.mask(15),
779 [0x01, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
780 );
781 assert_eq!(
782 addr.mask(26),
783 [0x01, 0x23, 0x45, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
784 );
785 assert_eq!(
786 addr.mask(128),
787 [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
788 );
789 assert_eq!(
790 addr.mask(127),
791 [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
792 );
793 }
794
795 #[test]
796 fn test_cidr() {
797 let cidr = Cidr::new(LINK_LOCAL_ADDR, 56);
801
802 let inside_subnet = [
803 [
805 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
806 0x00, 0x02,
807 ],
808 [
810 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
811 0x77, 0x88,
812 ],
813 [
815 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
816 0x00, 0x00,
817 ],
818 [
820 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
821 0x00, 0xff,
822 ],
823 ];
824
825 let outside_subnet = [
826 [
828 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
829 0x00, 0x01,
830 ],
831 [
833 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
834 0x00, 0x01,
835 ],
836 [
838 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
839 0x00, 0x01,
840 ],
841 [
843 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
844 0x00, 0x02,
845 ],
846 ];
847
848 let subnets = [
849 (
851 [
852 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
853 0xff, 0xff, 0xff,
854 ],
855 65,
856 ),
857 (
859 [
860 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
861 0x00, 0x00, 0x01,
862 ],
863 128,
864 ),
865 (
867 [
868 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
869 0x34, 0x56, 0x78,
870 ],
871 96,
872 ),
873 ];
874
875 let not_subnets = [
876 (
878 [
879 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
880 0xff, 0xff, 0xff,
881 ],
882 55,
883 ),
884 (
886 [
887 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
888 0xff, 0xff, 0xff,
889 ],
890 56,
891 ),
892 (
894 [
895 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
896 0xff, 0xff, 0xff,
897 ],
898 57,
899 ),
900 (
902 [
903 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
904 0x00, 0x00, 0x01,
905 ],
906 128,
907 ),
908 ];
909
910 for addr in inside_subnet.iter().map(|a| Address::from_bytes(a)) {
911 assert!(cidr.contains_addr(&addr));
912 }
913
914 for addr in outside_subnet.iter().map(|a| Address::from_bytes(a)) {
915 assert!(!cidr.contains_addr(&addr));
916 }
917
918 for subnet in subnets.iter().map(|&(a, p)| Cidr::new(Address::from(a), p)) {
919 assert!(cidr.contains_subnet(&subnet));
920 }
921
922 for subnet in not_subnets
923 .iter()
924 .map(|&(a, p)| Cidr::new(Address::from(a), p))
925 {
926 assert!(!cidr.contains_subnet(&subnet));
927 }
928
929 let cidr_without_prefix = Cidr::new(LINK_LOCAL_ADDR, 0);
930 assert!(cidr_without_prefix.contains_addr(&Address::LOCALHOST));
931 }
932
933 #[test]
934 #[should_panic(expected = "length")]
935 fn test_from_bytes_too_long() {
936 let _ = Address::from_bytes(&[0u8; 15]);
937 }
938
939 #[test]
940 fn test_scope() {
941 use super::*;
942 assert_eq!(
943 Address::new(0xff01, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
944 MulticastScope::InterfaceLocal
945 );
946 assert_eq!(
947 Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
948 MulticastScope::LinkLocal
949 );
950 assert_eq!(
951 Address::new(0xff03, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
952 MulticastScope::Unknown
953 );
954 assert_eq!(
955 Address::new(0xff04, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
956 MulticastScope::AdminLocal
957 );
958 assert_eq!(
959 Address::new(0xff05, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
960 MulticastScope::SiteLocal
961 );
962 assert_eq!(
963 Address::new(0xff08, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
964 MulticastScope::OrganizationLocal
965 );
966 assert_eq!(
967 Address::new(0xff0e, 0, 0, 0, 0, 0, 0, 1).x_multicast_scope(),
968 MulticastScope::Global
969 );
970
971 assert_eq!(
972 LINK_LOCAL_ALL_NODES.x_multicast_scope(),
973 MulticastScope::LinkLocal
974 );
975
976 assert_eq!(
978 LINK_LOCAL_ADDR.x_multicast_scope(),
979 MulticastScope::LinkLocal
980 );
981 assert_eq!(
982 GLOBAL_UNICAST_ADDR.x_multicast_scope(),
983 MulticastScope::Global
984 );
985 assert_eq!(
986 UNIQUE_LOCAL_ADDR.x_multicast_scope(),
987 MulticastScope::Global
988 );
989 }
990
991 static REPR_PACKET_BYTES: [u8; 52] = [
992 0x60, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x11, 0x40, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
993 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00,
994 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00,
995 0x0c, 0x02, 0x4e, 0xff, 0xff, 0xff, 0xff,
996 ];
997 static REPR_PAYLOAD_BYTES: [u8; 12] = [
998 0x00, 0x01, 0x00, 0x02, 0x00, 0x0c, 0x02, 0x4e, 0xff, 0xff, 0xff, 0xff,
999 ];
1000
1001 const fn packet_repr() -> Repr {
1002 Repr {
1003 src_addr: Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
1004 dst_addr: LINK_LOCAL_ALL_NODES,
1005 next_header: Protocol::Udp,
1006 payload_len: 12,
1007 hop_limit: 64,
1008 }
1009 }
1010
1011 #[test]
1012 fn test_packet_deconstruction() {
1013 let packet = Packet::new_unchecked(&REPR_PACKET_BYTES[..]);
1014 assert_eq!(packet.check_len(), Ok(()));
1015 assert_eq!(packet.version(), 6);
1016 assert_eq!(packet.traffic_class(), 0);
1017 assert_eq!(packet.flow_label(), 0);
1018 assert_eq!(packet.total_len(), 0x34);
1019 assert_eq!(packet.payload_len() as usize, REPR_PAYLOAD_BYTES.len());
1020 assert_eq!(packet.next_header(), Protocol::Udp);
1021 assert_eq!(packet.hop_limit(), 0x40);
1022 assert_eq!(packet.src_addr(), Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1));
1023 assert_eq!(packet.dst_addr(), LINK_LOCAL_ALL_NODES);
1024 assert_eq!(packet.payload(), &REPR_PAYLOAD_BYTES[..]);
1025 }
1026
1027 #[test]
1028 fn test_packet_construction() {
1029 let mut bytes = [0xff; 52];
1030 let mut packet = Packet::new_unchecked(&mut bytes[..]);
1031 packet.set_version(6);
1035 assert_eq!(packet.version(), 6);
1036 packet.set_traffic_class(0x99);
1037 assert_eq!(packet.version(), 6);
1038 assert_eq!(packet.traffic_class(), 0x99);
1039 packet.set_flow_label(0x54321);
1040 assert_eq!(packet.traffic_class(), 0x99);
1041 assert_eq!(packet.flow_label(), 0x54321);
1042 packet.set_payload_len(0xc);
1043 packet.set_next_header(Protocol::Udp);
1044 packet.set_hop_limit(0xfe);
1045 packet.set_src_addr(LINK_LOCAL_ALL_ROUTERS);
1046 packet.set_dst_addr(LINK_LOCAL_ALL_NODES);
1047 packet
1048 .payload_mut()
1049 .copy_from_slice(&REPR_PAYLOAD_BYTES[..]);
1050 let mut expected_bytes = [
1051 0x69, 0x95, 0x43, 0x21, 0x00, 0x0c, 0x11, 0xfe, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00,
1052 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x02, 0x00, 0x00,
1053 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
1054 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1055 ];
1056 let start = expected_bytes.len() - REPR_PAYLOAD_BYTES.len();
1057 expected_bytes[start..].copy_from_slice(&REPR_PAYLOAD_BYTES[..]);
1058 assert_eq!(packet.check_len(), Ok(()));
1059 assert_eq!(&*packet.into_inner(), &expected_bytes[..]);
1060 }
1061
1062 #[test]
1063 fn test_overlong() {
1064 let mut bytes = vec![];
1065 bytes.extend(&REPR_PACKET_BYTES[..]);
1066 bytes.push(0);
1067
1068 assert_eq!(
1069 Packet::new_unchecked(&bytes).payload().len(),
1070 REPR_PAYLOAD_BYTES.len()
1071 );
1072 assert_eq!(
1073 Packet::new_unchecked(&mut bytes).payload_mut().len(),
1074 REPR_PAYLOAD_BYTES.len()
1075 );
1076 }
1077
1078 #[test]
1079 fn test_total_len_overflow() {
1080 let mut bytes = vec![];
1081 bytes.extend(&REPR_PACKET_BYTES[..]);
1082 Packet::new_unchecked(&mut bytes).set_payload_len(0x80);
1083
1084 assert_eq!(Packet::new_checked(&bytes).unwrap_err(), Error);
1085 }
1086
1087 #[test]
1088 fn test_repr_parse_valid() {
1089 let packet = Packet::new_unchecked(&REPR_PACKET_BYTES[..]);
1090 let repr = Repr::parse(&packet).unwrap();
1091 assert_eq!(repr, packet_repr());
1092 }
1093
1094 #[test]
1095 fn test_repr_parse_bad_version() {
1096 let mut bytes = [0; 40];
1097 let mut packet = Packet::new_unchecked(&mut bytes[..]);
1098 packet.set_version(4);
1099 packet.set_payload_len(0);
1100 let packet = Packet::new_unchecked(&*packet.into_inner());
1101 assert_eq!(Repr::parse(&packet), Err(Error));
1102 }
1103
1104 #[test]
1105 fn test_repr_parse_smaller_than_header() {
1106 let mut bytes = [0; 40];
1107 let mut packet = Packet::new_unchecked(&mut bytes[..]);
1108 packet.set_version(6);
1109 packet.set_payload_len(39);
1110 let packet = Packet::new_unchecked(&*packet.into_inner());
1111 assert_eq!(Repr::parse(&packet), Err(Error));
1112 }
1113
1114 #[test]
1115 fn test_repr_parse_smaller_than_payload() {
1116 let mut bytes = [0; 40];
1117 let mut packet = Packet::new_unchecked(&mut bytes[..]);
1118 packet.set_version(6);
1119 packet.set_payload_len(1);
1120 let packet = Packet::new_unchecked(&*packet.into_inner());
1121 assert_eq!(Repr::parse(&packet), Err(Error));
1122 }
1123
1124 #[test]
1125 fn test_basic_repr_emit() {
1126 let repr = packet_repr();
1127 let mut bytes = vec![0xff; repr.buffer_len() + REPR_PAYLOAD_BYTES.len()];
1128 let mut packet = Packet::new_unchecked(&mut bytes);
1129 repr.emit(&mut packet);
1130 packet.payload_mut().copy_from_slice(&REPR_PAYLOAD_BYTES);
1131 assert_eq!(&*packet.into_inner(), &REPR_PACKET_BYTES[..]);
1132 }
1133
1134 #[test]
1135 fn test_pretty_print() {
1136 assert_eq!(
1137 format!(
1138 "{}",
1139 PrettyPrinter::<Packet<&'static [u8]>>::new("\n", &&REPR_PACKET_BYTES[..])
1140 ),
1141 "\nIPv6 src=fe80::1 dst=ff02::1 nxt_hdr=UDP hop_limit=64\n \\ UDP src=1 dst=2 len=4"
1142 );
1143 }
1144}