1 #![deny(missing_docs)]
2 
3 use byteorder::{ByteOrder, NetworkEndian};
4 use core::fmt;
5 
6 use super::{Error, Result};
7 use crate::wire::ip::pretty_print_ip_payload;
8 #[cfg(feature = "proto-ipv4")]
9 use crate::wire::ipv4;
10 
11 pub use super::IpProtocol as Protocol;
12 
13 /// Minimum MTU required of all links supporting IPv6. See [RFC 8200 § 5].
14 ///
15 /// [RFC 8200 § 5]: https://tools.ietf.org/html/rfc8200#section-5
16 pub const MIN_MTU: usize = 1280;
17 
18 /// Size of IPv6 adderess in octets.
19 ///
20 /// [RFC 8200 § 2]: https://www.rfc-editor.org/rfc/rfc4291#section-2
21 pub const ADDR_SIZE: usize = 16;
22 
23 /// Size of IPv4-mapping prefix in octets.
24 ///
25 /// [RFC 8200 § 2]: https://www.rfc-editor.org/rfc/rfc4291#section-2
26 pub const IPV4_MAPPED_PREFIX_SIZE: usize = ADDR_SIZE - 4; // 4 == ipv4::ADDR_SIZE , cannot DRY here because of dependency on a IPv4 module which is behind the feature
27 
28 /// A sixteen-octet IPv6 address.
29 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
30 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
31 pub struct Address(pub [u8; ADDR_SIZE]);
32 
33 impl Address {
34     /// The [unspecified address].
35     ///
36     /// [unspecified address]: https://tools.ietf.org/html/rfc4291#section-2.5.2
37     pub const UNSPECIFIED: Address = Address([0x00; ADDR_SIZE]);
38 
39     /// The link-local [all nodes multicast address].
40     ///
41     /// [all nodes multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1
42     pub const LINK_LOCAL_ALL_NODES: Address = Address([
43         0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44         0x01,
45     ]);
46 
47     /// The link-local [all routers multicast address].
48     ///
49     /// [all routers multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7.1
50     pub const LINK_LOCAL_ALL_ROUTERS: Address = Address([
51         0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52         0x02,
53     ]);
54 
55     /// The [loopback address].
56     ///
57     /// [loopback address]: https://tools.ietf.org/html/rfc4291#section-2.5.3
58     pub const LOOPBACK: Address = Address([
59         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60         0x01,
61     ]);
62 
63     /// The prefix used in [IPv4-mapped addresses].
64     ///
65     /// [IPv4-mapped addresses]: https://www.rfc-editor.org/rfc/rfc4291#section-2.5.5.2
66     pub const IPV4_MAPPED_PREFIX: [u8; IPV4_MAPPED_PREFIX_SIZE] =
67         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff];
68 
69     /// Construct an IPv6 address from parts.
70     #[allow(clippy::too_many_arguments)]
new( a0: u16, a1: u16, a2: u16, a3: u16, a4: u16, a5: u16, a6: u16, a7: u16, ) -> Address71     pub const fn new(
72         a0: u16,
73         a1: u16,
74         a2: u16,
75         a3: u16,
76         a4: u16,
77         a5: u16,
78         a6: u16,
79         a7: u16,
80     ) -> Address {
81         Address([
82             (a0 >> 8) as u8,
83             a0 as u8,
84             (a1 >> 8) as u8,
85             a1 as u8,
86             (a2 >> 8) as u8,
87             a2 as u8,
88             (a3 >> 8) as u8,
89             a3 as u8,
90             (a4 >> 8) as u8,
91             a4 as u8,
92             (a5 >> 8) as u8,
93             a5 as u8,
94             (a6 >> 8) as u8,
95             a6 as u8,
96             (a7 >> 8) as u8,
97             a7 as u8,
98         ])
99     }
100 
101     /// Construct an IPv6 address from a sequence of octets, in big-endian.
102     ///
103     /// # Panics
104     /// The function panics if `data` is not sixteen octets long.
from_bytes(data: &[u8]) -> Address105     pub fn from_bytes(data: &[u8]) -> Address {
106         let mut bytes = [0; ADDR_SIZE];
107         bytes.copy_from_slice(data);
108         Address(bytes)
109     }
110 
111     /// Construct an IPv6 address from a sequence of words, in big-endian.
112     ///
113     /// # Panics
114     /// The function panics if `data` is not 8 words long.
from_parts(data: &[u16]) -> Address115     pub fn from_parts(data: &[u16]) -> Address {
116         assert!(data.len() >= 8);
117         let mut bytes = [0; ADDR_SIZE];
118         for (word_idx, chunk) in bytes.chunks_mut(2).enumerate() {
119             NetworkEndian::write_u16(chunk, data[word_idx]);
120         }
121         Address(bytes)
122     }
123 
124     /// Write a IPv6 address to the given slice.
125     ///
126     /// # Panics
127     /// The function panics if `data` is not 8 words long.
write_parts(&self, data: &mut [u16])128     pub fn write_parts(&self, data: &mut [u16]) {
129         assert!(data.len() >= 8);
130         for (i, chunk) in self.0.chunks(2).enumerate() {
131             data[i] = NetworkEndian::read_u16(chunk);
132         }
133     }
134 
135     /// Return an IPv6 address as a sequence of octets, in big-endian.
as_bytes(&self) -> &[u8]136     pub const fn as_bytes(&self) -> &[u8] {
137         &self.0
138     }
139 
140     /// Query whether the IPv6 address is an [unicast address].
141     ///
142     /// [unicast address]: https://tools.ietf.org/html/rfc4291#section-2.5
is_unicast(&self) -> bool143     pub fn is_unicast(&self) -> bool {
144         !(self.is_multicast() || self.is_unspecified())
145     }
146 
147     /// Query whether the IPv6 address is a [multicast address].
148     ///
149     /// [multicast address]: https://tools.ietf.org/html/rfc4291#section-2.7
is_multicast(&self) -> bool150     pub const fn is_multicast(&self) -> bool {
151         self.0[0] == 0xff
152     }
153 
154     /// Query whether the IPv6 address is the [unspecified address].
155     ///
156     /// [unspecified address]: https://tools.ietf.org/html/rfc4291#section-2.5.2
is_unspecified(&self) -> bool157     pub fn is_unspecified(&self) -> bool {
158         self.0 == [0x00; ADDR_SIZE]
159     }
160 
161     /// Query whether the IPv6 address is in the [link-local] scope.
162     ///
163     /// [link-local]: https://tools.ietf.org/html/rfc4291#section-2.5.6
is_link_local(&self) -> bool164     pub fn is_link_local(&self) -> bool {
165         self.0[0..8] == [0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
166     }
167 
168     /// Query whether the IPv6 address is the [loopback address].
169     ///
170     /// [loopback address]: https://tools.ietf.org/html/rfc4291#section-2.5.3
is_loopback(&self) -> bool171     pub fn is_loopback(&self) -> bool {
172         *self == Self::LOOPBACK
173     }
174 
175     /// Query whether the IPv6 address is an [IPv4 mapped IPv6 address].
176     ///
177     /// [IPv4 mapped IPv6 address]: https://tools.ietf.org/html/rfc4291#section-2.5.5.2
is_ipv4_mapped(&self) -> bool178     pub fn is_ipv4_mapped(&self) -> bool {
179         self.0[..IPV4_MAPPED_PREFIX_SIZE] == Self::IPV4_MAPPED_PREFIX
180     }
181 
182     #[cfg(feature = "proto-ipv4")]
183     /// Convert an IPv4 mapped IPv6 address to an IPv4 address.
as_ipv4(&self) -> Option<ipv4::Address>184     pub fn as_ipv4(&self) -> Option<ipv4::Address> {
185         if self.is_ipv4_mapped() {
186             Some(ipv4::Address::from_bytes(
187                 &self.0[IPV4_MAPPED_PREFIX_SIZE..],
188             ))
189         } else {
190             None
191         }
192     }
193 
194     /// Helper function used to mask an address given a prefix.
195     ///
196     /// # Panics
197     /// This function panics if `mask` is greater than 128.
mask(&self, mask: u8) -> [u8; ADDR_SIZE]198     pub(super) fn mask(&self, mask: u8) -> [u8; ADDR_SIZE] {
199         assert!(mask <= 128);
200         let mut bytes = [0u8; ADDR_SIZE];
201         let idx = (mask as usize) / 8;
202         let modulus = (mask as usize) % 8;
203         let (first, second) = self.0.split_at(idx);
204         bytes[0..idx].copy_from_slice(first);
205         if idx < ADDR_SIZE {
206             let part = second[0];
207             bytes[idx] = part & (!(0xff >> modulus) as u8);
208         }
209         bytes
210     }
211 
212     /// The solicited node for the given unicast address.
213     ///
214     /// # Panics
215     /// This function panics if the given address is not
216     /// unicast.
solicited_node(&self) -> Address217     pub fn solicited_node(&self) -> Address {
218         assert!(self.is_unicast());
219         Address([
220             0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF,
221             self.0[13], self.0[14], self.0[15],
222         ])
223     }
224 
225     /// Convert to an `IpAddress`.
226     ///
227     /// Same as `.into()`, but works in `const`.
into_address(self) -> super::IpAddress228     pub const fn into_address(self) -> super::IpAddress {
229         super::IpAddress::Ipv6(self)
230     }
231 }
232 
233 #[cfg(feature = "std")]
234 impl From<::std::net::Ipv6Addr> for Address {
from(x: ::std::net::Ipv6Addr) -> Address235     fn from(x: ::std::net::Ipv6Addr) -> Address {
236         Address(x.octets())
237     }
238 }
239 
240 #[cfg(feature = "std")]
241 impl From<Address> for ::std::net::Ipv6Addr {
from(Address(x): Address) -> ::std::net::Ipv6Addr242     fn from(Address(x): Address) -> ::std::net::Ipv6Addr {
243         x.into()
244     }
245 }
246 
247 impl fmt::Display for Address {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result248     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
249         if self.is_ipv4_mapped() {
250             return write!(
251                 f,
252                 "::ffff:{}.{}.{}.{}",
253                 self.0[IPV4_MAPPED_PREFIX_SIZE + 0],
254                 self.0[IPV4_MAPPED_PREFIX_SIZE + 1],
255                 self.0[IPV4_MAPPED_PREFIX_SIZE + 2],
256                 self.0[IPV4_MAPPED_PREFIX_SIZE + 3]
257             );
258         }
259 
260         // The string representation of an IPv6 address should
261         // collapse a series of 16 bit sections that evaluate
262         // to 0 to "::"
263         //
264         // See https://tools.ietf.org/html/rfc4291#section-2.2
265         // for details.
266         enum State {
267             Head,
268             HeadBody,
269             Tail,
270             TailBody,
271         }
272         let mut words = [0u16; 8];
273         self.write_parts(&mut words);
274         let mut state = State::Head;
275         for word in words.iter() {
276             state = match (*word, &state) {
277                 // Once a u16 equal to zero write a double colon and
278                 // skip to the next non-zero u16.
279                 (0, &State::Head) | (0, &State::HeadBody) => {
280                     write!(f, "::")?;
281                     State::Tail
282                 }
283                 // Continue iterating without writing any characters until
284                 // we hit a non-zero value.
285                 (0, &State::Tail) => State::Tail,
286                 // When the state is Head or Tail write a u16 in hexadecimal
287                 // without the leading colon if the value is not 0.
288                 (_, &State::Head) => {
289                     write!(f, "{word:x}")?;
290                     State::HeadBody
291                 }
292                 (_, &State::Tail) => {
293                     write!(f, "{word:x}")?;
294                     State::TailBody
295                 }
296                 // Write the u16 with a leading colon when parsing a value
297                 // that isn't the first in a section
298                 (_, &State::HeadBody) | (_, &State::TailBody) => {
299                     write!(f, ":{word:x}")?;
300                     state
301                 }
302             }
303         }
304         Ok(())
305     }
306 }
307 
308 #[cfg(feature = "proto-ipv4")]
309 /// Convert the given IPv4 address into a IPv4-mapped IPv6 address
310 impl From<ipv4::Address> for Address {
from(address: ipv4::Address) -> Self311     fn from(address: ipv4::Address) -> Self {
312         let mut b = [0_u8; ADDR_SIZE];
313         b[..Self::IPV4_MAPPED_PREFIX.len()].copy_from_slice(&Self::IPV4_MAPPED_PREFIX);
314         b[Self::IPV4_MAPPED_PREFIX.len()..].copy_from_slice(&address.0);
315         Self(b)
316     }
317 }
318 
319 /// A specification of an IPv6 CIDR block, containing an address and a variable-length
320 /// subnet masking prefix length.
321 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
322 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
323 pub struct Cidr {
324     address: Address,
325     prefix_len: u8,
326 }
327 
328 impl Cidr {
329     /// The [solicited node prefix].
330     ///
331     /// [solicited node prefix]: https://tools.ietf.org/html/rfc4291#section-2.7.1
332     pub const SOLICITED_NODE_PREFIX: Cidr = Cidr {
333         address: Address([
334             0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x00,
335             0x00, 0x00,
336         ]),
337         prefix_len: 104,
338     };
339 
340     /// Create an IPv6 CIDR block from the given address and prefix length.
341     ///
342     /// # Panics
343     /// This function panics if the prefix length is larger than 128.
new(address: Address, prefix_len: u8) -> Cidr344     pub const fn new(address: Address, prefix_len: u8) -> Cidr {
345         assert!(prefix_len <= 128);
346         Cidr {
347             address,
348             prefix_len,
349         }
350     }
351 
352     /// Return the address of this IPv6 CIDR block.
address(&self) -> Address353     pub const fn address(&self) -> Address {
354         self.address
355     }
356 
357     /// Return the prefix length of this IPv6 CIDR block.
prefix_len(&self) -> u8358     pub const fn prefix_len(&self) -> u8 {
359         self.prefix_len
360     }
361 
362     /// Query whether the subnetwork described by this IPv6 CIDR block contains
363     /// the given address.
contains_addr(&self, addr: &Address) -> bool364     pub fn contains_addr(&self, addr: &Address) -> bool {
365         // right shift by 128 is not legal
366         if self.prefix_len == 0 {
367             return true;
368         }
369 
370         self.address.mask(self.prefix_len) == addr.mask(self.prefix_len)
371     }
372 
373     /// Query whether the subnetwork described by this IPV6 CIDR block contains
374     /// the subnetwork described by the given IPv6 CIDR block.
contains_subnet(&self, subnet: &Cidr) -> bool375     pub fn contains_subnet(&self, subnet: &Cidr) -> bool {
376         self.prefix_len <= subnet.prefix_len && self.contains_addr(&subnet.address)
377     }
378 }
379 
380 impl fmt::Display for Cidr {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result381     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
382         // https://tools.ietf.org/html/rfc4291#section-2.3
383         write!(f, "{}/{}", self.address, self.prefix_len)
384     }
385 }
386 
387 /// A read/write wrapper around an Internet Protocol version 6 packet buffer.
388 #[derive(Debug, PartialEq, Eq, Clone)]
389 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
390 pub struct Packet<T: AsRef<[u8]>> {
391     buffer: T,
392 }
393 
394 // Ranges and constants describing the IPv6 header
395 //
396 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
397 // |Version| Traffic Class |           Flow Label                  |
398 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
399 // |         Payload Length        |  Next Header  |   Hop Limit   |
400 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
401 // |                                                               |
402 // +                                                               +
403 // |                                                               |
404 // +                         Source Address                        +
405 // |                                                               |
406 // +                                                               +
407 // |                                                               |
408 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
409 // |                                                               |
410 // +                                                               +
411 // |                                                               |
412 // +                      Destination Address                      +
413 // |                                                               |
414 // +                                                               +
415 // |                                                               |
416 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
417 //
418 // See https://tools.ietf.org/html/rfc2460#section-3 for details.
419 mod field {
420     use crate::wire::field::*;
421     // 4-bit version number, 8-bit traffic class, and the
422     // 20-bit flow label.
423     pub const VER_TC_FLOW: Field = 0..4;
424     // 16-bit value representing the length of the payload.
425     // Note: Options are included in this length.
426     pub const LENGTH: Field = 4..6;
427     // 8-bit value identifying the type of header following this
428     // one. Note: The same numbers are used in IPv4.
429     pub const NXT_HDR: usize = 6;
430     // 8-bit value decremented by each node that forwards this
431     // packet. The packet is discarded when the value is 0.
432     pub const HOP_LIMIT: usize = 7;
433     // IPv6 address of the source node.
434     pub const SRC_ADDR: Field = 8..24;
435     // IPv6 address of the destination node.
436     pub const DST_ADDR: Field = 24..40;
437 }
438 
439 /// Length of an IPv6 header.
440 pub const HEADER_LEN: usize = field::DST_ADDR.end;
441 
442 impl<T: AsRef<[u8]>> Packet<T> {
443     /// Create a raw octet buffer with an IPv6 packet structure.
444     #[inline]
new_unchecked(buffer: T) -> Packet<T>445     pub const fn new_unchecked(buffer: T) -> Packet<T> {
446         Packet { buffer }
447     }
448 
449     /// Shorthand for a combination of [new_unchecked] and [check_len].
450     ///
451     /// [new_unchecked]: #method.new_unchecked
452     /// [check_len]: #method.check_len
453     #[inline]
new_checked(buffer: T) -> Result<Packet<T>>454     pub fn new_checked(buffer: T) -> Result<Packet<T>> {
455         let packet = Self::new_unchecked(buffer);
456         packet.check_len()?;
457         Ok(packet)
458     }
459 
460     /// Ensure that no accessor method will panic if called.
461     /// Returns `Err(Error)` if the buffer is too short.
462     ///
463     /// The result of this check is invalidated by calling [set_payload_len].
464     ///
465     /// [set_payload_len]: #method.set_payload_len
466     #[inline]
check_len(&self) -> Result<()>467     pub fn check_len(&self) -> Result<()> {
468         let len = self.buffer.as_ref().len();
469         if len < field::DST_ADDR.end || len < self.total_len() {
470             Err(Error)
471         } else {
472             Ok(())
473         }
474     }
475 
476     /// Consume the packet, returning the underlying buffer.
477     #[inline]
into_inner(self) -> T478     pub fn into_inner(self) -> T {
479         self.buffer
480     }
481 
482     /// Return the header length.
483     #[inline]
header_len(&self) -> usize484     pub const fn header_len(&self) -> usize {
485         // This is not a strictly necessary function, but it makes
486         // code more readable.
487         field::DST_ADDR.end
488     }
489 
490     /// Return the version field.
491     #[inline]
version(&self) -> u8492     pub fn version(&self) -> u8 {
493         let data = self.buffer.as_ref();
494         data[field::VER_TC_FLOW.start] >> 4
495     }
496 
497     /// Return the traffic class.
498     #[inline]
traffic_class(&self) -> u8499     pub fn traffic_class(&self) -> u8 {
500         let data = self.buffer.as_ref();
501         ((NetworkEndian::read_u16(&data[0..2]) & 0x0ff0) >> 4) as u8
502     }
503 
504     /// Return the flow label field.
505     #[inline]
flow_label(&self) -> u32506     pub fn flow_label(&self) -> u32 {
507         let data = self.buffer.as_ref();
508         NetworkEndian::read_u24(&data[1..4]) & 0x000fffff
509     }
510 
511     /// Return the payload length field.
512     #[inline]
payload_len(&self) -> u16513     pub fn payload_len(&self) -> u16 {
514         let data = self.buffer.as_ref();
515         NetworkEndian::read_u16(&data[field::LENGTH])
516     }
517 
518     /// Return the payload length added to the known header length.
519     #[inline]
total_len(&self) -> usize520     pub fn total_len(&self) -> usize {
521         self.header_len() + self.payload_len() as usize
522     }
523 
524     /// Return the next header field.
525     #[inline]
next_header(&self) -> Protocol526     pub fn next_header(&self) -> Protocol {
527         let data = self.buffer.as_ref();
528         Protocol::from(data[field::NXT_HDR])
529     }
530 
531     /// Return the hop limit field.
532     #[inline]
hop_limit(&self) -> u8533     pub fn hop_limit(&self) -> u8 {
534         let data = self.buffer.as_ref();
535         data[field::HOP_LIMIT]
536     }
537 
538     /// Return the source address field.
539     #[inline]
src_addr(&self) -> Address540     pub fn src_addr(&self) -> Address {
541         let data = self.buffer.as_ref();
542         Address::from_bytes(&data[field::SRC_ADDR])
543     }
544 
545     /// Return the destination address field.
546     #[inline]
dst_addr(&self) -> Address547     pub fn dst_addr(&self) -> Address {
548         let data = self.buffer.as_ref();
549         Address::from_bytes(&data[field::DST_ADDR])
550     }
551 }
552 
553 impl<'a, T: AsRef<[u8]> + ?Sized> Packet<&'a T> {
554     /// Return a pointer to the payload.
555     #[inline]
payload(&self) -> &'a [u8]556     pub fn payload(&self) -> &'a [u8] {
557         let data = self.buffer.as_ref();
558         let range = self.header_len()..self.total_len();
559         &data[range]
560     }
561 }
562 
563 impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
564     /// Set the version field.
565     #[inline]
set_version(&mut self, value: u8)566     pub fn set_version(&mut self, value: u8) {
567         let data = self.buffer.as_mut();
568         // Make sure to retain the lower order bits which contain
569         // the higher order bits of the traffic class
570         data[0] = (data[0] & 0x0f) | ((value & 0x0f) << 4);
571     }
572 
573     /// Set the traffic class field.
574     #[inline]
set_traffic_class(&mut self, value: u8)575     pub fn set_traffic_class(&mut self, value: u8) {
576         let data = self.buffer.as_mut();
577         // Put the higher order 4-bits of value in the lower order
578         // 4-bits of the first byte
579         data[0] = (data[0] & 0xf0) | ((value & 0xf0) >> 4);
580         // Put the lower order 4-bits of value in the higher order
581         // 4-bits of the second byte
582         data[1] = (data[1] & 0x0f) | ((value & 0x0f) << 4);
583     }
584 
585     /// Set the flow label field.
586     #[inline]
set_flow_label(&mut self, value: u32)587     pub fn set_flow_label(&mut self, value: u32) {
588         let data = self.buffer.as_mut();
589         // Retain the lower order 4-bits of the traffic class
590         let raw = (((data[1] & 0xf0) as u32) << 16) | (value & 0x0fffff);
591         NetworkEndian::write_u24(&mut data[1..4], raw);
592     }
593 
594     /// Set the payload length field.
595     #[inline]
set_payload_len(&mut self, value: u16)596     pub fn set_payload_len(&mut self, value: u16) {
597         let data = self.buffer.as_mut();
598         NetworkEndian::write_u16(&mut data[field::LENGTH], value);
599     }
600 
601     /// Set the next header field.
602     #[inline]
set_next_header(&mut self, value: Protocol)603     pub fn set_next_header(&mut self, value: Protocol) {
604         let data = self.buffer.as_mut();
605         data[field::NXT_HDR] = value.into();
606     }
607 
608     /// Set the hop limit field.
609     #[inline]
set_hop_limit(&mut self, value: u8)610     pub fn set_hop_limit(&mut self, value: u8) {
611         let data = self.buffer.as_mut();
612         data[field::HOP_LIMIT] = value;
613     }
614 
615     /// Set the source address field.
616     #[inline]
set_src_addr(&mut self, value: Address)617     pub fn set_src_addr(&mut self, value: Address) {
618         let data = self.buffer.as_mut();
619         data[field::SRC_ADDR].copy_from_slice(value.as_bytes());
620     }
621 
622     /// Set the destination address field.
623     #[inline]
set_dst_addr(&mut self, value: Address)624     pub fn set_dst_addr(&mut self, value: Address) {
625         let data = self.buffer.as_mut();
626         data[field::DST_ADDR].copy_from_slice(value.as_bytes());
627     }
628 
629     /// Return a mutable pointer to the payload.
630     #[inline]
payload_mut(&mut self) -> &mut [u8]631     pub fn payload_mut(&mut self) -> &mut [u8] {
632         let range = self.header_len()..self.total_len();
633         let data = self.buffer.as_mut();
634         &mut data[range]
635     }
636 }
637 
638 impl<'a, T: AsRef<[u8]> + ?Sized> fmt::Display for Packet<&'a T> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result639     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
640         match Repr::parse(self) {
641             Ok(repr) => write!(f, "{repr}"),
642             Err(err) => {
643                 write!(f, "IPv6 ({err})")?;
644                 Ok(())
645             }
646         }
647     }
648 }
649 
650 impl<T: AsRef<[u8]>> AsRef<[u8]> for Packet<T> {
as_ref(&self) -> &[u8]651     fn as_ref(&self) -> &[u8] {
652         self.buffer.as_ref()
653     }
654 }
655 
656 /// A high-level representation of an Internet Protocol version 6 packet header.
657 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
658 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
659 pub struct Repr {
660     /// IPv6 address of the source node.
661     pub src_addr: Address,
662     /// IPv6 address of the destination node.
663     pub dst_addr: Address,
664     /// Protocol contained in the next header.
665     pub next_header: Protocol,
666     /// Length of the payload including the extension headers.
667     pub payload_len: usize,
668     /// The 8-bit hop limit field.
669     pub hop_limit: u8,
670 }
671 
672 impl Repr {
673     /// Parse an Internet Protocol version 6 packet and return a high-level representation.
parse<T: AsRef<[u8]> + ?Sized>(packet: &Packet<&T>) -> Result<Repr>674     pub fn parse<T: AsRef<[u8]> + ?Sized>(packet: &Packet<&T>) -> Result<Repr> {
675         // Ensure basic accessors will work
676         packet.check_len()?;
677         if packet.version() != 6 {
678             return Err(Error);
679         }
680         Ok(Repr {
681             src_addr: packet.src_addr(),
682             dst_addr: packet.dst_addr(),
683             next_header: packet.next_header(),
684             payload_len: packet.payload_len() as usize,
685             hop_limit: packet.hop_limit(),
686         })
687     }
688 
689     /// Return the length of a header that will be emitted from this high-level representation.
buffer_len(&self) -> usize690     pub const fn buffer_len(&self) -> usize {
691         // This function is not strictly necessary, but it can make client code more readable.
692         field::DST_ADDR.end
693     }
694 
695     /// Emit a high-level representation into an Internet Protocol version 6 packet.
emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>)696     pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) {
697         // Make no assumptions about the original state of the packet buffer.
698         // Make sure to set every byte.
699         packet.set_version(6);
700         packet.set_traffic_class(0);
701         packet.set_flow_label(0);
702         packet.set_payload_len(self.payload_len as u16);
703         packet.set_hop_limit(self.hop_limit);
704         packet.set_next_header(self.next_header);
705         packet.set_src_addr(self.src_addr);
706         packet.set_dst_addr(self.dst_addr);
707     }
708 }
709 
710 impl fmt::Display for Repr {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result711     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
712         write!(
713             f,
714             "IPv6 src={} dst={} nxt_hdr={} hop_limit={}",
715             self.src_addr, self.dst_addr, self.next_header, self.hop_limit
716         )
717     }
718 }
719 
720 use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
721 
722 // TODO: This is very similar to the implementation for IPv4. Make
723 // a way to have less copy and pasted code here.
724 impl<T: AsRef<[u8]>> PrettyPrint for Packet<T> {
pretty_print( buffer: &dyn AsRef<[u8]>, f: &mut fmt::Formatter, indent: &mut PrettyIndent, ) -> fmt::Result725     fn pretty_print(
726         buffer: &dyn AsRef<[u8]>,
727         f: &mut fmt::Formatter,
728         indent: &mut PrettyIndent,
729     ) -> fmt::Result {
730         let (ip_repr, payload) = match Packet::new_checked(buffer) {
731             Err(err) => return write!(f, "{indent}({err})"),
732             Ok(ip_packet) => match Repr::parse(&ip_packet) {
733                 Err(_) => return Ok(()),
734                 Ok(ip_repr) => {
735                     write!(f, "{indent}{ip_repr}")?;
736                     (ip_repr, ip_packet.payload())
737                 }
738             },
739         };
740 
741         pretty_print_ip_payload(f, indent, ip_repr, payload)
742     }
743 }
744 
745 #[cfg(test)]
746 mod test {
747     use super::Error;
748     use super::{Address, Cidr};
749     use super::{Packet, Protocol, Repr};
750     use crate::wire::pretty_print::PrettyPrinter;
751 
752     #[cfg(feature = "proto-ipv4")]
753     use crate::wire::ipv4::Address as Ipv4Address;
754 
755     static LINK_LOCAL_ADDR: Address = Address([
756         0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
757         0x01,
758     ]);
759     #[test]
test_basic_multicast()760     fn test_basic_multicast() {
761         assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_unspecified());
762         assert!(Address::LINK_LOCAL_ALL_ROUTERS.is_multicast());
763         assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_link_local());
764         assert!(!Address::LINK_LOCAL_ALL_ROUTERS.is_loopback());
765         assert!(!Address::LINK_LOCAL_ALL_NODES.is_unspecified());
766         assert!(Address::LINK_LOCAL_ALL_NODES.is_multicast());
767         assert!(!Address::LINK_LOCAL_ALL_NODES.is_link_local());
768         assert!(!Address::LINK_LOCAL_ALL_NODES.is_loopback());
769     }
770 
771     #[test]
test_basic_link_local()772     fn test_basic_link_local() {
773         assert!(!LINK_LOCAL_ADDR.is_unspecified());
774         assert!(!LINK_LOCAL_ADDR.is_multicast());
775         assert!(LINK_LOCAL_ADDR.is_link_local());
776         assert!(!LINK_LOCAL_ADDR.is_loopback());
777     }
778 
779     #[test]
test_basic_loopback()780     fn test_basic_loopback() {
781         assert!(!Address::LOOPBACK.is_unspecified());
782         assert!(!Address::LOOPBACK.is_multicast());
783         assert!(!Address::LOOPBACK.is_link_local());
784         assert!(Address::LOOPBACK.is_loopback());
785     }
786 
787     #[test]
test_address_format()788     fn test_address_format() {
789         assert_eq!("ff02::1", format!("{}", Address::LINK_LOCAL_ALL_NODES));
790         assert_eq!("fe80::1", format!("{LINK_LOCAL_ADDR}"));
791         assert_eq!(
792             "fe80::7f00:0:1",
793             format!(
794                 "{}",
795                 Address::new(0xfe80, 0, 0, 0, 0, 0x7f00, 0x0000, 0x0001)
796             )
797         );
798         assert_eq!("::", format!("{}", Address::UNSPECIFIED));
799         assert_eq!("::1", format!("{}", Address::LOOPBACK));
800 
801         #[cfg(feature = "proto-ipv4")]
802         assert_eq!(
803             "::ffff:192.168.1.1",
804             format!("{}", Address::from(Ipv4Address::new(192, 168, 1, 1)))
805         );
806     }
807 
808     #[test]
test_new()809     fn test_new() {
810         assert_eq!(
811             Address::new(0xff02, 0, 0, 0, 0, 0, 0, 1),
812             Address::LINK_LOCAL_ALL_NODES
813         );
814         assert_eq!(
815             Address::new(0xff02, 0, 0, 0, 0, 0, 0, 2),
816             Address::LINK_LOCAL_ALL_ROUTERS
817         );
818         assert_eq!(Address::new(0, 0, 0, 0, 0, 0, 0, 1), Address::LOOPBACK);
819         assert_eq!(Address::new(0, 0, 0, 0, 0, 0, 0, 0), Address::UNSPECIFIED);
820         assert_eq!(Address::new(0xfe80, 0, 0, 0, 0, 0, 0, 1), LINK_LOCAL_ADDR);
821     }
822 
823     #[test]
test_from_parts()824     fn test_from_parts() {
825         assert_eq!(
826             Address::from_parts(&[0xff02, 0, 0, 0, 0, 0, 0, 1]),
827             Address::LINK_LOCAL_ALL_NODES
828         );
829         assert_eq!(
830             Address::from_parts(&[0xff02, 0, 0, 0, 0, 0, 0, 2]),
831             Address::LINK_LOCAL_ALL_ROUTERS
832         );
833         assert_eq!(
834             Address::from_parts(&[0, 0, 0, 0, 0, 0, 0, 1]),
835             Address::LOOPBACK
836         );
837         assert_eq!(
838             Address::from_parts(&[0, 0, 0, 0, 0, 0, 0, 0]),
839             Address::UNSPECIFIED
840         );
841         assert_eq!(
842             Address::from_parts(&[0xfe80, 0, 0, 0, 0, 0, 0, 1]),
843             LINK_LOCAL_ADDR
844         );
845     }
846 
847     #[test]
test_write_parts()848     fn test_write_parts() {
849         let mut bytes = [0u16; 8];
850         {
851             Address::LOOPBACK.write_parts(&mut bytes);
852             assert_eq!(Address::LOOPBACK, Address::from_parts(&bytes));
853         }
854         {
855             Address::LINK_LOCAL_ALL_ROUTERS.write_parts(&mut bytes);
856             assert_eq!(Address::LINK_LOCAL_ALL_ROUTERS, Address::from_parts(&bytes));
857         }
858         {
859             LINK_LOCAL_ADDR.write_parts(&mut bytes);
860             assert_eq!(LINK_LOCAL_ADDR, Address::from_parts(&bytes));
861         }
862     }
863 
864     #[test]
test_mask()865     fn test_mask() {
866         let addr = Address::new(0x0123, 0x4567, 0x89ab, 0, 0, 0, 0, 1);
867         assert_eq!(
868             addr.mask(11),
869             [0x01, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
870         );
871         assert_eq!(
872             addr.mask(15),
873             [0x01, 0x22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
874         );
875         assert_eq!(
876             addr.mask(26),
877             [0x01, 0x23, 0x45, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
878         );
879         assert_eq!(
880             addr.mask(128),
881             [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
882         );
883         assert_eq!(
884             addr.mask(127),
885             [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
886         );
887     }
888 
889     #[cfg(feature = "proto-ipv4")]
890     #[test]
test_is_ipv4_mapped()891     fn test_is_ipv4_mapped() {
892         assert!(!Address::UNSPECIFIED.is_ipv4_mapped());
893         assert!(Address::from(Ipv4Address::new(192, 168, 1, 1)).is_ipv4_mapped());
894     }
895 
896     #[cfg(feature = "proto-ipv4")]
897     #[test]
test_as_ipv4()898     fn test_as_ipv4() {
899         assert_eq!(None, Address::UNSPECIFIED.as_ipv4());
900 
901         let ipv4 = Ipv4Address::new(192, 168, 1, 1);
902         assert_eq!(Some(ipv4), Address::from(ipv4).as_ipv4());
903     }
904 
905     #[cfg(feature = "proto-ipv4")]
906     #[test]
test_from_ipv4_address()907     fn test_from_ipv4_address() {
908         assert_eq!(
909             Address([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 168, 1, 1]),
910             Address::from(Ipv4Address::new(192, 168, 1, 1))
911         );
912         assert_eq!(
913             Address([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 222, 1, 41, 90]),
914             Address::from(Ipv4Address::new(222, 1, 41, 90))
915         );
916     }
917 
918     #[test]
test_cidr()919     fn test_cidr() {
920         // fe80::1/56
921         // 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
922         // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
923         let cidr = Cidr::new(LINK_LOCAL_ADDR, 56);
924 
925         let inside_subnet = [
926             // fe80::2
927             [
928                 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
929                 0x00, 0x02,
930             ],
931             // fe80::1122:3344:5566:7788
932             [
933                 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
934                 0x77, 0x88,
935             ],
936             // fe80::ff00:0:0:0
937             [
938                 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
939                 0x00, 0x00,
940             ],
941             // fe80::ff
942             [
943                 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
944                 0x00, 0xff,
945             ],
946         ];
947 
948         let outside_subnet = [
949             // fe80:0:0:101::1
950             [
951                 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
952                 0x00, 0x01,
953             ],
954             // ::1
955             [
956                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
957                 0x00, 0x01,
958             ],
959             // ff02::1
960             [
961                 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
962                 0x00, 0x01,
963             ],
964             // ff02::2
965             [
966                 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
967                 0x00, 0x02,
968             ],
969         ];
970 
971         let subnets = [
972             // fe80::ffff:ffff:ffff:ffff/65
973             (
974                 [
975                     0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
976                     0xff, 0xff, 0xff,
977                 ],
978                 65,
979             ),
980             // fe80::1/128
981             (
982                 [
983                     0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
984                     0x00, 0x00, 0x01,
985                 ],
986                 128,
987             ),
988             // fe80::1234:5678/96
989             (
990                 [
991                     0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12,
992                     0x34, 0x56, 0x78,
993                 ],
994                 96,
995             ),
996         ];
997 
998         let not_subnets = [
999             // fe80::101:ffff:ffff:ffff:ffff/55
1000             (
1001                 [
1002                     0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
1003                     0xff, 0xff, 0xff,
1004                 ],
1005                 55,
1006             ),
1007             // fe80::101:ffff:ffff:ffff:ffff/56
1008             (
1009                 [
1010                     0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
1011                     0xff, 0xff, 0xff,
1012                 ],
1013                 56,
1014             ),
1015             // fe80::101:ffff:ffff:ffff:ffff/57
1016             (
1017                 [
1018                     0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
1019                     0xff, 0xff, 0xff,
1020                 ],
1021                 57,
1022             ),
1023             // ::1/128
1024             (
1025                 [
1026                     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1027                     0x00, 0x00, 0x01,
1028                 ],
1029                 128,
1030             ),
1031         ];
1032 
1033         for addr in inside_subnet.iter().map(|a| Address::from_bytes(a)) {
1034             assert!(cidr.contains_addr(&addr));
1035         }
1036 
1037         for addr in outside_subnet.iter().map(|a| Address::from_bytes(a)) {
1038             assert!(!cidr.contains_addr(&addr));
1039         }
1040 
1041         for subnet in subnets.iter().map(|&(a, p)| Cidr::new(Address(a), p)) {
1042             assert!(cidr.contains_subnet(&subnet));
1043         }
1044 
1045         for subnet in not_subnets.iter().map(|&(a, p)| Cidr::new(Address(a), p)) {
1046             assert!(!cidr.contains_subnet(&subnet));
1047         }
1048 
1049         let cidr_without_prefix = Cidr::new(LINK_LOCAL_ADDR, 0);
1050         assert!(cidr_without_prefix.contains_addr(&Address::LOOPBACK));
1051     }
1052 
1053     #[test]
1054     #[should_panic(expected = "length")]
test_from_bytes_too_long()1055     fn test_from_bytes_too_long() {
1056         let _ = Address::from_bytes(&[0u8; 15]);
1057     }
1058 
1059     #[test]
1060     #[should_panic(expected = "data.len() >= 8")]
test_from_parts_too_long()1061     fn test_from_parts_too_long() {
1062         let _ = Address::from_parts(&[0u16; 7]);
1063     }
1064 
1065     static REPR_PACKET_BYTES: [u8; 52] = [
1066         0x60, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x11, 0x40, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
1067         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00,
1068         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00,
1069         0x0c, 0x02, 0x4e, 0xff, 0xff, 0xff, 0xff,
1070     ];
1071     static REPR_PAYLOAD_BYTES: [u8; 12] = [
1072         0x00, 0x01, 0x00, 0x02, 0x00, 0x0c, 0x02, 0x4e, 0xff, 0xff, 0xff, 0xff,
1073     ];
1074 
packet_repr() -> Repr1075     const fn packet_repr() -> Repr {
1076         Repr {
1077             src_addr: Address([
1078                 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1079                 0x00, 0x01,
1080             ]),
1081             dst_addr: Address::LINK_LOCAL_ALL_NODES,
1082             next_header: Protocol::Udp,
1083             payload_len: 12,
1084             hop_limit: 64,
1085         }
1086     }
1087 
1088     #[test]
test_packet_deconstruction()1089     fn test_packet_deconstruction() {
1090         let packet = Packet::new_unchecked(&REPR_PACKET_BYTES[..]);
1091         assert_eq!(packet.check_len(), Ok(()));
1092         assert_eq!(packet.version(), 6);
1093         assert_eq!(packet.traffic_class(), 0);
1094         assert_eq!(packet.flow_label(), 0);
1095         assert_eq!(packet.total_len(), 0x34);
1096         assert_eq!(packet.payload_len() as usize, REPR_PAYLOAD_BYTES.len());
1097         assert_eq!(packet.next_header(), Protocol::Udp);
1098         assert_eq!(packet.hop_limit(), 0x40);
1099         assert_eq!(
1100             packet.src_addr(),
1101             Address([
1102                 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1103                 0x00, 0x01
1104             ])
1105         );
1106         assert_eq!(packet.dst_addr(), Address::LINK_LOCAL_ALL_NODES);
1107         assert_eq!(packet.payload(), &REPR_PAYLOAD_BYTES[..]);
1108     }
1109 
1110     #[test]
test_packet_construction()1111     fn test_packet_construction() {
1112         let mut bytes = [0xff; 52];
1113         let mut packet = Packet::new_unchecked(&mut bytes[..]);
1114         // Version, Traffic Class, and Flow Label are not
1115         // byte aligned. make sure the setters and getters
1116         // do not interfere with each other.
1117         packet.set_version(6);
1118         assert_eq!(packet.version(), 6);
1119         packet.set_traffic_class(0x99);
1120         assert_eq!(packet.version(), 6);
1121         assert_eq!(packet.traffic_class(), 0x99);
1122         packet.set_flow_label(0x54321);
1123         assert_eq!(packet.traffic_class(), 0x99);
1124         assert_eq!(packet.flow_label(), 0x54321);
1125         packet.set_payload_len(0xc);
1126         packet.set_next_header(Protocol::Udp);
1127         packet.set_hop_limit(0xfe);
1128         packet.set_src_addr(Address::LINK_LOCAL_ALL_ROUTERS);
1129         packet.set_dst_addr(Address::LINK_LOCAL_ALL_NODES);
1130         packet
1131             .payload_mut()
1132             .copy_from_slice(&REPR_PAYLOAD_BYTES[..]);
1133         let mut expected_bytes = [
1134             0x69, 0x95, 0x43, 0x21, 0x00, 0x0c, 0x11, 0xfe, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00,
1135             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x02, 0x00, 0x00,
1136             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
1137             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1138         ];
1139         let start = expected_bytes.len() - REPR_PAYLOAD_BYTES.len();
1140         expected_bytes[start..].copy_from_slice(&REPR_PAYLOAD_BYTES[..]);
1141         assert_eq!(packet.check_len(), Ok(()));
1142         assert_eq!(&*packet.into_inner(), &expected_bytes[..]);
1143     }
1144 
1145     #[test]
test_overlong()1146     fn test_overlong() {
1147         let mut bytes = vec![];
1148         bytes.extend(&REPR_PACKET_BYTES[..]);
1149         bytes.push(0);
1150 
1151         assert_eq!(
1152             Packet::new_unchecked(&bytes).payload().len(),
1153             REPR_PAYLOAD_BYTES.len()
1154         );
1155         assert_eq!(
1156             Packet::new_unchecked(&mut bytes).payload_mut().len(),
1157             REPR_PAYLOAD_BYTES.len()
1158         );
1159     }
1160 
1161     #[test]
test_total_len_overflow()1162     fn test_total_len_overflow() {
1163         let mut bytes = vec![];
1164         bytes.extend(&REPR_PACKET_BYTES[..]);
1165         Packet::new_unchecked(&mut bytes).set_payload_len(0x80);
1166 
1167         assert_eq!(Packet::new_checked(&bytes).unwrap_err(), Error);
1168     }
1169 
1170     #[test]
test_repr_parse_valid()1171     fn test_repr_parse_valid() {
1172         let packet = Packet::new_unchecked(&REPR_PACKET_BYTES[..]);
1173         let repr = Repr::parse(&packet).unwrap();
1174         assert_eq!(repr, packet_repr());
1175     }
1176 
1177     #[test]
test_repr_parse_bad_version()1178     fn test_repr_parse_bad_version() {
1179         let mut bytes = vec![0; 40];
1180         let mut packet = Packet::new_unchecked(&mut bytes[..]);
1181         packet.set_version(4);
1182         packet.set_payload_len(0);
1183         let packet = Packet::new_unchecked(&*packet.into_inner());
1184         assert_eq!(Repr::parse(&packet), Err(Error));
1185     }
1186 
1187     #[test]
test_repr_parse_smaller_than_header()1188     fn test_repr_parse_smaller_than_header() {
1189         let mut bytes = vec![0; 40];
1190         let mut packet = Packet::new_unchecked(&mut bytes[..]);
1191         packet.set_version(6);
1192         packet.set_payload_len(39);
1193         let packet = Packet::new_unchecked(&*packet.into_inner());
1194         assert_eq!(Repr::parse(&packet), Err(Error));
1195     }
1196 
1197     #[test]
test_repr_parse_smaller_than_payload()1198     fn test_repr_parse_smaller_than_payload() {
1199         let mut bytes = vec![0; 40];
1200         let mut packet = Packet::new_unchecked(&mut bytes[..]);
1201         packet.set_version(6);
1202         packet.set_payload_len(1);
1203         let packet = Packet::new_unchecked(&*packet.into_inner());
1204         assert_eq!(Repr::parse(&packet), Err(Error));
1205     }
1206 
1207     #[test]
test_basic_repr_emit()1208     fn test_basic_repr_emit() {
1209         let repr = packet_repr();
1210         let mut bytes = vec![0xff; repr.buffer_len() + REPR_PAYLOAD_BYTES.len()];
1211         let mut packet = Packet::new_unchecked(&mut bytes);
1212         repr.emit(&mut packet);
1213         packet.payload_mut().copy_from_slice(&REPR_PAYLOAD_BYTES);
1214         assert_eq!(&*packet.into_inner(), &REPR_PACKET_BYTES[..]);
1215     }
1216 
1217     #[test]
test_pretty_print()1218     fn test_pretty_print() {
1219         assert_eq!(
1220             format!(
1221                 "{}",
1222                 PrettyPrinter::<Packet<&'static [u8]>>::new("\n", &&REPR_PACKET_BYTES[..])
1223             ),
1224             "\nIPv6 src=fe80::1 dst=ff02::1 nxt_hdr=UDP hop_limit=64\n \\ UDP src=1 dst=2 len=4"
1225         );
1226     }
1227 }
1228