smoltcp/wire/
ipv6.rs

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
11/// Minimum MTU required of all links supporting IPv6. See [RFC 8200 § 5].
12///
13/// [RFC 8200 § 5]: https://tools.ietf.org/html/rfc8200#section-5
14pub const MIN_MTU: usize = 1280;
15
16/// Size of IPv6 adderess in octets.
17///
18/// [RFC 8200 § 2]: https://www.rfc-editor.org/rfc/rfc4291#section-2
19pub const ADDR_SIZE: usize = 16;
20
21/// The link-local [all nodes multicast address].
22///
23/// [all nodes multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1
24pub const LINK_LOCAL_ALL_NODES: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1);
25
26/// The link-local [all routers multicast address].
27///
28/// [all routers multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1
29pub const LINK_LOCAL_ALL_ROUTERS: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 2);
30
31/// The link-local [all MLVDv2-capable routers multicast address].
32///
33/// [all MLVDv2-capable routers multicast address]: https://tools.ietf.org/html/rfc3810#section-11
34pub const LINK_LOCAL_ALL_MLDV2_ROUTERS: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x16);
35
36/// The link-local [all RPL nodes multicast address].
37///
38/// [all RPL nodes multicast address]: https://www.rfc-editor.org/rfc/rfc6550.html#section-20.19
39pub const LINK_LOCAL_ALL_RPL_NODES: Address = Address::new(0xff02, 0, 0, 0, 0, 0, 0, 0x1a);
40
41/// The [scope] of an address.
42///
43/// [scope]: https://www.rfc-editor.org/rfc/rfc4291#section-2.7
44#[repr(u8)]
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub(crate) enum MulticastScope {
47    /// Interface Local scope
48    InterfaceLocal = 0x1,
49    /// Link local scope
50    LinkLocal = 0x2,
51    /// Administratively configured
52    AdminLocal = 0x4,
53    /// Single site scope
54    SiteLocal = 0x5,
55    /// Organization scope
56    OrganizationLocal = 0x8,
57    /// Global scope
58    Global = 0xE,
59    /// Unknown scope
60    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    /// Construct an IPv6 address from a sequence of octets, in big-endian.
81    ///
82    /// # Panics
83    /// The function panics if `data` is not sixteen octets long.
84    fn from_bytes(data: &[u8]) -> Address;
85
86    /// Query whether the IPv6 address is an [unicast address].
87    ///
88    /// [unicast address]: https://tools.ietf.org/html/rfc4291#section-2.5
89    ///
90    /// `x_` prefix is to avoid a collision with the still-unstable method in `core::ip`.
91    fn x_is_unicast(&self) -> bool;
92
93    /// Query whether the IPv6 address is a [global unicast address].
94    ///
95    /// [global unicast address]: https://datatracker.ietf.org/doc/html/rfc3587
96    fn is_global_unicast(&self) -> bool;
97
98    /// Query whether the IPv6 address is in the [link-local] scope.
99    ///
100    /// [link-local]: https://tools.ietf.org/html/rfc4291#section-2.5.6
101    fn is_link_local(&self) -> bool;
102
103    /// Query whether the IPv6 address is a [Unique Local Address] (ULA).
104    ///
105    /// [Unique Local Address]: https://tools.ietf.org/html/rfc4193
106    ///
107    /// `x_` prefix is to avoid a collision with the still-unstable method in `core::ip`.
108    fn x_is_unique_local(&self) -> bool;
109
110    /// Helper function used to mask an address given a prefix.
111    ///
112    /// # Panics
113    /// This function panics if `mask` is greater than 128.
114    fn mask(&self, mask: u8) -> [u8; ADDR_SIZE];
115
116    /// The solicited node for the given unicast address.
117    ///
118    /// # Panics
119    /// This function panics if the given address is not
120    /// unicast.
121    fn solicited_node(&self) -> Address;
122
123    /// Return the scope of the address.
124    ///
125    /// `x_` prefix is to avoid a collision with the still-unstable method in `core::ip`.
126    fn x_multicast_scope(&self) -> MulticastScope;
127
128    /// Query whether the IPv6 address is a [solicited-node multicast address].
129    ///
130    /// [Solicited-node multicast address]: https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1
131    fn is_solicited_node_multicast(&self) -> bool;
132
133    /// If `self` is a CIDR-compatible subnet mask, return `Some(prefix_len)`,
134    /// where `prefix_len` is the number of leading zeroes. Return `None` otherwise.
135    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            // ULA are considered global scope
194            // https://www.rfc-editor.org/rfc/rfc6724#section-3.1
195            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                    // Expect 1s until first 0
217                    if one {
218                        prefix_len += 1;
219                    } else {
220                        ones = false;
221                    }
222                } else if one {
223                    // 1 where 0 was expected
224                    return None;
225                }
226                mask >>= 1;
227            }
228        }
229        Some(prefix_len)
230    }
231}
232
233/// A specification of an IPv6 CIDR block, containing an address and a variable-length
234/// subnet masking prefix length.
235#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
236pub struct Cidr {
237    address: Address,
238    prefix_len: u8,
239}
240
241impl Cidr {
242    /// The [solicited node prefix].
243    ///
244    /// [solicited node prefix]: https://tools.ietf.org/html/rfc4291#section-2.7.1
245    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    /// Create an IPv6 CIDR block from the given address and prefix length.
251    ///
252    /// # Panics
253    /// This function panics if the prefix length is larger than 128.
254    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    /// Return the address of this IPv6 CIDR block.
263    pub const fn address(&self) -> Address {
264        self.address
265    }
266
267    /// Return the prefix length of this IPv6 CIDR block.
268    pub const fn prefix_len(&self) -> u8 {
269        self.prefix_len
270    }
271
272    /// Query whether the subnetwork described by this IPv6 CIDR block contains
273    /// the given address.
274    pub fn contains_addr(&self, addr: &Address) -> bool {
275        // right shift by 128 is not legal
276        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    /// Query whether the subnetwork described by this IPV6 CIDR block contains
284    /// the subnetwork described by the given IPv6 CIDR block.
285    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        // https://tools.ietf.org/html/rfc4291#section-2.3
293        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/// A read/write wrapper around an Internet Protocol version 6 packet buffer.
305#[derive(Debug, PartialEq, Eq, Clone)]
306#[cfg_attr(feature = "defmt", derive(defmt::Format))]
307pub struct Packet<T: AsRef<[u8]>> {
308    buffer: T,
309}
310
311// Ranges and constants describing the IPv6 header
312//
313// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
314// |Version| Traffic Class |           Flow Label                  |
315// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
316// |         Payload Length        |  Next Header  |   Hop Limit   |
317// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
318// |                                                               |
319// +                                                               +
320// |                                                               |
321// +                         Source Address                        +
322// |                                                               |
323// +                                                               +
324// |                                                               |
325// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
326// |                                                               |
327// +                                                               +
328// |                                                               |
329// +                      Destination Address                      +
330// |                                                               |
331// +                                                               +
332// |                                                               |
333// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
334//
335// See https://tools.ietf.org/html/rfc2460#section-3 for details.
336mod field {
337    use crate::wire::field::*;
338    // 4-bit version number, 8-bit traffic class, and the
339    // 20-bit flow label.
340    pub const VER_TC_FLOW: Field = 0..4;
341    // 16-bit value representing the length of the payload.
342    // Note: Options are included in this length.
343    pub const LENGTH: Field = 4..6;
344    // 8-bit value identifying the type of header following this
345    // one. Note: The same numbers are used in IPv4.
346    pub const NXT_HDR: usize = 6;
347    // 8-bit value decremented by each node that forwards this
348    // packet. The packet is discarded when the value is 0.
349    pub const HOP_LIMIT: usize = 7;
350    // IPv6 address of the source node.
351    pub const SRC_ADDR: Field = 8..24;
352    // IPv6 address of the destination node.
353    pub const DST_ADDR: Field = 24..40;
354}
355
356/// Length of an IPv6 header.
357pub const HEADER_LEN: usize = field::DST_ADDR.end;
358
359impl<T: AsRef<[u8]>> Packet<T> {
360    /// Create a raw octet buffer with an IPv6 packet structure.
361    #[inline]
362    pub const fn new_unchecked(buffer: T) -> Packet<T> {
363        Packet { buffer }
364    }
365
366    /// Shorthand for a combination of [new_unchecked] and [check_len].
367    ///
368    /// [new_unchecked]: #method.new_unchecked
369    /// [check_len]: #method.check_len
370    #[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    /// Ensure that no accessor method will panic if called.
378    /// Returns `Err(Error)` if the buffer is too short.
379    ///
380    /// The result of this check is invalidated by calling [set_payload_len].
381    ///
382    /// [set_payload_len]: #method.set_payload_len
383    #[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    /// Consume the packet, returning the underlying buffer.
394    #[inline]
395    pub fn into_inner(self) -> T {
396        self.buffer
397    }
398
399    /// Return the header length.
400    #[inline]
401    pub const fn header_len(&self) -> usize {
402        // This is not a strictly necessary function, but it makes
403        // code more readable.
404        field::DST_ADDR.end
405    }
406
407    /// Return the version field.
408    #[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    /// Return the traffic class.
415    #[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    /// Return the flow label field.
422    #[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    /// Return the payload length field.
429    #[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    /// Return the payload length added to the known header length.
436    #[inline]
437    pub fn total_len(&self) -> usize {
438        self.header_len() + self.payload_len() as usize
439    }
440
441    /// Return the next header field.
442    #[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    /// Return the hop limit field.
449    #[inline]
450    pub fn hop_limit(&self) -> u8 {
451        let data = self.buffer.as_ref();
452        data[field::HOP_LIMIT]
453    }
454
455    /// Return the source address field.
456    #[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    /// Return the destination address field.
463    #[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    /// Return a pointer to the payload.
472    #[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    /// Set the version field.
482    #[inline]
483    pub fn set_version(&mut self, value: u8) {
484        let data = self.buffer.as_mut();
485        // Make sure to retain the lower order bits which contain
486        // the higher order bits of the traffic class
487        data[0] = (data[0] & 0x0f) | ((value & 0x0f) << 4);
488    }
489
490    /// Set the traffic class field.
491    #[inline]
492    pub fn set_traffic_class(&mut self, value: u8) {
493        let data = self.buffer.as_mut();
494        // Put the higher order 4-bits of value in the lower order
495        // 4-bits of the first byte
496        data[0] = (data[0] & 0xf0) | ((value & 0xf0) >> 4);
497        // Put the lower order 4-bits of value in the higher order
498        // 4-bits of the second byte
499        data[1] = (data[1] & 0x0f) | ((value & 0x0f) << 4);
500    }
501
502    /// Set the flow label field.
503    #[inline]
504    pub fn set_flow_label(&mut self, value: u32) {
505        let data = self.buffer.as_mut();
506        // Retain the lower order 4-bits of the traffic class
507        let raw = (((data[1] & 0xf0) as u32) << 16) | (value & 0x0fffff);
508        NetworkEndian::write_u24(&mut data[1..4], raw);
509    }
510
511    /// Set the payload length field.
512    #[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    /// Set the next header field.
519    #[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    /// Set the hop limit field.
526    #[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    /// Set the source address field.
533    #[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    /// Set the destination address field.
540    #[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    /// Return a mutable pointer to the payload.
547    #[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/// A high-level representation of an Internet Protocol version 6 packet header.
574#[derive(Debug, PartialEq, Eq, Clone, Copy)]
575pub struct Repr {
576    /// IPv6 address of the source node.
577    pub src_addr: Address,
578    /// IPv6 address of the destination node.
579    pub dst_addr: Address,
580    /// Protocol contained in the next header.
581    pub next_header: Protocol,
582    /// Length of the payload including the extension headers.
583    pub payload_len: usize,
584    /// The 8-bit hop limit field.
585    pub hop_limit: u8,
586}
587
588impl Repr {
589    /// Parse an Internet Protocol version 6 packet and return a high-level representation.
590    pub fn parse<T: AsRef<[u8]> + ?Sized>(packet: &Packet<&T>) -> Result<Repr> {
591        // Ensure basic accessors will work
592        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    /// Return the length of a header that will be emitted from this high-level representation.
606    pub const fn buffer_len(&self) -> usize {
607        // This function is not strictly necessary, but it can make client code more readable.
608        field::DST_ADDR.end
609    }
610
611    /// Emit a high-level representation into an Internet Protocol version 6 packet.
612    pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) {
613        // Make no assumptions about the original state of the packet buffer.
614        // Make sure to set every byte.
615        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
652// TODO: This is very similar to the implementation for IPv4. Make
653// a way to have less copy and pasted code here.
654impl<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        // fe80::1/56
798        // 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
799        // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
800        let cidr = Cidr::new(LINK_LOCAL_ADDR, 56);
801
802        let inside_subnet = [
803            // fe80::2
804            [
805                0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
806                0x00, 0x02,
807            ],
808            // fe80::1122:3344:5566:7788
809            [
810                0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
811                0x77, 0x88,
812            ],
813            // fe80::ff00:0:0:0
814            [
815                0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
816                0x00, 0x00,
817            ],
818            // fe80::ff
819            [
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            // fe80:0:0:101::1
827            [
828                0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
829                0x00, 0x01,
830            ],
831            // ::1
832            [
833                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
834                0x00, 0x01,
835            ],
836            // ff02::1
837            [
838                0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
839                0x00, 0x01,
840            ],
841            // ff02::2
842            [
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            // fe80::ffff:ffff:ffff:ffff/65
850            (
851                [
852                    0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
853                    0xff, 0xff, 0xff,
854                ],
855                65,
856            ),
857            // fe80::1/128
858            (
859                [
860                    0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
861                    0x00, 0x00, 0x01,
862                ],
863                128,
864            ),
865            // fe80::1234:5678/96
866            (
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            // fe80::101:ffff:ffff:ffff:ffff/55
877            (
878                [
879                    0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
880                    0xff, 0xff, 0xff,
881                ],
882                55,
883            ),
884            // fe80::101:ffff:ffff:ffff:ffff/56
885            (
886                [
887                    0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
888                    0xff, 0xff, 0xff,
889                ],
890                56,
891            ),
892            // fe80::101:ffff:ffff:ffff:ffff/57
893            (
894                [
895                    0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
896                    0xff, 0xff, 0xff,
897                ],
898                57,
899            ),
900            // ::1/128
901            (
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        // For source address selection, unicast addresses also have a scope:
977        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        // Version, Traffic Class, and Flow Label are not
1032        // byte aligned. make sure the setters and getters
1033        // do not interfere with each other.
1034        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}