Skip to main content

packet_formats/ipv6/
mod.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Parsing and serialization of IPv6 packets.
6//!
7//! The IPv6 packet format is defined in [RFC 8200] Sections 3 and 4.
8//!
9//! [RFC 8200]: https://datatracker.ietf.org/doc/html/rfc8200
10
11pub mod ext_hdrs;
12
13use alloc::vec::Vec;
14use core::borrow::Borrow;
15use core::fmt::{self, Debug, Formatter};
16use core::ops::Range;
17
18use log::debug;
19use net_types::ip::{GenericOverIp, Ipv4Addr, Ipv6, Ipv6Addr, Ipv6SourceAddr};
20use packet::records::{AlignedRecordSequenceBuilder, Records, RecordsRaw};
21use packet::{
22    BufferProvider, BufferView, BufferViewMut, EmptyBuf, FragmentedBytesMut, FromRaw,
23    GrowBufferMut, InnerPacketBuilder, LayoutBufferAlloc, MaybeParsed, NestablePacketBuilder,
24    NestableSerializer, NoOpSerializationContext, PacketBuilder, PacketConstraints, ParsablePacket,
25    ParseMetadata, PartialPacketBuilder, PartialSerializer, SerializeError, SerializeTarget,
26    Serializer,
27};
28use zerocopy::byteorder::network_endian::{U16, U32};
29use zerocopy::{
30    FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, SplitByteSliceMut, Unaligned,
31};
32
33use crate::TRANSPORT_HEADER_MAX_SIZE;
34use crate::error::{IpParseErrorAction, IpParseResult, Ipv6ParseError, ParseError};
35use crate::icmp::Icmpv6ParameterProblemCode;
36use crate::ip::{
37    DscpAndEcn, FragmentOffset, IpEnvelope, IpExt, IpPacketBuilder, IpProto,
38    IpSerializationContext, Ipv4Proto, Ipv6ExtHdrType, Ipv6Proto, Nat64Error,
39    Nat64TranslationResult,
40};
41use crate::ipv4::{HDR_PREFIX_LEN, Ipv4PacketBuilder};
42use crate::ipv6::ext_hdrs::ExtensionHeaderOptionAction;
43use crate::tcp::{TcpParseArgs, TcpSegment};
44use crate::udp::{UdpPacket, UdpParseArgs};
45
46use ext_hdrs::{
47    HopByHopOption, HopByHopOptionData, IPV6_FRAGMENT_EXT_HDR_LEN, Ipv6ExtensionHeader,
48    Ipv6ExtensionHeaderImpl, Ipv6ExtensionHeaderParsingContext, Ipv6ExtensionHeaderParsingError,
49    is_valid_next_header_upper_layer,
50};
51
52/// Length of the IPv6 fixed header.
53pub const IPV6_FIXED_HDR_LEN: usize = 40;
54
55/// The range of bytes within an IPv6 header buffer that the
56/// payload length field uses.
57pub const IPV6_PAYLOAD_LEN_BYTE_RANGE: Range<usize> = 4..6;
58
59// Offset to the Next Header field within the fixed IPv6 header
60const NEXT_HEADER_OFFSET: u8 = 6;
61
62// The maximum length for Hop-by-Hop Options. The stored byte's maximum
63// representable value is `u8::MAX` and it means the header has
64// that many 8-octets, not including the first 8 octets.
65const IPV6_HBH_OPTIONS_MAX_LEN: usize = (u8::MAX as usize) * 8 + 8;
66
67/// The maximum payload length after an IPv6 header.
68///
69/// The maximum IPv6 payload is the total number of bytes after the fixed header
70/// and must fit in a u16 as defined in [RFC 8200 Section 3].
71///
72/// [RFC 8200 Section 3]: https://datatracker.ietf.org/doc/html/rfc8200#section-3.
73const IPV6_MAX_PAYLOAD_LENGTH: usize = u16::MAX as usize;
74
75/// Convert an extension header parsing error to an IP packet
76/// parsing error.
77fn ext_hdr_err_fn(hdr: &FixedHeader, err: Ipv6ExtensionHeaderParsingError) -> Ipv6ParseError {
78    // Below, we set parameter problem data's `pointer` to `IPV6_FIXED_HDR_LEN` + `pointer`
79    // since the the `pointer` we get from an `Ipv6ExtensionHeaderParsingError` is calculated
80    // from the start of the extension headers. Within an IPv6 packet, extension headers
81    // start right after the fixed header with a length of `IPV6_FIXED_HDR_LEN` so we add `pointer`
82    // to `IPV6_FIXED_HDR_LEN` to get the pointer to the field with the parameter problem error
83    // from the start of the IPv6 packet. For a non-jumbogram packet, we know that
84    // `IPV6_FIXED_HDR_LEN` + `pointer` will not overflow because the maximum size of an
85    // IPv6 packet is 65575 bytes (fixed header + extension headers + body) and 65575 definitely
86    // fits within an `u32`. This may no longer hold true if/when jumbogram packets are supported.
87    // For the jumbogram case when the size of extension headers could be >= (4 GB - 41 bytes) (which
88    // we almost certainly will never encounter), the pointer calculation may overflow. To account for
89    // this scenario, we check for overflows when adding `IPV6_FIXED_HDR_LEN` to `pointer`. If
90    // we do end up overflowing, we will discard the packet (even if we were normally required to
91    // send back an ICMP error message) because we will be unable to construct a correct ICMP error
92    // message (the pointer field of the ICMP message will not be able to hold a value > (4^32 - 1)
93    // which is what we would have if the pointer calculation overflows). But again, we should almost
94    // never encounter this scenario so we don't care if we have incorrect behaviour.
95
96    match err {
97        Ipv6ExtensionHeaderParsingError::ErroneousHeaderField { pointer, must_send_icmp } => {
98            Ipv6ParseError::ParameterProblem {
99                src_ip: hdr.src_ip,
100                dst_ip: hdr.dst_ip,
101                code: Icmpv6ParameterProblemCode::ErroneousHeaderField,
102                pointer,
103                must_send_icmp,
104                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
105            }
106        }
107        Ipv6ExtensionHeaderParsingError::UnrecognizedNextHeader { pointer, must_send_icmp } => {
108            Ipv6ParseError::ParameterProblem {
109                src_ip: hdr.src_ip,
110                dst_ip: hdr.dst_ip,
111                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
112                pointer,
113                must_send_icmp,
114                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
115            }
116        }
117        Ipv6ExtensionHeaderParsingError::UnrecognizedOption { pointer, must_send_icmp, action } => {
118            let action = match action {
119                ExtensionHeaderOptionAction::SkipAndContinue => unreachable!(
120                    "Should never end up here because this action should never result in an error"
121                ),
122                ExtensionHeaderOptionAction::DiscardPacket => IpParseErrorAction::DiscardPacket,
123                ExtensionHeaderOptionAction::DiscardPacketSendIcmp => {
124                    IpParseErrorAction::DiscardPacketSendIcmp
125                }
126                ExtensionHeaderOptionAction::DiscardPacketSendIcmpNoMulticast => {
127                    IpParseErrorAction::DiscardPacketSendIcmpNoMulticast
128                }
129            };
130
131            Ipv6ParseError::ParameterProblem {
132                src_ip: hdr.src_ip,
133                dst_ip: hdr.dst_ip,
134                code: Icmpv6ParameterProblemCode::UnrecognizedIpv6Option,
135                pointer,
136                must_send_icmp,
137                action,
138            }
139        }
140        Ipv6ExtensionHeaderParsingError::BufferExhausted
141        | Ipv6ExtensionHeaderParsingError::MalformedData => {
142            // Unexpectedly running out of a buffer or encountering malformed
143            // data when parsing is a formatting error.
144            Ipv6ParseError::Parse { error: ParseError::Format }
145        }
146    }
147}
148
149/// The IPv6 fixed header which precedes any extension headers and the body.
150#[derive(Debug, Default, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq)]
151#[repr(C)]
152pub struct FixedHeader {
153    version_tc_flowlabel: [u8; 4],
154    payload_len: U16,
155    next_hdr: u8,
156    hop_limit: u8,
157    src_ip: Ipv6Addr,
158    dst_ip: Ipv6Addr,
159}
160
161const IP_VERSION: u8 = 6;
162const VERSION_OFFSET: u8 = 4;
163const FLOW_LABEL_MAX: u32 = (1 << 20) - 1;
164
165impl FixedHeader {
166    #[allow(clippy::too_many_arguments)]
167    fn new(
168        dscp_and_ecn: DscpAndEcn,
169        flow_label: u32,
170        payload_len: u16,
171        next_hdr: u8,
172        hop_limit: u8,
173        src_ip: Ipv6Addr,
174        dst_ip: Ipv6Addr,
175    ) -> FixedHeader {
176        debug_assert!(flow_label <= FLOW_LABEL_MAX);
177
178        let traffic_class = dscp_and_ecn.raw();
179        FixedHeader {
180            version_tc_flowlabel: [
181                IP_VERSION << VERSION_OFFSET | traffic_class >> 4,
182                (traffic_class << 4) | ((flow_label >> 16) as u8),
183                (flow_label >> 8) as u8,
184                flow_label as u8,
185            ],
186            payload_len: U16::new(payload_len),
187            next_hdr,
188            hop_limit,
189            src_ip,
190            dst_ip,
191        }
192    }
193
194    fn version(&self) -> u8 {
195        self.version_tc_flowlabel[0] >> 4
196    }
197
198    fn dscp_and_ecn(&self) -> DscpAndEcn {
199        ((self.version_tc_flowlabel[0] & 0xF) << 4 | self.version_tc_flowlabel[1] >> 4).into()
200    }
201
202    fn flowlabel(&self) -> u32 {
203        (u32::from(self.version_tc_flowlabel[1]) & 0xF) << 16
204            | u32::from(self.version_tc_flowlabel[2]) << 8
205            | u32::from(self.version_tc_flowlabel[3])
206    }
207}
208
209/// Provides common access to IPv6 header fields.
210///
211/// `Ipv6Header` provides access to IPv6 header fields as a common
212/// implementation for both [`Ipv6Packet`] and [`Ipv6PacketRaw`].
213pub trait Ipv6Header {
214    /// Gets a reference to the IPv6 [`FixedHeader`].
215    fn get_fixed_header(&self) -> &FixedHeader;
216
217    /// The Hop Limit.
218    fn hop_limit(&self) -> u8 {
219        self.get_fixed_header().hop_limit
220    }
221
222    /// The Next Header.
223    fn next_header(&self) -> u8 {
224        self.get_fixed_header().next_hdr
225    }
226
227    /// The source IP address.
228    fn src_ip(&self) -> Ipv6Addr {
229        self.get_fixed_header().src_ip
230    }
231
232    /// The destination IP address.
233    fn dst_ip(&self) -> Ipv6Addr {
234        self.get_fixed_header().dst_ip
235    }
236
237    /// The Differentiated Services Code Point (DSCP) and the Explicit
238    /// Congestion Notification (ECN).
239    fn dscp_and_ecn(&self) -> DscpAndEcn {
240        self.get_fixed_header().dscp_and_ecn()
241    }
242}
243
244impl Ipv6Header for FixedHeader {
245    fn get_fixed_header(&self) -> &FixedHeader {
246        self
247    }
248}
249
250/// An IPv6 packet.
251///
252/// An `Ipv6Packet` shares its underlying memory with the byte slice it was
253/// parsed from or serialized to, meaning that no copying or extra allocation is
254/// necessary.
255pub struct Ipv6Packet<B> {
256    fixed_hdr: Ref<B, FixedHeader>,
257    extension_hdrs: Records<B, Ipv6ExtensionHeaderImpl>,
258    body: B,
259    proto: Ipv6Proto,
260}
261
262impl<B: SplitByteSlice, I: IpExt> GenericOverIp<I> for Ipv6Packet<B> {
263    type Type = <I as IpExt>::Packet<B>;
264}
265
266impl<B: SplitByteSlice> Ipv6Header for Ipv6Packet<B> {
267    fn get_fixed_header(&self) -> &FixedHeader {
268        &self.fixed_hdr
269    }
270}
271
272impl<B: SplitByteSlice> ParsablePacket<B, ()> for Ipv6Packet<B> {
273    type Error = Ipv6ParseError;
274
275    fn parse_metadata(&self) -> ParseMetadata {
276        let header_len = Ref::bytes(&self.fixed_hdr).len() + self.extension_hdrs.bytes().len();
277        ParseMetadata::from_packet(header_len, self.body.len(), 0)
278    }
279
280    fn parse<BV: BufferView<B>>(buffer: BV, _args: ()) -> Result<Self, Ipv6ParseError> {
281        Ipv6PacketRaw::parse(buffer, ()).and_then(Ipv6Packet::try_from_raw)
282    }
283}
284
285impl<B: SplitByteSlice> FromRaw<Ipv6PacketRaw<B>, ()> for Ipv6Packet<B> {
286    type Error = Ipv6ParseError;
287
288    fn try_from_raw_with(raw: Ipv6PacketRaw<B>, _args: ()) -> Result<Self, Self::Error> {
289        let fixed_hdr = raw.fixed_hdr;
290
291        let extension_hdrs = match raw.extension_hdrs {
292            MaybeParsed::Complete(v) => Records::try_from_raw(v),
293            MaybeParsed::Incomplete(buffer) => {
294                // If raw parser failed then try full parser again. This is
295                // expected to fail, but the returned error may be different
296                // from the error reported by the raw parser.
297                let context = Ipv6ExtensionHeaderParsingContext::new(fixed_hdr.next_hdr);
298                match Records::<_, Ipv6ExtensionHeaderImpl>::parse_with_context(buffer, context) {
299                    Err(err) => Err(err),
300                    Ok(_) => panic!("Extension Header parsing succeeded after raw parse failure."),
301                }
302            }
303        };
304        let extension_hdrs = extension_hdrs.map_err(|e| ext_hdr_err_fn(&fixed_hdr, e))?;
305
306        // Under RFC 8200 Section 4.5:
307        // - For non-initial fragments (offset > 0), the Next Header field is ignored during
308        //   reassembly.
309        // - For initial fragments (offset == 0), the Next Header field indicates the type of the
310        //   first header in the Fragmentable Part, which may be an extension header (e.g.
311        //   Destination Options) or an upper-layer protocol.
312        // In either case, upper-layer protocol validation is deferred until the packet is
313        // reassembled, so `proto` is only required to be a valid upper-layer protocol when no
314        // Fragment header is present.
315        let (body, proto) =
316            raw.body_proto.expect("Unable to retrieve Ipv6Proto or MaybeParsed body from raw");
317        debug_assert!(
318            extension_hdrs
319                .iter()
320                .any(|ext_hdr| matches!(ext_hdr, Ipv6ExtensionHeader::Fragment { .. }))
321                || is_valid_next_header_upper_layer(proto.into())
322        );
323
324        let body = match body {
325            MaybeParsed::Complete(b) => b,
326            MaybeParsed::Incomplete(_b) => {
327                return debug_err!(Err(ParseError::Format.into()), "IPv6 body unretrievable.");
328            }
329        };
330
331        // check that the lengths match:
332        //
333        // As per Section 3 of RFC 8200, payload length includes the length of
334        // the extension headers as well.
335        if extension_hdrs.bytes().len() + body.len() != usize::from(fixed_hdr.payload_len.get()) {
336            return debug_err!(
337                Err(ParseError::Format.into()),
338                "Payload len does not match body and extension headers"
339            );
340        }
341
342        // validate IP version in header
343        if fixed_hdr.version() != 6 {
344            return debug_err!(
345                Err(ParseError::Format.into()),
346                "unexpected IP version: {}",
347                fixed_hdr.version()
348            );
349        }
350
351        Ok(Ipv6Packet { fixed_hdr, extension_hdrs, body, proto })
352    }
353}
354
355impl<B, C> PartialSerializer<C> for Ipv6Packet<B>
356where
357    B: SplitByteSlice,
358    C: IpSerializationContext<Ipv6>,
359{
360    // TODO(https://fxbug.dev/473824085): Keep the reference to the whole
361    // serialized packet and return it from `partial_serialize()` as
362    // `PartialSerializeResult::Slice`.
363
364    fn partial_serialize_new_buf<BB: GrowBufferMut, A: LayoutBufferAlloc<BB>>(
365        &self,
366        _context: &mut C,
367        constraints: PacketConstraints,
368        alloc: A,
369    ) -> Result<(BB, usize), SerializeError<A::Error>> {
370        // Copy IP header, extension header and up to 64 bytes of the body,
371        // which includes the transport headers.
372        let fixed_hdr = Ref::bytes(&self.fixed_hdr);
373        let extension_hdrs = self.extension_hdrs.bytes();
374        let fixed_hdr_len = fixed_hdr.len();
375        let header_len = fixed_hdr_len + extension_hdrs.len();
376        let body_to_copy = self.body().len().min(TRANSPORT_HEADER_MAX_SIZE);
377        let outer_header_len = constraints.header_len();
378        let mut buffer = alloc.layout_alloc(outer_header_len + header_len, body_to_copy, 0)?;
379        buffer.with_parts_mut(|prefix, mut body, _suffix| {
380            let extensions_pos = outer_header_len + fixed_hdr_len;
381            prefix[outer_header_len..extensions_pos].copy_from_slice(fixed_hdr);
382            prefix[extensions_pos..].copy_from_slice(extension_hdrs);
383            body.copy_from_slice(&self.body()[..body_to_copy]);
384        });
385        buffer.grow_front(header_len);
386        let total_size = header_len + self.body.len();
387        Ok((buffer, total_size))
388    }
389}
390
391impl<B: SplitByteSlice> Ipv6Packet<B> {
392    /// Returns an iterator over the extension headers.
393    ///
394    /// For fragmented packets, this will only yield extension headers up to and
395    /// including the Fragment header, as any headers following the Fragment
396    /// header are part of the Fragmentable Part and remain in the packet body
397    /// until reassembly.
398    pub fn iter_extension_hdrs(&self) -> impl Iterator<Item = Ipv6ExtensionHeader<'_>> {
399        self.extension_hdrs.iter()
400    }
401
402    /// The packet body.
403    pub fn body(&self) -> &[u8] {
404        &self.body
405    }
406
407    /// The Differentiated Services Code Point (DSCP) and the Explicit
408    /// Congestion Notification (ECN).
409    pub fn dscp_and_ecn(&self) -> DscpAndEcn {
410        self.fixed_hdr.dscp_and_ecn()
411    }
412
413    /// The flow label.
414    pub fn flowlabel(&self) -> u32 {
415        self.fixed_hdr.flowlabel()
416    }
417
418    /// The Upper layer protocol for this packet.
419    ///
420    /// This is found in the fixed header's Next Header if there are no extension
421    /// headers, or the Next Header value in the last extension header if there are.
422    /// This also uses the same codes, encoded by the Rust type `Ipv6Proto`.
423    ///
424    /// Note that for fragmented packets, this returns the Next Header value
425    /// from the Fragment header, which identifies the initial header type of the
426    /// Fragmentable Part of the original packet (which may be an extension header
427    /// such as Destination Options or an upper-layer protocol). For non-initial
428    /// fragments, this value describes the initial header type of the reassembled
429    /// packet and does not necessarily describe the data immediately following
430    /// in this fragment. Callers must reassemble fragmented packets (including
431    /// atomic fragments, whose Fragment Offset and M flag are both zero) before
432    /// treating this value as an upper-layer protocol.
433    pub fn proto(&self) -> Ipv6Proto {
434        self.proto
435    }
436
437    /// The source IP address represented as an [`Ipv6SourceAddr`].
438    ///
439    /// Unlike [`IpHeader::src_ip`], `src_ipv6` returns an `Ipv6SourceAddr`,
440    /// which represents the valid values that a source address can take
441    /// (namely, a unicast or unspecified address) or `None` if the address is
442    /// invalid (namely, a multicast address or an ipv4-mapped-ipv6 address).
443    pub fn src_ipv6(&self) -> Option<Ipv6SourceAddr> {
444        Ipv6SourceAddr::new(self.fixed_hdr.src_ip)
445    }
446
447    /// Return a buffer that is a copy of the header bytes in this
448    /// packet, including the fixed header and the extension headers
449    /// preceding the fragment extension header, but without the fragment
450    /// extension header.
451    ///
452    /// Note, extension header parsing stops after the first fragment
453    /// extension header, so any extension headers following it are part of
454    /// the packet's body, and are not included.
455    ///
456    /// # Panics
457    ///
458    /// Panics if there is no fragment extension header in this packet.
459    pub fn copy_header_bytes_for_fragment(&self) -> Vec<u8> {
460        // Since the final header will not include a fragment header, we don't
461        // need to allocate bytes for it (`IPV6_FRAGMENT_EXT_HDR_LEN` bytes).
462        let expected_bytes_len = self.header_len() - IPV6_FRAGMENT_EXT_HDR_LEN;
463        let mut bytes = Vec::with_capacity(expected_bytes_len);
464
465        bytes.extend_from_slice(Ref::bytes(&self.fixed_hdr));
466
467        // Extension header parsing stops after the first fragment header, so
468        // the fragment header must be the last extension header. Find the
469        // offset of the Next Header field identifying the fragment header,
470        // which is either in the fixed header or in the extension header
471        // immediately preceding the fragment header.
472        let mut iter = self.extension_hdrs.iter();
473        let fragment_hdr_next_header_offset = loop {
474            let next_header_offset = iter.context().next_header_offset;
475            // This should never panic because this function must only be
476            // called when the packet has a fragment extension header.
477            match iter
478                .next()
479                .expect("exhausted all extension headers without finding fragment header")
480            {
481                Ipv6ExtensionHeader::Fragment { .. } => break next_header_offset,
482                Ipv6ExtensionHeader::HopByHopOptions { .. }
483                | Ipv6ExtensionHeader::DestinationOptions { .. }
484                | Ipv6ExtensionHeader::Routing { .. } => {}
485            }
486        };
487        debug_assert!(iter.next().is_none(), "fragment header must be the last extension header");
488
489        // Copy extension headers that appear before the fragment header.
490        let extension_hdr_bytes = self.extension_hdrs.bytes();
491        let (preceding_hdrs, fragment_hdr) =
492            extension_hdr_bytes.split_at(extension_hdr_bytes.len() - IPV6_FRAGMENT_EXT_HDR_LEN);
493        bytes.extend_from_slice(preceding_hdrs);
494
495        // Update the Next Header field identifying the fragment header to the
496        // next header value within the fragment header, which is located in
497        // its first byte.
498        bytes[fragment_hdr_next_header_offset] = fragment_hdr[0];
499
500        // `bytes`'s length should be exactly `expected_bytes_len`.
501        assert_eq!(bytes.len(), expected_bytes_len);
502        bytes
503    }
504
505    /// Returns an [`Ipv6PerFragmentHeaderBuilder`] for this packet.
506    ///
507    /// This builder will include the extension headers that should be part
508    /// of the per-fragment header, and omit the extension headers that should
509    /// be part of the fragment body. All bytes in the original packet after
510    /// `per_fragment_builder().headers_len()` should be considered the fragment
511    /// body.
512    ///
513    /// Per [RFC 8200 Section 4.5]:
514    ///   The Per-Fragment headers must consist of the IPv6 header plus any
515    ///   extension headers that must be processed by nodes en route to the
516    ///   destination, that is, all headers up to and including the Routing
517    ///   header if present, else the Hop-by-Hop Options header if present,
518    ///   else no extension headers.
519    ///
520    /// [RFC 8200 Section 4.5]: https://datatracker.ietf.org/doc/html/rfc8200#section-4.5
521    pub fn per_fragment_builder(&self) -> Ipv6PerFragmentHeaderBuilder<Vec<u8>> {
522        let mut routing_point = None;
523        let mut hbh_point = None;
524        let mut iter = self.extension_hdrs.iter();
525        let mut is_first_ext_hdr = true;
526
527        while let Some(ext_hdr) = iter.next() {
528            match ext_hdr {
529                Ipv6ExtensionHeader::HopByHopOptions { .. } => {
530                    // Per RFC 8200 Section 4.1
531                    //   IPv6 nodes must accept and attempt to process extension
532                    //   headers in any order and occurring any number of times
533                    //   in the same packet, except for the Hop-by-Hop Options
534                    //   header, which is restricted to appear immediately after
535                    //   an IPv6 header only.
536                    // Therefore we only copy over the Hop-By-Hop option if it
537                    // is first.
538                    if is_first_ext_hdr {
539                        hbh_point = Some((
540                            iter.context().position,
541                            iter.context().next_header_offset,
542                            iter.context().next_header,
543                        ));
544                    }
545                }
546                Ipv6ExtensionHeader::Routing { .. } => {
547                    routing_point = Some((
548                        iter.context().position,
549                        iter.context().next_header_offset,
550                        iter.context().next_header,
551                    ));
552                    break;
553                }
554                _ => {}
555            }
556            is_first_ext_hdr = false;
557        }
558
559        let split_point = routing_point.or(hbh_point);
560        let (meta, next_header) = match split_point {
561            Some((position, next_header_offset, next_header)) => (
562                Some(Ipv6PerFragmentMeta {
563                    ext_hdrs: self.extension_hdrs.bytes()[..position - IPV6_FIXED_HDR_LEN].to_vec(),
564                    first_ext_hdr: Ipv6ExtHdrType::from(self.fixed_hdr.next_hdr),
565                    last_next_hdr_offset: next_header_offset - IPV6_FIXED_HDR_LEN,
566                }),
567                next_header,
568            ),
569            None => (None, self.fixed_hdr.next_hdr),
570        };
571        // NB: All extension headers are after the split point are now part of
572        // of the fragment body. In order to serialize the fragment header
573        // properly, update the protocol for the builder to be the first
574        // extension header in the body (or the upperlayer proto, if none).
575        let mut prefix_builder = self.builder();
576        prefix_builder.proto = Ipv6Proto::from(next_header);
577
578        Ipv6PerFragmentHeaderBuilder { prefix_builder, meta }
579    }
580
581    /// The size of the fixed header plus extension headers.
582    pub fn header_len(&self) -> usize {
583        Ref::bytes(&self.fixed_hdr).len() + self.extension_hdrs.bytes().len()
584    }
585
586    fn fragment_header_present(&self) -> bool {
587        for ext_hdr in self.extension_hdrs.iter() {
588            if matches!(ext_hdr, Ipv6ExtensionHeader::Fragment { .. }) {
589                return true;
590            }
591        }
592        false
593    }
594
595    /// Construct a builder with the same contents as this packet.
596    pub fn builder(&self) -> Ipv6PacketBuilder {
597        Ipv6PacketBuilder {
598            dscp_and_ecn: self.dscp_and_ecn(),
599            flowlabel: self.flowlabel(),
600            hop_limit: self.hop_limit(),
601            proto: self.proto(),
602            src_ip: self.src_ip(),
603            dst_ip: self.dst_ip(),
604        }
605    }
606
607    /// Performs the header translation part of NAT64 as described in [RFC
608    /// 7915].
609    ///
610    /// `nat64_translate` follows the rules described in RFC 7915 to construct
611    /// the IPv4 equivalent of this IPv6 packet. If the payload is a TCP segment
612    /// or a UDP packet, its checksum will be updated. If the payload is an
613    /// ICMPv6 packet, it will be converted to the equivalent ICMPv4 packet. For
614    /// all other payloads, the payload will be unchanged, and the IP header will
615    /// be translated. On success, a [`Serializer`] is returned which describes
616    /// the new packet to be sent.
617    ///
618    /// Note that the IPv4 TTL/IPv6 Hop Limit field is not modified. It is the
619    /// caller's responsibility to decrement and process this field per RFC
620    /// 7915.
621    ///
622    /// In some cases, the packet has no IPv4 equivalent, in which case the
623    /// value [`Nat64TranslationResult::Drop`] will be returned, instructing the
624    /// caller to silently drop the packet.
625    ///
626    /// # Errors
627    ///
628    /// `nat64_translate` will return an error if support has not yet been
629    /// implemented for translating a particular IP protocol.
630    ///
631    /// [RFC 7915]: https://datatracker.ietf.org/doc/html/rfc7915
632    pub fn nat64_translate(
633        &self,
634        v4_src_addr: Ipv4Addr,
635        v4_dst_addr: Ipv4Addr,
636    ) -> Nat64TranslationResult<
637        impl Serializer<NoOpSerializationContext, Buffer = EmptyBuf> + Debug + '_,
638        Nat64Error,
639    > {
640        // A single `Serializer` type so that all possible return values from
641        // this function have the same type.
642        #[derive(Debug)]
643        enum Nat64Serializer<T, U, O> {
644            Tcp(T),
645            Udp(U),
646            Other(O),
647        }
648        impl<T, U, O> Serializer<NoOpSerializationContext> for Nat64Serializer<T, U, O>
649        where
650            T: Serializer<NoOpSerializationContext, Buffer = EmptyBuf>,
651            U: Serializer<NoOpSerializationContext, Buffer = EmptyBuf>,
652            O: Serializer<NoOpSerializationContext, Buffer = EmptyBuf>,
653        {
654            type Buffer = EmptyBuf;
655            fn serialize<B, P>(
656                self,
657                context: &mut NoOpSerializationContext,
658                outer: PacketConstraints,
659                provider: P,
660            ) -> Result<B, (SerializeError<P::Error>, Self)>
661            where
662                B: GrowBufferMut,
663                P: BufferProvider<Self::Buffer, B>,
664            {
665                match self {
666                    Nat64Serializer::Tcp(serializer) => serializer
667                        .serialize(context, outer, provider)
668                        .map_err(|(err, ser)| (err, Nat64Serializer::Tcp(ser))),
669                    Nat64Serializer::Udp(serializer) => serializer
670                        .serialize(context, outer, provider)
671                        .map_err(|(err, ser)| (err, Nat64Serializer::Udp(ser))),
672                    Nat64Serializer::Other(serializer) => serializer
673                        .serialize(context, outer, provider)
674                        .map_err(|(err, ser)| (err, Nat64Serializer::Other(ser))),
675                }
676            }
677
678            fn serialize_new_buf<B: GrowBufferMut, A: LayoutBufferAlloc<B>>(
679                &self,
680                context: &mut NoOpSerializationContext,
681                outer: PacketConstraints,
682                alloc: A,
683            ) -> Result<B, SerializeError<A::Error>> {
684                match self {
685                    Nat64Serializer::Tcp(serializer) => {
686                        serializer.serialize_new_buf(context, outer, alloc)
687                    }
688                    Nat64Serializer::Udp(serializer) => {
689                        serializer.serialize_new_buf(context, outer, alloc)
690                    }
691                    Nat64Serializer::Other(serializer) => {
692                        serializer.serialize_new_buf(context, outer, alloc)
693                    }
694                }
695            }
696        }
697
698        impl<T, U, O> NestableSerializer for Nat64Serializer<T, U, O>
699        where
700            T: Serializer<NoOpSerializationContext, Buffer = EmptyBuf>,
701            U: Serializer<NoOpSerializationContext, Buffer = EmptyBuf>,
702            O: Serializer<NoOpSerializationContext, Buffer = EmptyBuf>,
703        {
704        }
705
706        // TODO(https://fxbug.dev/42174049): Add support for fragmented packets
707        // forwarding.
708        if self.fragment_header_present() {
709            return Nat64TranslationResult::Err(Nat64Error::NotImplemented);
710        }
711
712        let v4_builder = |v4_proto| {
713            let mut builder =
714                Ipv4PacketBuilder::new(v4_src_addr, v4_dst_addr, self.hop_limit(), v4_proto);
715            builder.dscp_and_ecn(self.dscp_and_ecn());
716
717            // The IPv4 header length is 20 bytes (so IHL field value is 5), as
718            // no header options are present in translated IPv4 packet.
719            // As per RFC 7915 Section 5.1:
720            //  "Internet Header Length:  5 (no IPv4 options)"
721            const IPV4_HEADER_LEN_BYTES: usize = HDR_PREFIX_LEN;
722
723            // As per RFC 7915 Section 5.1,
724            //    "Flags:  The More Fragments flag is set to zero.  The Don't Fragment
725            //        (DF) flag is set as follows: If the size of the translated IPv4
726            //        packet is less than or equal to 1260 bytes, it is set to zero;
727            //        otherwise, it is set to one."
728            builder.df_flag(self.body().len() + IPV4_HEADER_LEN_BYTES > 1260);
729
730            // TODO(https://fxbug.dev/42174049): This needs an update once
731            // we don't return early for fragment_header_present case.
732            builder.fragment_offset(FragmentOffset::ZERO);
733            builder.mf_flag(false);
734
735            builder
736        };
737
738        match self.proto() {
739            Ipv6Proto::Proto(IpProto::Tcp) => {
740                let v4_pkt_builder = v4_builder(Ipv4Proto::Proto(IpProto::Tcp));
741                let args = TcpParseArgs::new(self.src_ip(), self.dst_ip());
742                // TODO(https://fxbug.dev/42174405): We're doing roughly similar work
743                // in valid/invalid parsing case. Remove match statement and
744                // update the checksum in place without needing to parse the TCP
745                // segment once we have ability to update the checksum.
746                match TcpSegment::parse(&mut self.body.as_bytes(), args) {
747                    Ok(tcp) => {
748                        // Creating a new tcp_serializer for IPv6 packet from
749                        // the existing one ensures that checksum is
750                        // updated due to changed IP addresses.
751                        let tcp_serializer =
752                            Nat64Serializer::Tcp(tcp.into_serializer(v4_src_addr, v4_dst_addr));
753                        Nat64TranslationResult::Forward(v4_pkt_builder.wrap_body(tcp_serializer))
754                    }
755                    Err(msg) => {
756                        debug!("Parsing of TCP segment failed: {:?}", msg);
757
758                        // This means we can't create a TCP segment builder with
759                        // updated checksum. Parsing may fail due to a variety of
760                        // reasons, including incorrect checksum in incoming packet.
761                        // We should still return a packet with IP payload copied
762                        // as is from IPv6 to IPv4. This handling is similar to
763                        // the handling of the case with unsupported protocol type
764                        // as done in `Ipv6Proto::Other(val)` case below. The similar
765                        // reasoning from RFC appiles here as well.
766                        let common_serializer =
767                            Nat64Serializer::Other(self.body().into_serializer());
768                        Nat64TranslationResult::Forward(v4_pkt_builder.wrap_body(common_serializer))
769                    }
770                }
771            }
772
773            // TODO(https://fxbug.dev/42174405): We're doing roughly similar work
774            // in valid/invalid parsing case. Remove match statement and
775            // update the checksum in place without needing to parse the UDP segment
776            // once we have ability to update checksum.
777            Ipv6Proto::Proto(IpProto::Udp) => {
778                let v4_pkt_builder = v4_builder(Ipv4Proto::Proto(IpProto::Udp));
779                let args = UdpParseArgs::new(self.src_ip(), self.dst_ip());
780                match UdpPacket::parse(&mut self.body.as_bytes(), args) {
781                    Ok(udp) => {
782                        // Creating a new udp_serializer for IPv6 packet from
783                        // the existing one ensures that checksum is
784                        // updated due to changed IP addresses.
785                        let udp_serializer =
786                            Nat64Serializer::Udp(udp.into_serializer(v4_src_addr, v4_dst_addr));
787                        Nat64TranslationResult::Forward(v4_pkt_builder.wrap_body(udp_serializer))
788                    }
789                    Err(msg) => {
790                        debug!("Parsing of UDP packet failed: {:?}", msg);
791
792                        // This means we can't create a UDP packet builder with
793                        // updated checksum. Parsing may fail due to a variety of
794                        // reasons, including incorrect checksum in incoming packet.
795                        // We should still return a packet with IP payload copied
796                        // as is from IPv6 to IPv4. This handling is similar to
797                        // the handling of the case with unsupported protocol type
798                        // as done in `Ipv6Proto::Other(val)` case below. The similar
799                        // reasoning from RFC appiles here as well.
800
801                        let common_serializer =
802                            Nat64Serializer::Other(self.body().into_serializer());
803                        Nat64TranslationResult::Forward(v4_pkt_builder.wrap_body(common_serializer))
804                    }
805                }
806            }
807
808            // TODO(https://fxbug.dev/42174051): Implement ICMP packet translation
809            // support here.
810            Ipv6Proto::Icmpv6 => Nat64TranslationResult::Err(Nat64Error::NotImplemented),
811
812            // For all other protocols, an IPv4 packet must be forwarded even if
813            // the transport layer checksum update is not implemented.
814            // As per RFC 7915 Section 5.1,
815            //     "Protocol:
816            //       ...
817            //
818            //       For the first 'next header' that does not match one of the cases
819            //       above, its Next Header value (which contains the transport
820            //       protocol number) is copied to the protocol field in the IPv4
821            //       header.  This means that all transport protocols are translated.
822            //
823            //       Note:  Some translated protocols will fail at the receiver for
824            //          various reasons: some are known to fail when translated (e.g.,
825            //          IPsec Authentication Header (51)), and others will fail
826            //          checksum validation if the address translation is not checksum
827            //          neutral [RFC6052] and the translator does not update the
828            //          transport protocol's checksum (because the translator doesn't
829            //          support recalculating the checksum for that transport protocol;
830            //          see Section 5.5)."
831            Ipv6Proto::Other(val) => {
832                let v4_pkt_builder = v4_builder(Ipv4Proto::Other(val));
833                let common_serializer = Nat64Serializer::Other(self.body().into_serializer());
834                Nat64TranslationResult::Forward(v4_pkt_builder.wrap_body(common_serializer))
835            }
836
837            Ipv6Proto::NoNextHeader => {
838                let v4_pkt_builder = v4_builder(Ipv4Proto::Other(Ipv6Proto::NoNextHeader.into()));
839                let common_serializer = Nat64Serializer::Other(self.body().into_serializer());
840                Nat64TranslationResult::Forward(v4_pkt_builder.wrap_body(common_serializer))
841            }
842
843            // Don't forward packets that use IANA's reserved protocol; they're
844            // invalid.
845            Ipv6Proto::Proto(IpProto::Reserved) => Nat64TranslationResult::Drop,
846        }
847    }
848
849    /// Copies the packet (Header + Extensions + Body) into a `Vec`.
850    pub fn to_vec(&self) -> Vec<u8> {
851        let Ipv6Packet { fixed_hdr, extension_hdrs, body, proto: _ } = self;
852        let mut buf = Vec::with_capacity(
853            Ref::bytes(&fixed_hdr).len() + extension_hdrs.bytes().len() + body.as_bytes().len(),
854        );
855        buf.extend(Ref::bytes(&fixed_hdr));
856        buf.extend(extension_hdrs.bytes());
857        buf.extend(body.as_bytes());
858        buf
859    }
860}
861
862impl<B: SplitByteSliceMut> Ipv6Packet<B> {
863    /// Set the source IP address.
864    pub fn set_src_ip(&mut self, addr: Ipv6Addr) {
865        self.fixed_hdr.src_ip = addr;
866    }
867
868    /// Set the destination IP address.
869    pub fn set_dst_ip(&mut self, addr: Ipv6Addr) {
870        self.fixed_hdr.dst_ip = addr;
871    }
872
873    /// Set the hop limit.
874    pub fn set_hop_limit(&mut self, hlim: u8) {
875        self.fixed_hdr.hop_limit = hlim;
876    }
877
878    /// The packet body.
879    pub fn body_mut(&mut self) -> &mut [u8] {
880        &mut self.body
881    }
882
883    /// Provides simultaneous access to header, extension headers, and mutable
884    /// body.
885    pub fn parts_with_body_mut(&mut self) -> (&FixedHeader, ExtensionHeaders<'_>, &mut [u8]) {
886        (&self.fixed_hdr, ExtensionHeaders(self.extension_hdrs.as_ref()), &mut self.body)
887    }
888}
889
890impl<B: SplitByteSlice> Debug for Ipv6Packet<B> {
891    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
892        f.debug_struct("Ipv6Packet")
893            .field("src_ip", &self.src_ip())
894            .field("dst_ip", &self.dst_ip())
895            .field("hop_limit", &self.hop_limit())
896            .field("proto", &self.proto())
897            .field("dscp", &self.dscp_and_ecn().dscp())
898            .field("ecn", &self.dscp_and_ecn().ecn())
899            .field("flowlabel", &self.flowlabel())
900            .field("extension headers", &"TODO")
901            .field("body", &alloc::format!("<{} bytes>", self.body.len()))
902            .finish()
903    }
904}
905
906/// The extension headers in an [`Ipv6Packet`].
907pub struct ExtensionHeaders<'a>(Records<&'a [u8], Ipv6ExtensionHeaderImpl>);
908
909impl<'a> ExtensionHeaders<'a> {
910    /// Returns an iterator over the extension headers.
911    pub fn iter(&self) -> impl Iterator<Item = Ipv6ExtensionHeader<'_>> {
912        self.0.iter()
913    }
914
915    /// Returns the raw bytes of the extension headers.
916    pub fn bytes(&self) -> &[u8] {
917        self.0.bytes()
918    }
919}
920
921/// We were unable to parse the extension headers.
922///
923/// As a result, we were unable to determine the upper-layer Protocol Number
924/// (which is stored in the last extension header's Next Header field) and were
925/// unable figure out where the body begins.
926#[derive(Copy, Clone, Debug, Eq, PartialEq)]
927pub struct ExtHdrParseError;
928
929/// A partially parsed and not yet validated IPv6 packet.
930///
931/// `Ipv6PacketRaw` provides minimal parsing of an IPv6 packet, namely
932/// it only requires that the fixed header part ([`HeaderPrefix`]) be retrieved,
933/// all the other parts of the packet may be missing when attempting to create
934/// it.
935///
936/// [`Ipv6Packet`] provides a [`FromRaw`] implementation that can be used to
937/// validate an `Ipv6PacketRaw`.
938pub struct Ipv6PacketRaw<B> {
939    /// A raw packet always contains at least a fully parsed `FixedHeader`.
940    fixed_hdr: Ref<B, FixedHeader>,
941    /// When `extension_hdrs` is [`MaybeParsed::Complete`], it contains the
942    /// `RecordsRaw` that can be validated for full extension headers parsing.
943    /// Otherwise, it just contains the extension header bytes that were
944    /// successfully consumed before reaching an error (typically "buffer
945    /// exhausted").
946    extension_hdrs: MaybeParsed<RecordsRaw<B, Ipv6ExtensionHeaderImpl>, B>,
947    /// The body and upper-layer Protocol Number.
948    ///
949    /// If extension headers failed to parse, this will be
950    /// `Err(ExtHdrParseError)`. Extension headers must be parsed in order to
951    /// find the bounds of the upper-layer payload and to find that last
952    /// extension header's Next Header field, which is the Protocol Number of
953    /// the upper-layer payload.
954    ///
955    /// The body will be [`MaybeParsed::Complete`] if all the body bytes were
956    /// consumed (as stated by the header's payload length value) or
957    /// [`MaybeParsed::Incomplete`] containing the bytes that were present
958    /// otherwise.
959    body_proto: Result<(MaybeParsed<B, B>, Ipv6Proto), ExtHdrParseError>,
960}
961
962impl<B> Ipv6PacketRaw<B> {
963    /// Returns a mutable reference to the body bytes of this [`Ipv6PacketRaw`].
964    ///
965    /// Might not be complete if a full packet was not received.
966    pub fn body_mut(&mut self) -> Option<&mut B> {
967        match self.body_proto {
968            Ok(ref mut b) => match b {
969                (MaybeParsed::Complete(b), _) => Some(b),
970                (MaybeParsed::Incomplete(b), _) => Some(b),
971            },
972            Err(_) => None,
973        }
974    }
975}
976
977impl<B: SplitByteSlice> Ipv6Header for Ipv6PacketRaw<B> {
978    fn get_fixed_header(&self) -> &FixedHeader {
979        &self.fixed_hdr
980    }
981}
982
983impl<B: SplitByteSlice> ParsablePacket<B, ()> for Ipv6PacketRaw<B> {
984    type Error = Ipv6ParseError;
985
986    fn parse<BV: BufferView<B>>(mut buffer: BV, _args: ()) -> Result<Self, Self::Error> {
987        let fixed_hdr = buffer
988            .take_obj_front::<FixedHeader>()
989            .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for header"))?;
990        let payload_len = fixed_hdr.payload_len.get().into();
991        // Trim the buffer if it exceeds the length specified in the header.
992        let _: Option<B> = buffer.len().checked_sub(payload_len).map(|padding| {
993            buffer.take_back(padding).unwrap_or_else(|| {
994                panic!("buffer.len()={} padding={}", buffer.len(), padding);
995            })
996        });
997
998        let mut extension_hdr_context = Ipv6ExtensionHeaderParsingContext::new(fixed_hdr.next_hdr);
999
1000        let extension_hdrs =
1001            RecordsRaw::parse_raw_with_mut_context(&mut buffer, &mut extension_hdr_context)
1002                .map_incomplete(|(b, _)| b);
1003
1004        let body_proto = match &extension_hdrs {
1005            MaybeParsed::Complete(r) => {
1006                let _: &RecordsRaw<B, _> = r;
1007                // If we have extension headers our context's
1008                // (`extension_hdr_context`) `next_header` would be updated with
1009                // the last extension header's Next Header value. This will also
1010                // work if we don't have any extension headers. Let's consider
1011                // that scenario: When we have no extension headers, the Next
1012                // Header value in the fixed header will be a valid upper layer
1013                // protocol value.  `parse_bv_with_mut_context` will return
1014                // almost immediately without doing any actual work when it
1015                // checks the context's (`extension_hdr_context`) `next_header`
1016                // value and ends parsing since, according to our context, its
1017                // data is for an upper layer protocol. Now, since nothing was
1018                // parsed, our context was never modified, so the next header
1019                // value it was initialized with when calling
1020                // `Ipv6ExtensionHeaderParsingContext::new`, will not have
1021                // changed. We simply use that value and assign it to proto
1022                // below.
1023
1024                // Extension header raw parsing only finishes when we have a
1025                // valid next header that is meant for the upper layer, or when
1026                // a fragment header was encountered. The assertion below
1027                // enforces that contract.
1028                assert!(
1029                    extension_hdr_context.saw_fragment
1030                        || is_valid_next_header_upper_layer(extension_hdr_context.next_header)
1031                );
1032                let proto = Ipv6Proto::from(extension_hdr_context.next_header);
1033                let body = MaybeParsed::new_with_min_len(
1034                    buffer.into_rest(),
1035                    payload_len.saturating_sub(extension_hdrs.len()),
1036                );
1037                Ok((body, proto))
1038            }
1039            MaybeParsed::Incomplete(b) => {
1040                let _: &B = b;
1041                Err(ExtHdrParseError)
1042            }
1043        };
1044
1045        Ok(Ipv6PacketRaw { fixed_hdr, extension_hdrs, body_proto })
1046    }
1047
1048    fn parse_metadata(&self) -> ParseMetadata {
1049        let header_len = Ref::bytes(&self.fixed_hdr).len() + self.extension_hdrs.len();
1050        let body_len = self.body_proto.as_ref().map(|(b, _p)| b.len()).unwrap_or(0);
1051        ParseMetadata::from_packet(header_len, body_len, 0)
1052    }
1053}
1054
1055impl<B: SplitByteSlice> Ipv6PacketRaw<B> {
1056    /// Returns the body and upper-layer Protocol Number.
1057    ///
1058    /// If extension headers failed to parse, `body_proto` returns
1059    /// `Err(ExtHdrParseError)`. Extension headers must be parsed in order to
1060    /// find the bounds of the upper-layer payload and to find that last
1061    /// extension header's Next Header field, which is the Protocol Number of
1062    /// the upper-layer payload.
1063    ///
1064    /// Note that extension header parsing stops after the first Fragment
1065    /// header. For packets with a Fragment header, the returned body is the
1066    /// Fragmentable Part of the packet following the Fragment header, and the
1067    /// returned Protocol Number is the Fragment header's Next Header value,
1068    /// which may not be an upper-layer protocol (e.g. it may identify another
1069    /// extension header).
1070    ///
1071    /// The returned body will be [`MaybeParsed::Complete`] if all the body
1072    /// bytes were consumed (as stated by the header's payload length value) or
1073    /// [`MaybeParsed::Incomplete`] containing the bytes that were present
1074    /// otherwise.
1075    pub fn body_proto(&self) -> Result<(MaybeParsed<&[u8], &[u8]>, Ipv6Proto), ExtHdrParseError> {
1076        self.body_proto
1077            .as_ref()
1078            .map(|(mp, proto)| {
1079                (mp.as_ref().map(|b| b.deref()).map_incomplete(|b| b.deref()), *proto)
1080            })
1081            .map_err(|e| *e)
1082    }
1083
1084    /// Returns the body.
1085    ///
1086    /// If extension headers failed to parse, `body` returns
1087    /// `Err(ExtHdrParseError)`. Extension headers must be parsed in order to
1088    /// find the bounds of the upper-layer payload.
1089    ///
1090    /// Note that for packets with a Fragment header, the returned body is the
1091    /// Fragmentable Part of the packet following the Fragment header. See
1092    /// [`Ipv6PacketRaw::body_proto`] for details.
1093    ///
1094    /// The returned body will be [`MaybeParsed::Complete`] if all the body
1095    /// bytes were consumed (as stated by the header's payload length value) or
1096    /// [`MaybeParsed::Incomplete`] containing the bytes that were present
1097    /// otherwise.
1098    pub fn body(&self) -> Result<MaybeParsed<&[u8], &[u8]>, ExtHdrParseError> {
1099        self.body_proto().map(|(body, _proto)| body)
1100    }
1101
1102    /// Returns the upper-layer Protocol Number.
1103    ///
1104    /// If extension headers failed to parse, `body_proto` returns
1105    /// `Err(ExtHdrParseError)`. Extension headers must be parsed in order to
1106    /// find the last extension header's Next Header field, which is the
1107    /// Protocol Number of the upper-layer payload.
1108    ///
1109    /// Note that for packets with a Fragment header, the returned Protocol
1110    /// Number is the Fragment header's Next Header value, which may not be an
1111    /// upper-layer protocol. See [`Ipv6PacketRaw::body_proto`] for details.
1112    pub fn proto(&self) -> Result<Ipv6Proto, ExtHdrParseError> {
1113        self.body_proto().map(|(_body, proto)| proto)
1114    }
1115}
1116
1117impl<B: SplitByteSliceMut> Ipv6PacketRaw<B> {
1118    /// Set the source IP address.
1119    pub fn set_src_ip(&mut self, addr: Ipv6Addr) {
1120        self.fixed_hdr.src_ip = addr;
1121    }
1122
1123    /// Set the destination IP address.
1124    pub fn set_dst_ip(&mut self, addr: Ipv6Addr) {
1125        self.fixed_hdr.dst_ip = addr;
1126    }
1127
1128    /// Set the payload length of the IPv6 packet.
1129    pub fn set_payload_len(&mut self, payload_len: u16) {
1130        self.fixed_hdr.payload_len = U16::new(payload_len);
1131    }
1132}
1133
1134/// A next header that may be either a next layer header or an IPv6 extension
1135/// header.
1136pub enum NextHeader {
1137    /// A next layer header follows.
1138    NextLayer(Ipv6Proto),
1139    /// An extension header follows.
1140    Extension(Ipv6ExtHdrType),
1141}
1142
1143impl From<NextHeader> for u8 {
1144    fn from(next_hdr: NextHeader) -> Self {
1145        match next_hdr {
1146            NextHeader::NextLayer(n) => n.into(),
1147            NextHeader::Extension(e) => e.into(),
1148        }
1149    }
1150}
1151
1152mod sealed {
1153    use super::*;
1154    /// A marker trait for IPv6 headers that can be serialized before header
1155    /// `T`.
1156    ///
1157    /// This trait is used to enforce IPv6 extension header ordering according
1158    /// to [RFC 8200 Section 4.1].
1159    ///
1160    /// [RFC 8200 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc8200#section-4.1
1161    pub trait Ipv6HeaderBefore<T> {}
1162
1163    impl<'a, O, T> Ipv6HeaderBefore<T> for &'a O where O: Ipv6HeaderBefore<T> {}
1164
1165    /// A trait abstracting all types of IPv6 header builders.
1166    pub trait Ipv6HeaderBuilder {
1167        /// Returns an immutable reference to the fixed header builder.
1168        fn fixed_header(&self) -> &Ipv6PacketBuilder;
1169
1170        /// Returns the total header length of the extension headers, including
1171        /// previous extension headers, but excluding the fixed header size.
1172        fn extension_headers_len(&self) -> usize;
1173
1174        /// Serializes the header into `buffer`.
1175        ///
1176        /// `next_header` is the header immediately after the current one.
1177        /// `payload_len` is the total size of the frame after this header.
1178        fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1179            &self,
1180            buffer: &mut BV,
1181            next_header: NextHeader,
1182            payload_len: usize,
1183        );
1184    }
1185}
1186use sealed::{Ipv6HeaderBefore, Ipv6HeaderBuilder};
1187
1188impl<'a, O> Ipv6HeaderBuilder for &'a O
1189where
1190    O: Ipv6HeaderBuilder,
1191{
1192    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1193        O::fixed_header(self)
1194    }
1195
1196    fn extension_headers_len(&self) -> usize {
1197        O::extension_headers_len(self)
1198    }
1199
1200    fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1201        &self,
1202        buffer: &mut BV,
1203        next_header: NextHeader,
1204        payload_len: usize,
1205    ) {
1206        O::serialize_header(self, buffer, next_header, payload_len)
1207    }
1208}
1209
1210/// A helper macro to implement `PacketBuilder` methods for implementers of
1211/// `Ipv6HeaderBuilder`.
1212///
1213/// This can't be a blanket impl because `PacketBuilder` is a foreign trait.
1214macro_rules! impl_packet_builder_base {
1215    {} => {
1216        fn constraints(&self) -> PacketConstraints {
1217            let ext_headers = self.extension_headers_len();
1218            let header_len = IPV6_FIXED_HDR_LEN + ext_headers;
1219            let footer_len = 0;
1220            let min_body_len = 0;
1221            // Extension headers take from the IPv6 available payload size.
1222            // See RFC 8200 Section 3 for details.
1223            let max_body_len = IPV6_MAX_PAYLOAD_LENGTH - ext_headers;
1224            PacketConstraints::new(header_len, footer_len, min_body_len, max_body_len)
1225        }
1226    }
1227}
1228
1229macro_rules! impl_packet_builder {
1230    {} => {
1231        fn context_state(&self) -> C::ContextState {
1232            C::envelope_to_state(IpEnvelope::new(self.extension_headers_len() > 0))
1233        }
1234
1235        fn serialize(
1236            &self,
1237            _context: &mut C,
1238            target: &mut SerializeTarget<'_>,
1239            body: FragmentedBytesMut<'_, '_>,
1240        ) {
1241            let mut bv = &mut target.header;
1242            self.serialize_header(
1243                &mut bv,
1244                NextHeader::NextLayer(
1245                    <Ipv6PacketBuilder as IpPacketBuilder<C, Ipv6>>::proto(self.fixed_header())
1246                ),
1247                body.len(),
1248            );
1249        }
1250    }
1251}
1252
1253macro_rules! impl_partial_packet_builder {
1254    {} => {
1255        fn partial_serialize(
1256            &self,
1257            _context: &mut C,
1258            body_len: usize,
1259            mut buffer: &mut [u8],
1260        ) {
1261            self.serialize_header(
1262                &mut &mut buffer,
1263                NextHeader::NextLayer(
1264                    <Ipv6PacketBuilder as IpPacketBuilder<C, Ipv6>>::proto(self.fixed_header())
1265                ),
1266                body_len,
1267            );
1268        }
1269    }
1270}
1271/// A builder for IPv6 packets.
1272#[derive(Debug, Clone, Eq, PartialEq)]
1273pub struct Ipv6PacketBuilder {
1274    dscp_and_ecn: DscpAndEcn,
1275    flowlabel: u32,
1276    hop_limit: u8,
1277    // The protocol number of the upper layer protocol, not the Next Header
1278    // value of the first extension header (if one exists).
1279    proto: Ipv6Proto,
1280    src_ip: Ipv6Addr,
1281    dst_ip: Ipv6Addr,
1282}
1283
1284impl Ipv6PacketBuilder {
1285    /// Constructs a new `Ipv6PacketBuilder`.
1286    ///
1287    /// The `proto` field encodes the protocol number identifying the upper
1288    /// layer payload, not the Next Header value of the first extension header
1289    /// (if one exists).
1290    pub fn new<S: Into<Ipv6Addr>, D: Into<Ipv6Addr>>(
1291        src_ip: S,
1292        dst_ip: D,
1293        hop_limit: u8,
1294        proto: Ipv6Proto,
1295    ) -> Ipv6PacketBuilder {
1296        Ipv6PacketBuilder {
1297            dscp_and_ecn: DscpAndEcn::default(),
1298            flowlabel: 0,
1299            hop_limit,
1300            proto,
1301            src_ip: src_ip.into(),
1302            dst_ip: dst_ip.into(),
1303        }
1304    }
1305
1306    /// Set the Differentiated Services Code Point (DSCP) and the Explicit
1307    /// Congestion Notification (ECN).
1308    pub fn dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
1309        self.dscp_and_ecn = dscp_and_ecn;
1310    }
1311
1312    /// Set the flowlabel.
1313    ///
1314    /// # Panics
1315    ///
1316    /// `flowlabel` panics if `flowlabel` is greater than 2^20 - 1.
1317    pub fn flowlabel(&mut self, flowlabel: u32) {
1318        assert!(flowlabel <= 1 << 20, "invalid flowlabel: {:x}", flowlabel);
1319        self.flowlabel = flowlabel;
1320    }
1321}
1322
1323impl Ipv6HeaderBuilder for Ipv6PacketBuilder {
1324    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1325        self
1326    }
1327
1328    fn extension_headers_len(&self) -> usize {
1329        0
1330    }
1331
1332    fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1333        &self,
1334        buffer: &mut BV,
1335        next_header: NextHeader,
1336        payload_len: usize,
1337    ) {
1338        buffer
1339            .write_obj_front(&FixedHeader::new(
1340                self.dscp_and_ecn,
1341                self.flowlabel,
1342                {
1343                    // The caller promises to supply a body whose length
1344                    // does not exceed max_body_len. Doing this as a
1345                    // debug_assert (rather than an assert) is fine because,
1346                    // with debug assertions disabled, we'll just write an
1347                    // incorrect header value, which is acceptable if the
1348                    // caller has violated their contract.
1349                    debug_assert!(payload_len <= u16::MAX as usize);
1350                    payload_len as u16
1351                },
1352                next_header.into(),
1353                self.hop_limit,
1354                self.src_ip,
1355                self.dst_ip,
1356            ))
1357            .expect("not enough bytes for IPv6 fixed header");
1358    }
1359}
1360
1361impl NestablePacketBuilder for Ipv6PacketBuilder {
1362    impl_packet_builder_base! {}
1363}
1364
1365impl<C: IpSerializationContext<Ipv6>> PacketBuilder<C> for Ipv6PacketBuilder {
1366    impl_packet_builder! {}
1367}
1368
1369impl<C: IpSerializationContext<Ipv6>> PartialPacketBuilder<C> for Ipv6PacketBuilder {
1370    impl_partial_packet_builder! {}
1371}
1372
1373/// A builder for Ipv6 packets with HBH Options.
1374#[derive(Debug, Clone)]
1375pub struct Ipv6PacketBuilderWithHbhOptions<'a, I> {
1376    prefix_builder: Ipv6PacketBuilder,
1377    hbh_options: AlignedRecordSequenceBuilder<HopByHopOption<'a>, I>,
1378}
1379
1380impl<'a, I> Ipv6PacketBuilderWithHbhOptions<'a, I>
1381where
1382    I: Iterator + Clone,
1383    I::Item: Borrow<HopByHopOption<'a>>,
1384{
1385    /// Creates a IPv6 packet builder with a Hop By Hop Options extension header.
1386    pub fn new<T: IntoIterator<Item = I::Item, IntoIter = I>>(
1387        prefix_builder: Ipv6PacketBuilder,
1388        options: T,
1389    ) -> Option<Ipv6PacketBuilderWithHbhOptions<'a, I>> {
1390        let iter = options.into_iter();
1391        // https://tools.ietf.org/html/rfc2711#section-2.1 specifies that
1392        // an RouterAlert option can only appear once.
1393        if iter
1394            .clone()
1395            .filter(|r| matches!(r.borrow().data, HopByHopOptionData::RouterAlert { .. }))
1396            .count()
1397            > 1
1398        {
1399            return None;
1400        }
1401        let hbh_options = AlignedRecordSequenceBuilder::new(2, iter);
1402        // And we don't want our options to become too long.
1403        if next_multiple_of_eight(2 + hbh_options.serialized_len()) > IPV6_HBH_OPTIONS_MAX_LEN {
1404            return None;
1405        }
1406        Some(Ipv6PacketBuilderWithHbhOptions { prefix_builder, hbh_options })
1407    }
1408
1409    fn aligned_hbh_len(&self) -> usize {
1410        let opt_len = self.hbh_options.serialized_len();
1411        let hbh_len = opt_len + 2;
1412        next_multiple_of_eight(hbh_len)
1413    }
1414}
1415
1416fn next_multiple_of_eight(x: usize) -> usize {
1417    (x + 7) & (!7)
1418}
1419
1420impl<C: IpSerializationContext<Ipv6>> IpPacketBuilder<C, Ipv6> for Ipv6PacketBuilder {
1421    fn new(src_ip: Ipv6Addr, dst_ip: Ipv6Addr, ttl: u8, proto: Ipv6Proto) -> Self {
1422        Ipv6PacketBuilder::new(src_ip, dst_ip, ttl, proto)
1423    }
1424
1425    fn src_ip(&self) -> Ipv6Addr {
1426        self.src_ip
1427    }
1428
1429    fn set_src_ip(&mut self, addr: Ipv6Addr) {
1430        self.src_ip = addr;
1431    }
1432
1433    fn dst_ip(&self) -> Ipv6Addr {
1434        self.dst_ip
1435    }
1436
1437    fn set_dst_ip(&mut self, addr: Ipv6Addr) {
1438        self.dst_ip = addr;
1439    }
1440
1441    fn proto(&self) -> Ipv6Proto {
1442        self.proto
1443    }
1444
1445    fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
1446        self.dscp_and_ecn = dscp_and_ecn;
1447    }
1448}
1449
1450impl<'a, I> Ipv6HeaderBuilder for Ipv6PacketBuilderWithHbhOptions<'a, I>
1451where
1452    I: Iterator + Clone,
1453    I::Item: Borrow<HopByHopOption<'a>>,
1454{
1455    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1456        &self.prefix_builder
1457    }
1458
1459    fn extension_headers_len(&self) -> usize {
1460        self.prefix_builder.extension_headers_len() + self.aligned_hbh_len()
1461    }
1462
1463    fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1464        &self,
1465        buffer: &mut BV,
1466        next_header: NextHeader,
1467        payload_len: usize,
1468    ) {
1469        let aligned_hbh_len = self.aligned_hbh_len();
1470        // The next header in the fixed header now should be 0 (Hop-by-Hop Extension Header)
1471        self.prefix_builder.serialize_header(
1472            buffer,
1473            NextHeader::Extension(Ipv6ExtHdrType::HopByHopOptions),
1474            payload_len + aligned_hbh_len,
1475        );
1476        // take the first two bytes to write in proto and length information.
1477        let mut hbh_header = buffer.take_front(aligned_hbh_len).unwrap();
1478        let hbh_header: &mut [u8] = hbh_header.as_mut();
1479        hbh_header[0] = next_header.into();
1480        hbh_header[1] = u8::try_from((aligned_hbh_len - 8) / 8).expect("extension header too big");
1481        self.hbh_options.serialize_into(&mut hbh_header[2..]);
1482    }
1483}
1484
1485impl<'a, I> NestablePacketBuilder for Ipv6PacketBuilderWithHbhOptions<'a, I>
1486where
1487    I: Iterator + Clone,
1488    I::Item: Borrow<HopByHopOption<'a>>,
1489{
1490    impl_packet_builder_base! {}
1491}
1492
1493impl<'a, I, C: IpSerializationContext<Ipv6>> PacketBuilder<C>
1494    for Ipv6PacketBuilderWithHbhOptions<'a, I>
1495where
1496    I: Iterator + Clone,
1497    I::Item: Borrow<HopByHopOption<'a>>,
1498{
1499    impl_packet_builder! {}
1500}
1501
1502impl<'a, I, C: IpSerializationContext<Ipv6>> PartialPacketBuilder<C>
1503    for Ipv6PacketBuilderWithHbhOptions<'a, I>
1504where
1505    I: Iterator + Clone,
1506    I::Item: Borrow<HopByHopOption<'a>>,
1507{
1508    impl_partial_packet_builder! {}
1509}
1510
1511impl<'a, C: IpSerializationContext<Ipv6>, I> IpPacketBuilder<C, Ipv6>
1512    for Ipv6PacketBuilderWithHbhOptions<'a, I>
1513where
1514    I: Iterator<Item: Borrow<HopByHopOption<'a>>> + Debug + Default + Clone,
1515{
1516    fn new(src_ip: Ipv6Addr, dst_ip: Ipv6Addr, ttl: u8, proto: Ipv6Proto) -> Self {
1517        Ipv6PacketBuilderWithHbhOptions::new(
1518            Ipv6PacketBuilder::new(src_ip, dst_ip, ttl, proto),
1519            I::default(),
1520        )
1521        .expect("packet builder with no options should be valid")
1522    }
1523
1524    fn src_ip(&self) -> Ipv6Addr {
1525        self.prefix_builder.src_ip
1526    }
1527
1528    fn set_src_ip(&mut self, addr: Ipv6Addr) {
1529        self.prefix_builder.src_ip = addr;
1530    }
1531
1532    fn dst_ip(&self) -> Ipv6Addr {
1533        self.prefix_builder.dst_ip
1534    }
1535
1536    fn set_dst_ip(&mut self, addr: Ipv6Addr) {
1537        self.prefix_builder.dst_ip = addr;
1538    }
1539
1540    fn proto(&self) -> Ipv6Proto {
1541        self.prefix_builder.proto
1542    }
1543
1544    fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
1545        <Ipv6PacketBuilder as IpPacketBuilder<C, Ipv6>>::set_dscp_and_ecn(
1546            &mut self.prefix_builder,
1547            dscp_and_ecn,
1548        )
1549    }
1550}
1551
1552/// Metadata about extension headers for the `Ipv6PerFragmentHeaderBuilder`.
1553#[derive(Debug, Clone, Eq, PartialEq)]
1554struct Ipv6PerFragmentMeta<B> {
1555    ext_hdrs: B,
1556    first_ext_hdr: Ipv6ExtHdrType,
1557    last_next_hdr_offset: usize,
1558}
1559
1560/// A builder for IPv6 packets containing the per-fragment extension headers.
1561///
1562/// Generally, this should be wrapped with an
1563/// [`Ipv6PacketBuilderWithFragmentHeader`].
1564#[derive(Debug, Clone, Eq, PartialEq)]
1565pub struct Ipv6PerFragmentHeaderBuilder<B> {
1566    prefix_builder: Ipv6PacketBuilder,
1567    meta: Option<Ipv6PerFragmentMeta<B>>,
1568}
1569
1570impl<B: AsRef<[u8]>> Ipv6PerFragmentHeaderBuilder<B> {
1571    /// Returns the length of the header (fixed header and extension headers).
1572    pub fn header_len(&self) -> usize {
1573        self.extension_headers_len() + IPV6_FIXED_HDR_LEN
1574    }
1575
1576    /// Converts `self` into an identical builder with references to the
1577    /// underlying extension header bytes.
1578    pub fn as_ref(&self) -> Ipv6PerFragmentHeaderBuilder<&[u8]> {
1579        let Self { prefix_builder, meta } = self;
1580        let meta = meta.as_ref().map(
1581            |Ipv6PerFragmentMeta { ext_hdrs, first_ext_hdr, last_next_hdr_offset }| {
1582                Ipv6PerFragmentMeta {
1583                    ext_hdrs: ext_hdrs.as_ref(),
1584                    first_ext_hdr: *first_ext_hdr,
1585                    last_next_hdr_offset: *last_next_hdr_offset,
1586                }
1587            },
1588        );
1589        Ipv6PerFragmentHeaderBuilder { prefix_builder: prefix_builder.clone(), meta }
1590    }
1591}
1592
1593impl<B: AsRef<[u8]>> Ipv6HeaderBuilder for Ipv6PerFragmentHeaderBuilder<B> {
1594    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1595        &self.prefix_builder
1596    }
1597
1598    fn extension_headers_len(&self) -> usize {
1599        self.meta
1600            .as_ref()
1601            .map(|Ipv6PerFragmentMeta { ext_hdrs, .. }| ext_hdrs.as_ref().len())
1602            .unwrap_or(0)
1603    }
1604
1605    fn serialize_header<BB: SplitByteSliceMut, BV: BufferViewMut<BB>>(
1606        &self,
1607        buffer: &mut BV,
1608        next_header: NextHeader,
1609        payload_len: usize,
1610    ) {
1611        let Self { prefix_builder, meta } = self;
1612        match meta {
1613            None => prefix_builder.serialize_header(buffer, next_header, payload_len),
1614            Some(Ipv6PerFragmentMeta { ext_hdrs, first_ext_hdr, last_next_hdr_offset }) => {
1615                let ext_hdrs = ext_hdrs.as_ref();
1616                let ext_hdrs_len = ext_hdrs.len();
1617                prefix_builder.serialize_header(
1618                    buffer,
1619                    NextHeader::Extension(*first_ext_hdr),
1620                    payload_len + ext_hdrs_len,
1621                );
1622                let mut ext_hdr_buf =
1623                    buffer.take_front(ext_hdrs_len).expect("buffer should be long enough");
1624                let ext_hdr_buf: &mut [u8] = ext_hdr_buf.as_mut();
1625                ext_hdr_buf.copy_from_slice(ext_hdrs);
1626                ext_hdr_buf[*last_next_hdr_offset] = u8::from(next_header);
1627            }
1628        }
1629    }
1630}
1631
1632impl<B: AsRef<[u8]>> NestablePacketBuilder for Ipv6PerFragmentHeaderBuilder<B> {
1633    impl_packet_builder_base! {}
1634}
1635
1636impl<B: AsRef<[u8]>, C: IpSerializationContext<Ipv6>> PacketBuilder<C>
1637    for Ipv6PerFragmentHeaderBuilder<B>
1638{
1639    impl_packet_builder! {}
1640}
1641
1642impl<B: AsRef<[u8]>, C: IpSerializationContext<Ipv6>> PartialPacketBuilder<C>
1643    for Ipv6PerFragmentHeaderBuilder<B>
1644{
1645    impl_partial_packet_builder! {}
1646}
1647
1648/// An IPv6 packet builder that includes the fragmentation header.
1649///
1650/// `Ipv6PacketBuilderWithFragmentHeader` wraps another compatible packet
1651/// builder to attach the fragment header on it.
1652///
1653/// See [RFC 8200 Section 2.5] for the fragment header format.
1654///
1655/// [RFC 8200 Section 2.5]: https://datatracker.ietf.org/doc/html/rfc8200#section-4.5
1656#[derive(Debug, Eq, PartialEq)]
1657pub struct Ipv6PacketBuilderWithFragmentHeader<B> {
1658    header_builder: B,
1659    fragment_offset: FragmentOffset,
1660    more_fragments: bool,
1661    identification: u32,
1662}
1663
1664impl<B: Ipv6HeaderBefore<Self>> Ipv6PacketBuilderWithFragmentHeader<B> {
1665    /// Creates a new `Ipv6PacketBuilderWithFragmentHeader`.
1666    pub fn new(
1667        header_builder: B,
1668        fragment_offset: FragmentOffset,
1669        more_fragments: bool,
1670        identification: u32,
1671    ) -> Self {
1672        Self { header_builder, fragment_offset, more_fragments, identification }
1673    }
1674}
1675
1676impl<B> Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<B>> for Ipv6PacketBuilder {}
1677impl<B, I> Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<B>>
1678    for Ipv6PacketBuilderWithHbhOptions<'_, I>
1679{
1680}
1681impl<HB, B> Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<HB>>
1682    for Ipv6PerFragmentHeaderBuilder<B>
1683{
1684}
1685
1686/// A marker trait for all header builder types that can be used to construct
1687/// and serialize IPv6 headers using [`Ipv6PacketBuilderWithFragmentHeader`].
1688pub trait Ipv6PacketBuilderBeforeFragment:
1689    Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<Self>> + Ipv6HeaderBuilder + Sized
1690{
1691}
1692impl<B> Ipv6PacketBuilderBeforeFragment for B where
1693    B: Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<Self>> + Ipv6HeaderBuilder + Sized
1694{
1695}
1696
1697impl<B: Ipv6HeaderBuilder> Ipv6HeaderBuilder for Ipv6PacketBuilderWithFragmentHeader<B> {
1698    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1699        self.header_builder.fixed_header()
1700    }
1701
1702    fn extension_headers_len(&self) -> usize {
1703        self.header_builder.extension_headers_len() + IPV6_FRAGMENT_EXT_HDR_LEN
1704    }
1705
1706    fn serialize_header<BB: SplitByteSliceMut, BV: BufferViewMut<BB>>(
1707        &self,
1708        buffer: &mut BV,
1709        next_header: NextHeader,
1710        payload_len: usize,
1711    ) {
1712        let Self { header_builder, fragment_offset, more_fragments, identification } = self;
1713        let payload_len = payload_len + IPV6_FRAGMENT_EXT_HDR_LEN;
1714        header_builder.serialize_header(
1715            buffer,
1716            NextHeader::Extension(Ipv6ExtHdrType::Fragment),
1717            payload_len,
1718        );
1719        buffer.write_obj_front(&u8::from(next_header)).unwrap();
1720        // Reserved.
1721        let _: BB = buffer.take_front_zero(1).unwrap();
1722        let more_fragments = u16::from(*more_fragments);
1723        buffer
1724            .write_obj_front(&U16::new(fragment_offset.into_raw() << 3 | more_fragments))
1725            .unwrap();
1726        buffer.write_obj_front(&U32::new(*identification)).unwrap();
1727    }
1728}
1729
1730impl<B: Ipv6HeaderBuilder> NestablePacketBuilder for Ipv6PacketBuilderWithFragmentHeader<B> {
1731    impl_packet_builder_base! {}
1732}
1733
1734impl<B: Ipv6HeaderBuilder, C: IpSerializationContext<Ipv6>> PacketBuilder<C>
1735    for Ipv6PacketBuilderWithFragmentHeader<B>
1736{
1737    impl_packet_builder! {}
1738}
1739
1740impl<B: Ipv6HeaderBuilder, C: IpSerializationContext<Ipv6>> PartialPacketBuilder<C>
1741    for Ipv6PacketBuilderWithFragmentHeader<B>
1742{
1743    impl_partial_packet_builder! {}
1744}
1745
1746/// Reassembles a fragmented packet into a parsed IP packet.
1747///
1748/// # Panics
1749///
1750/// Panics if the provided header is too small to hold a valid header.
1751pub(crate) fn reassemble_fragmented_packet<
1752    'a,
1753    B: SplitByteSliceMut,
1754    BV: BufferViewMut<B>,
1755    I: Iterator<Item = &'a [u8]>,
1756>(
1757    mut buffer: BV,
1758    header: &[u8],
1759    body_fragments: I,
1760) -> IpParseResult<Ipv6, ()> {
1761    assert!(header.len() >= IPV6_FIXED_HDR_LEN);
1762
1763    let bytes = buffer.as_mut();
1764
1765    // First, copy over the header data.
1766    bytes[0..header.len()].copy_from_slice(header);
1767    let mut byte_count = header.len();
1768
1769    // Next, copy over the body fragments.
1770    for p in body_fragments {
1771        bytes[byte_count..byte_count + p.len()].copy_from_slice(p);
1772        byte_count += p.len();
1773    }
1774
1775    //
1776    // Fix up the IPv6 header
1777    //
1778
1779    // For IPv6, the payload length is the sum of the length of the
1780    // extension headers and the packet body. The header as it is stored
1781    // includes the IPv6 fixed header and all extension headers, so
1782    // `bytes_count` is the sum of the size of the fixed header,
1783    // extension headers and packet body. To calculate the payload
1784    // length we subtract the size of the fixed header from the total
1785    // byte count of a reassembled packet.
1786    let payload_length = byte_count - IPV6_FIXED_HDR_LEN;
1787
1788    // Make sure that the payload length is not more than the maximum
1789    // possible IPv6 packet length.
1790    if payload_length > usize::from(u16::MAX) {
1791        return debug_err!(
1792            Err(ParseError::Format.into()),
1793            "fragmented packet payload length of {} bytes is too large",
1794            payload_length
1795        );
1796    }
1797
1798    // We know the call to `unwrap` will not fail because we verified the length
1799    // of `header` and copied it's bytes into `bytes`.
1800    let mut header = Ref::<_, FixedHeader>::from_prefix(bytes).unwrap().0;
1801
1802    // Update the payload length field.
1803    header.payload_len.set(u16::try_from(payload_length).unwrap());
1804
1805    Ok(())
1806}
1807
1808#[cfg(test)]
1809mod tests {
1810    use assert_matches::assert_matches;
1811    use packet::{Buf, FragmentedBuffer, ParseBuffer, PartialSerializeResult};
1812    use test_case::test_case;
1813
1814    use crate::ethernet::{EthernetFrame, EthernetFrameLengthCheck};
1815    use crate::testutil::*;
1816
1817    use super::ext_hdrs::*;
1818    use super::*;
1819
1820    const DEFAULT_SRC_IP: Ipv6Addr =
1821        Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
1822    const DEFAULT_DST_IP: Ipv6Addr =
1823        Ipv6Addr::from_bytes([17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]);
1824
1825    const DEFAULT_V4_SRC_IP: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
1826    const DEFAULT_V4_DST_IP: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
1827
1828    #[test]
1829    fn test_parse_serialize_full_tcp() {
1830        use crate::testdata::syn_v6::*;
1831
1832        let mut buf = ETHERNET_FRAME.bytes;
1833        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
1834        verify_ethernet_frame(&frame, ETHERNET_FRAME);
1835
1836        let mut body = frame.body();
1837        let packet = body.parse::<Ipv6Packet<_>>().unwrap();
1838        verify_ipv6_packet(&packet, IPV6_PACKET);
1839
1840        // Verify serialization via builders.
1841        let buffer = packet
1842            .body()
1843            .into_serializer()
1844            .wrap_in(packet.builder())
1845            .wrap_in(frame.builder())
1846            .serialize_vec_outer(&mut NoOpSerializationContext)
1847            .unwrap();
1848        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
1849
1850        // Verify serialization via `to_vec`.
1851        assert_eq!(&packet.to_vec()[..], IPV6_PACKET.bytes);
1852    }
1853
1854    #[test]
1855    fn test_parse_serialize_full_udp() {
1856        use crate::testdata::dns_request_v6::*;
1857
1858        let mut buf = ETHERNET_FRAME.bytes;
1859        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
1860        verify_ethernet_frame(&frame, ETHERNET_FRAME);
1861
1862        let mut body = frame.body();
1863        let packet = body.parse::<Ipv6Packet<_>>().unwrap();
1864        verify_ipv6_packet(&packet, IPV6_PACKET);
1865
1866        // Verify serialization via builders.
1867        let buffer = packet
1868            .body()
1869            .into_serializer()
1870            .wrap_in(packet.builder())
1871            .wrap_in(frame.builder())
1872            .serialize_vec_outer(&mut NoOpSerializationContext)
1873            .unwrap();
1874        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
1875
1876        // Verify serialization via `to_vec`.
1877        assert_eq!(&packet.to_vec()[..], IPV6_PACKET.bytes);
1878    }
1879
1880    #[test]
1881    fn test_parse_serialize_with_extension_headers() {
1882        // NB; Use MLD as test data arbitrarily, because it includes IPv6
1883        // extension headers.
1884        use crate::testdata::mld_router_report::*;
1885
1886        let mut buf = REPORT;
1887        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1888        assert_eq!(packet.iter_extension_hdrs().count(), 1);
1889
1890        // NB: Don't verify serialization via builders, as they omit IPv6
1891        // extension headers.
1892
1893        // Verify serialization via `to_vec`.
1894        assert_eq!(&packet.to_vec()[..], REPORT);
1895    }
1896
1897    fn fixed_hdr_to_bytes(fixed_hdr: FixedHeader) -> [u8; IPV6_FIXED_HDR_LEN] {
1898        zerocopy::transmute!(fixed_hdr)
1899    }
1900
1901    // Return a new FixedHeader with reasonable defaults.
1902    fn new_fixed_hdr() -> FixedHeader {
1903        FixedHeader::new(
1904            DscpAndEcn::new(0, 2),
1905            0x77,
1906            0,
1907            IpProto::Tcp.into(),
1908            64,
1909            DEFAULT_SRC_IP,
1910            DEFAULT_DST_IP,
1911        )
1912    }
1913
1914    #[test]
1915    fn test_parse() {
1916        let mut buf = &fixed_hdr_to_bytes(new_fixed_hdr())[..];
1917        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1918        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
1919        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
1920        assert_eq!(packet.flowlabel(), 0x77);
1921        assert_eq!(packet.hop_limit(), 64);
1922        assert_eq!(packet.fixed_hdr.next_hdr, IpProto::Tcp.into());
1923        assert_eq!(packet.proto(), IpProto::Tcp.into());
1924        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
1925        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
1926        assert_eq!(packet.body(), []);
1927    }
1928
1929    #[test]
1930    fn test_parse_with_ext_hdrs() {
1931        #[rustfmt::skip]
1932        let mut buf = [
1933            // FixedHeader (will be replaced later)
1934            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1935            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1936
1937            // HopByHop Options Extension Header
1938            Ipv6ExtHdrType::Routing.into(), // Next Header
1939            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1940            0,                       // Pad1
1941            1, 0,                    // Pad2
1942            1, 1, 0,                 // Pad3
1943
1944            // Routing Extension Header
1945            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
1946            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1947            0,                                  // Routing Type (Deprecated as per RFC 5095)
1948            0,                                  // Segments Left
1949            0, 0, 0, 0,                         // Reserved
1950            // Addresses for Routing Header w/ Type 0
1951            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
1952            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1953
1954            // Destination Options Extension Header
1955            IpProto::Tcp.into(),    // Next Header
1956            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1957            0,                      // Pad1
1958            1, 0,                   // Pad2
1959            1, 1, 0,                // Pad3
1960            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
1961
1962            // Body
1963            1, 2, 3, 4, 5,
1964        ];
1965        let mut fixed_hdr = new_fixed_hdr();
1966        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
1967        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
1968        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
1969        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
1970        let mut buf = &buf[..];
1971        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1972        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
1973        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
1974        assert_eq!(packet.flowlabel(), 0x77);
1975        assert_eq!(packet.hop_limit(), 64);
1976        assert_eq!(packet.fixed_hdr.next_hdr, Ipv6ExtHdrType::HopByHopOptions.into());
1977        assert_eq!(packet.proto(), IpProto::Tcp.into());
1978        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
1979        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
1980        assert_eq!(packet.body(), [1, 2, 3, 4, 5]);
1981        let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = packet.iter_extension_hdrs().collect();
1982        assert_eq!(ext_hdrs.len(), 3);
1983        // Check first extension header (hop-by-hop options)
1984        if let Ipv6ExtensionHeader::HopByHopOptions { options } = &ext_hdrs[0] {
1985            // Everything should have been a NOP/ignore
1986            assert_eq!(options.iter().count(), 0);
1987        } else {
1988            panic!("Should have matched HopByHopOptions!");
1989        }
1990
1991        // Check second extension header (routing)
1992        if let Ipv6ExtensionHeader::Routing { routing_data } = &ext_hdrs[1] {
1993            assert_eq!(routing_data.routing_type(), Err(RoutingTypeParseError::UnsupportedType(0)));
1994            assert_eq!(routing_data.segments_left(), 0);
1995        } else {
1996            panic!("Should have matched RoutingExtensionHeader: {:?}", &ext_hdrs[1]);
1997        }
1998
1999        // Check the third extension header (destination options)
2000        if let Ipv6ExtensionHeader::DestinationOptions { options } = &ext_hdrs[2] {
2001            // Everything should have been a NOP/ignore
2002            assert_eq!(options.iter().count(), 0);
2003        } else {
2004            panic!("Should have matched DestinationOptions!");
2005        }
2006
2007        // Test with a NoNextHeader as the final Next Header
2008        #[rustfmt::skip]
2009        let mut buf = [
2010            // FixedHeader (will be replaced later)
2011            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2012            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2013
2014            // HopByHop Options Extension Header w/ NoNextHeader as the next header
2015            Ipv6Proto::NoNextHeader.into(), // Next Header
2016            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2017            0,                       // Pad1
2018            1, 0,                    // Pad2
2019            1, 1, 0,                 // Pad3
2020
2021            // Body
2022            1, 2, 3, 4, 5,
2023        ];
2024        let mut fixed_hdr = new_fixed_hdr();
2025        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2026        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2027        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2028        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2029        let mut buf = &buf[..];
2030        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2031        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
2032        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
2033        assert_eq!(packet.flowlabel(), 0x77);
2034        assert_eq!(packet.hop_limit(), 64);
2035        assert_eq!(packet.fixed_hdr.next_hdr, Ipv6ExtHdrType::HopByHopOptions.into());
2036        assert_eq!(packet.proto(), Ipv6Proto::NoNextHeader);
2037        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
2038        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
2039        assert_eq!(packet.body(), [1, 2, 3, 4, 5]);
2040        let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = packet.iter_extension_hdrs().collect();
2041        assert_eq!(ext_hdrs.len(), 1);
2042        // Check first extension header (hop-by-hop options)
2043        if let Ipv6ExtensionHeader::HopByHopOptions { options } = &ext_hdrs[0] {
2044            // Everything should have been a NOP/ignore
2045            assert_eq!(options.iter().count(), 0);
2046        } else {
2047            panic!("Should have matched HopByHopOptions!");
2048        }
2049    }
2050
2051    #[test]
2052    fn test_parse_error() {
2053        // Set the version to 5. The version must be 6.
2054        let mut fixed_hdr = new_fixed_hdr();
2055        fixed_hdr.version_tc_flowlabel[0] = 0x50;
2056        assert_eq!(
2057            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
2058            ParseError::Format.into()
2059        );
2060
2061        // Set the payload len to 2, even though there's no payload.
2062        let mut fixed_hdr = new_fixed_hdr();
2063        fixed_hdr.payload_len = U16::new(2);
2064        assert_eq!(
2065            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
2066            ParseError::Format.into()
2067        );
2068
2069        // Use invalid next header.
2070        let mut fixed_hdr = new_fixed_hdr();
2071        fixed_hdr.next_hdr = 255;
2072        let packet = fixed_hdr_to_bytes(fixed_hdr);
2073
2074        // Raw parsing should succeed even with unrecognized Next Header.
2075        assert!((&packet[..]).parse::<Ipv6PacketRaw<_>>().is_ok());
2076
2077        // Full parse should fail with unrecognized next header error.
2078        assert_eq!(
2079            (&packet[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
2080            Ipv6ParseError::ParameterProblem {
2081                src_ip: DEFAULT_SRC_IP,
2082                dst_ip: DEFAULT_DST_IP,
2083                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2084                pointer: u32::from(NEXT_HEADER_OFFSET),
2085                must_send_icmp: false,
2086                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2087            }
2088        );
2089
2090        // Use ICMP(v4) as next header.
2091        let mut fixed_hdr = new_fixed_hdr();
2092        fixed_hdr.next_hdr = Ipv4Proto::Icmp.into();
2093        assert_eq!(
2094            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
2095            Ipv6ParseError::ParameterProblem {
2096                src_ip: DEFAULT_SRC_IP,
2097                dst_ip: DEFAULT_DST_IP,
2098                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2099                pointer: u32::from(NEXT_HEADER_OFFSET),
2100                must_send_icmp: false,
2101                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2102            }
2103        );
2104
2105        // Test HopByHop extension header not being the very first extension header
2106        #[rustfmt::skip]
2107        let mut buf = [
2108            // FixedHeader (will be replaced later)
2109            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2110            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2111
2112            // Routing Extension Header
2113            Ipv6ExtHdrType::HopByHopOptions.into(),    // Next Header (Valid but HopByHop restricted to first extension header)
2114            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2115            0,                                  // Routing Type
2116            0,                                  // Segments Left
2117            0, 0, 0, 0,                         // Reserved
2118            // Addresses for Routing Header w/ Type 0
2119            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2120            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2121
2122            // HopByHop Options Extension Header
2123            IpProto::Tcp.into(),             // Next Header
2124            0,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2125            0,                                  // Pad1
2126            1, 0,                               // Pad2
2127            1, 1, 0,                            // Pad3
2128
2129            // Body
2130            1, 2, 3, 4, 5,
2131        ];
2132        let mut fixed_hdr = new_fixed_hdr();
2133        fixed_hdr.next_hdr = Ipv6ExtHdrType::Routing.into();
2134        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2135        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2136        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2137        let mut buf = &buf[..];
2138        assert_eq!(
2139            buf.parse::<Ipv6Packet<_>>().unwrap_err(),
2140            Ipv6ParseError::ParameterProblem {
2141                src_ip: DEFAULT_SRC_IP,
2142                dst_ip: DEFAULT_DST_IP,
2143                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2144                pointer: IPV6_FIXED_HDR_LEN as u32,
2145                must_send_icmp: false,
2146                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2147            }
2148        );
2149
2150        // Test Unrecognized Routing Type
2151        #[rustfmt::skip]
2152        let mut buf = [
2153            // FixedHeader (will be replaced later)
2154            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2155            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2156
2157            // Routing Extension Header
2158            IpProto::Tcp.into(),                // Next Header
2159            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2160            255,                                // Routing Type (Invalid)
2161            1,                                  // Segments Left
2162            0, 0, 0, 0,                         // Reserved
2163            // Addresses for Routing Header w/ Type 0
2164            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2165            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2166
2167            // Body
2168            1, 2, 3, 4, 5,
2169        ];
2170        let mut fixed_hdr = new_fixed_hdr();
2171        fixed_hdr.next_hdr = Ipv6ExtHdrType::Routing.into();
2172        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2173        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2174        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2175        let expected_error = Ipv6ParseError::ParameterProblem {
2176            src_ip: DEFAULT_SRC_IP,
2177            dst_ip: DEFAULT_DST_IP,
2178            code: Icmpv6ParameterProblemCode::ErroneousHeaderField,
2179            pointer: (IPV6_FIXED_HDR_LEN as u32) + 2,
2180            must_send_icmp: true,
2181            action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2182        };
2183        assert_eq!((&buf[..]).parse::<Ipv6Packet<_>>().unwrap_err(), expected_error);
2184
2185        // Test an unrecognized Routing Type with an unrecognized Next Header.
2186        // This shouldn't change the result: each header should be processed
2187        // before validating the Next Header field.
2188        buf[IPV6_FIXED_HDR_LEN] = 250; // Next Header (Invalid)
2189
2190        assert_eq!((&buf[..]).parse::<Ipv6Packet<_>>().unwrap_err(), expected_error);
2191    }
2192
2193    #[test]
2194    fn test_parse_all_next_header_values() {
2195        // Test that, when parsing a packet with the fixed header's Next Header
2196        // field set to any value, parsing does not panic. A previous version
2197        // of this code would panic on some Next Header values.
2198
2199        // This packet was found via fuzzing to trigger a panic.
2200        let mut buf = [
2201            0x81, 0x13, 0x27, 0xeb, 0x75, 0x92, 0x33, 0x89, 0x01, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
2202            0x03, 0x70, 0x00, 0x22, 0xf7, 0x30, 0x2c, 0x06, 0xfe, 0xc9, 0x00, 0x2d, 0x3b, 0xeb,
2203            0xad, 0x3e, 0x5c, 0x41, 0xc8, 0x70, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x11, 0x00,
2204            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x4f, 0x4f, 0x6f, 0x4f, 0x4f, 0x4f, 0x4f,
2205            0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x19, 0x19,
2206            0x19, 0x19, 0x19, 0x4f, 0x4f, 0x4f, 0x4f, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2207            0x00, 0x4f, 0x4f, 0x5a, 0x5a, 0x5a, 0xc9, 0x5a, 0x46, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
2208            0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0xe4, 0x5a, 0x5a, 0x5a, 0x5a,
2209        ];
2210
2211        // First, assert that the Next Header value found by the fuzzer (51)
2212        // produces the error we expect.
2213        assert_matches!(
2214            (&buf[..]).parse::<Ipv6Packet<_>>(),
2215            Err(Ipv6ParseError::ParameterProblem {
2216                src_ip: _,
2217                dst_ip: _,
2218                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2219                pointer: 6,
2220                must_send_icmp: false,
2221                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2222            })
2223        );
2224
2225        // Second, ensure that, regardless of the exact result produced, no Next
2226        // Header value causes parsing to panic.
2227        for b in 0u8..=255 {
2228            // Overwrite the Next Header field.
2229            buf[6] = b;
2230            let _: Result<_, _> = (&buf[..]).parse::<Ipv6Packet<_>>();
2231        }
2232    }
2233
2234    #[test]
2235    fn test_esp_packet() {
2236        // Encapsulating Security Payload (ESP) is not supported yet. Verify
2237        // that for ESP packets Ipv6Packet parsing fails, but Ipv6PacketRaw
2238        // parser succeeds.
2239
2240        const ESP_NEXT_HEADER: u8 = 50;
2241
2242        // 1. ESP as first extension header (Next Header in Fixed Header = ESP)
2243        let mut fixed_hdr = new_fixed_hdr();
2244        fixed_hdr.next_hdr = ESP_NEXT_HEADER;
2245        fixed_hdr.payload_len = U16::new(8);
2246        let mut buf = fixed_hdr_to_bytes(fixed_hdr).to_vec();
2247        buf.extend_from_slice(&[0; 8]);
2248
2249        // Ipv6Packet parsing fails.
2250        assert_matches!(
2251            (&buf[..]).parse::<Ipv6Packet<_>>(),
2252            Err(Ipv6ParseError::ParameterProblem {
2253                src_ip: _,
2254                dst_ip: _,
2255                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2256                pointer: 6, // Next Header field in Fixed Header.
2257                must_send_icmp: false,
2258                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2259            })
2260        );
2261
2262        // Ipv6PacketRaw parsing succeeds
2263        let mut buf_ref = &buf[..];
2264        assert!(buf_ref.parse::<Ipv6PacketRaw<_>>().is_ok());
2265
2266        // 2. ESP in middle (after Hop-by-Hop)
2267        let mut fixed_hdr = new_fixed_hdr();
2268        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2269        fixed_hdr.payload_len = U16::new(16);
2270        let mut buf = fixed_hdr_to_bytes(fixed_hdr).to_vec();
2271        // Hop-by-Hop header: Next Header = ESP (50), Hdr Ext Len = 0 (8 bytes total)
2272        buf.extend_from_slice(&[ESP_NEXT_HEADER, 0, 0, 0, 0, 0, 0, 0]);
2273        // ESP body
2274        buf.extend_from_slice(&[0; 8]);
2275
2276        // Ipv6Packet parsing fails
2277        assert_matches!(
2278            (&buf[..]).parse::<Ipv6Packet<_>>(),
2279            Err(Ipv6ParseError::ParameterProblem {
2280                src_ip: _,
2281                dst_ip: _,
2282                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2283                pointer: 40, // Next Header in the Hop-by-Hop header.
2284                must_send_icmp: false,
2285                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2286            })
2287        );
2288
2289        // Ipv6PacketRaw parsing succeeds
2290        let mut buf_ref = &buf[..];
2291        assert!(buf_ref.parse::<Ipv6PacketRaw<_>>().is_ok());
2292    }
2293
2294    #[test]
2295    fn test_parse_ext_hdr_unrecognized_next_header() {
2296        // Test that parsing an IPv6 packet with an unrecognized Next Header value
2297        // in an extension header succeeds for Ipv6PacketRaw, but fails for Ipv6Packet.
2298
2299        #[rustfmt::skip]
2300        let mut buf = [
2301            // FixedHeader (will be replaced later)
2302            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2303            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2304
2305            // HopByHop Options Extension Header
2306            250,                     // Next Header (unrecognized next header type)
2307            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2308            0,                       // Pad1
2309            1, 0,                    // Pad2
2310            1, 1, 0,                 // Pad3
2311
2312            // Body
2313            1, 2, 3, 4, 5,
2314        ];
2315        let mut fixed_hdr = new_fixed_hdr();
2316        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2317        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2318        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2319        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2320
2321        // Raw parsing should succeed.
2322        assert!((&buf[..]).parse::<Ipv6PacketRaw<_>>().is_ok());
2323
2324        // Full packet validation should fail.
2325        assert_eq!(
2326            (&buf[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
2327            Ipv6ParseError::ParameterProblem {
2328                src_ip: DEFAULT_SRC_IP,
2329                dst_ip: DEFAULT_DST_IP,
2330                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2331                pointer: IPV6_FIXED_HDR_LEN as u32,
2332                must_send_icmp: false,
2333                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2334            }
2335        );
2336    }
2337
2338    #[test]
2339    fn test_partial_parse() {
2340        use core::convert::TryInto as _;
2341        use core::ops::Deref as _;
2342
2343        // Can't partial parse extension headers:
2344        #[rustfmt::skip]
2345        let mut buf = [
2346            // FixedHeader (will be replaced later)
2347            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2348            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2349
2350            // HopByHop Options Extension Header
2351            IpProto::Tcp.into(), // Next Header
2352            0,                   // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2353            0,                   // Pad1
2354            1, 0,                // Pad2
2355            1, 1, 0,             // Pad3
2356
2357            // Body
2358            1, 2, 3, 4, 5,
2359        ];
2360        let len = buf.len() - IPV6_FIXED_HDR_LEN;
2361        let len = len.try_into().unwrap();
2362        let make_fixed_hdr = || {
2363            let mut fixed_hdr = new_fixed_hdr();
2364            fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2365            fixed_hdr.payload_len = U16::new(len);
2366            fixed_hdr
2367        };
2368        // make HopByHop malformed:
2369        const MALFORMED_BYTE: u8 = 10;
2370        buf[IPV6_FIXED_HDR_LEN + 1] = MALFORMED_BYTE;
2371        let fixed_hdr = fixed_hdr_to_bytes(make_fixed_hdr());
2372        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr);
2373        let mut buf = &buf[..];
2374        let partial = buf.parse::<Ipv6PacketRaw<_>>().unwrap();
2375        let Ipv6PacketRaw { fixed_hdr, extension_hdrs, body_proto } = &partial;
2376        assert_eq!(fixed_hdr.deref(), &make_fixed_hdr());
2377        let b = extension_hdrs.as_ref().incomplete().unwrap();
2378        assert_eq!(*b, &[IpProto::Tcp.into(), MALFORMED_BYTE][..]);
2379        assert_eq!(body_proto, &Err(ExtHdrParseError));
2380        assert!(Ipv6Packet::try_from_raw(partial).is_err());
2381
2382        // Incomplete body:
2383        let mut buf = [
2384            // FixedHeader (will be replaced later)
2385            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2386            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Body
2387            1, 2, 3, 4, 5,
2388        ];
2389        let make_fixed_hdr = || {
2390            let mut fixed_hdr = new_fixed_hdr();
2391            fixed_hdr.next_hdr = IpProto::Tcp.into();
2392            fixed_hdr.payload_len = U16::new(10);
2393            fixed_hdr
2394        };
2395        let fixed_hdr = fixed_hdr_to_bytes(make_fixed_hdr());
2396        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr);
2397        let mut parsebuff = &buf[..];
2398        let partial = parsebuff.parse::<Ipv6PacketRaw<_>>().unwrap();
2399        let Ipv6PacketRaw { fixed_hdr, extension_hdrs, body_proto } = &partial;
2400        assert_eq!(fixed_hdr.deref(), &make_fixed_hdr());
2401        assert_eq!(extension_hdrs.as_ref().complete().unwrap().deref(), []);
2402        let (body, proto) = body_proto.unwrap();
2403        assert_eq!(body.incomplete().unwrap(), &buf[IPV6_FIXED_HDR_LEN..]);
2404        assert_eq!(proto, IpProto::Tcp.into());
2405        assert!(Ipv6Packet::try_from_raw(partial).is_err());
2406    }
2407
2408    // Return a stock Ipv6PacketBuilder with reasonable default values.
2409    fn new_builder() -> Ipv6PacketBuilder {
2410        Ipv6PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, 64, IpProto::Tcp.into())
2411    }
2412
2413    #[test]
2414    fn test_serialize() {
2415        let mut builder = new_builder();
2416        builder.dscp_and_ecn(DscpAndEcn::new(0x12, 3));
2417        builder.flowlabel(0x10405);
2418        let mut buf = (&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
2419            .into_serializer()
2420            .wrap_in(builder)
2421            .serialize_vec_outer(&mut NoOpSerializationContext)
2422            .unwrap();
2423        // assert that we get the literal bytes we expected
2424        assert_eq!(
2425            buf.as_ref(),
2426            &[
2427                100, 177, 4, 5, 0, 10, 6, 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
2428                16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, 1, 2, 3, 4,
2429                5, 6, 7, 8, 9
2430            ][..],
2431        );
2432
2433        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2434        // assert that when we parse those bytes, we get the values we set in
2435        // the builder
2436        assert_eq!(packet.dscp_and_ecn().dscp(), 0x12);
2437        assert_eq!(packet.dscp_and_ecn().ecn(), 3);
2438        assert_eq!(packet.flowlabel(), 0x10405);
2439    }
2440
2441    #[test]
2442    fn test_partial_serialize() {
2443        let mut builder = new_builder();
2444        builder.dscp_and_ecn(DscpAndEcn::new(0x12, 3));
2445        builder.flowlabel(0x10405);
2446        const BODY: &[u8] = &[0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2447        let packet = (&BODY).into_serializer().wrap_in(builder);
2448
2449        // Note that this header is different from the one in test_serialize
2450        // because the checksum is not calculated.
2451        const HEADER: &[u8] = &[
2452            100, 177, 4, 5, 0, 10, 6, 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
2453            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
2454        ];
2455        const PACKET_SIZE: usize = HEADER.len() + BODY.len();
2456
2457        // PartialSerializer serializes the header only if the buffer is
2458        // large enough to fit the whole header.
2459        let buf = assert_matches!(
2460            packet.partial_serialize(&mut NoOpSerializationContext, packet::new_buf_vec),
2461            Ok(PartialSerializeResult::NewBuffer { buffer, total_size: PACKET_SIZE }) => buffer
2462        );
2463        assert_eq!(buf.as_ref(), HEADER);
2464    }
2465
2466    #[test]
2467    fn test_serialize_zeroes() {
2468        // Test that Ipv6PacketBuilder::serialize properly zeroes memory before
2469        // serializing the header.
2470        let mut buf_0 = [0; IPV6_FIXED_HDR_LEN];
2471        let _: Buf<&mut [u8]> = Buf::new(&mut buf_0[..], IPV6_FIXED_HDR_LEN..)
2472            .wrap_in(new_builder())
2473            .serialize_vec_outer(&mut NoOpSerializationContext)
2474            .unwrap()
2475            .unwrap_a();
2476        let mut buf_1 = [0xFF; IPV6_FIXED_HDR_LEN];
2477        let _: Buf<&mut [u8]> = Buf::new(&mut buf_1[..], IPV6_FIXED_HDR_LEN..)
2478            .wrap_in(new_builder())
2479            .serialize_vec_outer(&mut NoOpSerializationContext)
2480            .unwrap()
2481            .unwrap_a();
2482        assert_eq!(&buf_0[..], &buf_1[..]);
2483    }
2484
2485    #[test]
2486    fn test_packet_builder_proto_not_next_header() {
2487        // Test that Ipv6PacketBuilder's `proto` field is used as the Protocol
2488        // Number for the upper layer payload, not the Next Header value for the
2489        // extension header.
2490        let mut buf = (&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
2491            .into_serializer()
2492            .wrap_in(
2493                Ipv6PacketBuilderWithHbhOptions::new(
2494                    new_builder(),
2495                    &[HopByHopOption {
2496                        action: ExtensionHeaderOptionAction::SkipAndContinue,
2497                        mutable: false,
2498                        data: HopByHopOptionData::RouterAlert { data: 0 },
2499                    }],
2500                )
2501                .unwrap(),
2502            )
2503            .serialize_vec_outer(&mut NoOpSerializationContext)
2504            .unwrap();
2505        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2506        assert_eq!(packet.proto(), IpProto::Tcp.into());
2507        assert_eq!(packet.next_header(), Ipv6ExtHdrType::HopByHopOptions.into());
2508    }
2509
2510    #[test]
2511    #[should_panic(expected = "SizeLimitExceeded, Nested { inner: Buf { buf:")]
2512    fn test_serialize_panic_packet_length() {
2513        // Test that a packet whose payload is longer than 2^16 - 1 bytes is
2514        // rejected.
2515        let _: Buf<&mut [u8]> = Buf::new(&mut [0; 1 << 16][..], ..)
2516            .wrap_in(new_builder())
2517            .serialize_vec_outer(&mut NoOpSerializationContext)
2518            .unwrap()
2519            .unwrap_a();
2520    }
2521
2522    #[test]
2523    #[should_panic(expected = "exhausted all extension headers without finding fragment header")]
2524    fn test_copy_header_bytes_for_fragment_without_ext_hdrs() {
2525        let mut buf = &fixed_hdr_to_bytes(new_fixed_hdr())[..];
2526        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2527        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2528    }
2529
2530    #[test]
2531    #[should_panic(expected = "exhausted all extension headers without finding fragment header")]
2532    fn test_copy_header_bytes_for_fragment_with_1_ext_hdr_no_fragment() {
2533        #[rustfmt::skip]
2534        let mut buf = [
2535            // FixedHeader (will be replaced later)
2536            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2537            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2538
2539            // HopByHop Options Extension Header
2540            IpProto::Tcp.into(),     // Next Header
2541            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2542            0,                       // Pad1
2543            1, 0,                    // Pad2
2544            1, 1, 0,                 // Pad3
2545
2546            // Body
2547            1, 2, 3, 4, 5,
2548        ];
2549        let mut fixed_hdr = new_fixed_hdr();
2550        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2551        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2552        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2553        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2554        let mut buf = &buf[..];
2555        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2556        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2557    }
2558
2559    #[test]
2560    #[should_panic(expected = "exhausted all extension headers without finding fragment header")]
2561    fn test_copy_header_bytes_for_fragment_with_2_ext_hdr_no_fragment() {
2562        #[rustfmt::skip]
2563        let mut buf = [
2564            // FixedHeader (will be replaced later)
2565            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2566            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2567
2568            // HopByHop Options Extension Header
2569            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2570            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2571            0,                       // Pad1
2572            1, 0,                    // Pad2
2573            1, 1, 0,                 // Pad3
2574
2575            // Destination Options Extension Header
2576            IpProto::Tcp.into(),    // Next Header
2577            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2578            0,                      // Pad1
2579            1, 0,                   // Pad2
2580            1, 1, 0,                // Pad3
2581            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2582
2583            // Body
2584            1, 2, 3, 4, 5,
2585        ];
2586        let mut fixed_hdr = new_fixed_hdr();
2587        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2588        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2589        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2590        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2591        let mut buf = &buf[..];
2592        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2593        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2594    }
2595
2596    #[test]
2597    fn test_copy_header_bytes_for_fragment() {
2598        //
2599        // Only a fragment extension header
2600        //
2601
2602        #[rustfmt::skip]
2603        let mut bytes = [
2604            // FixedHeader (will be replaced later)
2605            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2606            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2607
2608            // Fragment Extension Header
2609            IpProto::Tcp.into(),     // Next Header
2610            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2611            0, 0,                    // Fragment Offset, Res, M (M_flag)
2612            1, 1, 1, 1,              // Identification
2613
2614            // Body
2615            1, 2, 3, 4, 5,
2616        ];
2617        let mut fixed_hdr = new_fixed_hdr();
2618        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2619        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2620        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2621        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2622        let mut buf = &bytes[..];
2623        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2624        let copied_bytes = packet.copy_header_bytes_for_fragment();
2625        bytes[6] = IpProto::Tcp.into();
2626        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN]);
2627
2628        //
2629        // Fragment header after a single extension header
2630        //
2631
2632        #[rustfmt::skip]
2633        let mut bytes = [
2634            // FixedHeader (will be replaced later)
2635            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2636            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2637
2638            // HopByHop Options Extension Header
2639            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2640            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2641            0,                       // Pad1
2642            1, 0,                    // Pad2
2643            1, 1, 0,                 // Pad3
2644
2645            // Fragment Extension Header
2646            IpProto::Tcp.into(),     // Next Header
2647            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2648            0, 0,                    // Fragment Offset, Res, M (M_flag)
2649            1, 1, 1, 1,              // Identification
2650
2651            // Body
2652            1, 2, 3, 4, 5,
2653        ];
2654        let mut fixed_hdr = new_fixed_hdr();
2655        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2656        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2657        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2658        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2659        let mut buf = &bytes[..];
2660        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2661        let copied_bytes = packet.copy_header_bytes_for_fragment();
2662        bytes[IPV6_FIXED_HDR_LEN] = IpProto::Tcp.into();
2663        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN + 8]);
2664
2665        //
2666        // Fragment header after many extension headers (many = 2)
2667        //
2668
2669        #[rustfmt::skip]
2670        let mut bytes = [
2671            // FixedHeader (will be replaced later)
2672            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2673            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2674
2675            // HopByHop Options Extension Header
2676            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2677            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2678            0,                       // Pad1
2679            1, 0,                    // Pad2
2680            1, 1, 0,                 // Pad3
2681
2682            // Destination Options Extension Header
2683            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2684            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2685            0,                      // Pad1
2686            1, 0,                   // Pad2
2687            1, 1, 0,                // Pad3
2688            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2689
2690            // Fragment Extension Header
2691            IpProto::Tcp.into(),     // Next Header
2692            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2693            0, 0,                    // Fragment Offset, Res, M (M_flag)
2694            1, 1, 1, 1,              // Identification
2695
2696            // Body
2697            1, 2, 3, 4, 5,
2698        ];
2699        let mut fixed_hdr = new_fixed_hdr();
2700        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2701        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2702        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2703        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2704        let mut buf = &bytes[..];
2705        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2706        let copied_bytes = packet.copy_header_bytes_for_fragment();
2707        bytes[IPV6_FIXED_HDR_LEN + 8] = IpProto::Tcp.into();
2708        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN + 24]);
2709
2710        //
2711        // Fragment header before an extension header
2712        //
2713
2714        #[rustfmt::skip]
2715        let mut bytes = [
2716            // FixedHeader (will be replaced later)
2717            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2718            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2719
2720            // Fragment Extension Header
2721            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2722            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2723            0, 0,                    // Fragment Offset, Res, M (M_flag)
2724            1, 1, 1, 1,              // Identification
2725
2726            // Destination Options Extension Header (part of fragmentable payload)
2727            IpProto::Tcp.into(),    // Next Header
2728            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2729            0,                      // Pad1
2730            1, 0,                   // Pad2
2731            1, 1, 0,                // Pad3
2732            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2733
2734            // Body
2735            1, 2, 3, 4, 5,
2736        ];
2737        let mut fixed_hdr = new_fixed_hdr();
2738        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2739        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2740        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2741        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2742        let mut buf = &bytes[..];
2743        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2744        let copied_bytes = packet.copy_header_bytes_for_fragment();
2745        let mut expected_bytes = Vec::new();
2746        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2747        expected_bytes[usize::from(NEXT_HEADER_OFFSET)] = Ipv6ExtHdrType::DestinationOptions.into();
2748        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2749        // The Destination Options header is in the packet's body.
2750        assert_eq!(packet.body(), &bytes[IPV6_FIXED_HDR_LEN + IPV6_FRAGMENT_EXT_HDR_LEN..]);
2751
2752        //
2753        // Fragment header before many extension headers (many = 2)
2754        //
2755
2756        #[rustfmt::skip]
2757        let mut bytes = [
2758            // FixedHeader (will be replaced later)
2759            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2760            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2761
2762            // Fragment Extension Header
2763            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2764            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2765            0, 0,                    // Fragment Offset, Res, M (M_flag)
2766            1, 1, 1, 1,              // Identification
2767
2768            // Destination Options Extension Header (part of fragmentable payload)
2769            Ipv6ExtHdrType::Routing.into(),    // Next Header
2770            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2771            0,                      // Pad1
2772            1, 0,                   // Pad2
2773            1, 1, 0,                // Pad3
2774            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2775
2776            // Routing extension header (part of fragmentable payload)
2777            IpProto::Tcp.into(),                // Next Header
2778            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2779            0,                                  // Routing Type (Deprecated as per RFC 5095)
2780            0,                                  // Segments Left
2781            0, 0, 0, 0,                         // Reserved
2782            // Addresses for Routing Header w/ Type 0
2783            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2784            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2785
2786            // Body
2787            1, 2, 3, 4, 5,
2788        ];
2789        let mut fixed_hdr = new_fixed_hdr();
2790        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2791        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2792        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2793        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2794        let mut buf = &bytes[..];
2795        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2796        let copied_bytes = packet.copy_header_bytes_for_fragment();
2797        let mut expected_bytes = Vec::new();
2798        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2799        expected_bytes[usize::from(NEXT_HEADER_OFFSET)] = Ipv6ExtHdrType::DestinationOptions.into();
2800        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2801        // The Destination Options and Routing Header are in the packet's body.
2802        assert_eq!(packet.body(), &bytes[IPV6_FIXED_HDR_LEN + IPV6_FRAGMENT_EXT_HDR_LEN..]);
2803
2804        //
2805        // Fragment header between extension headers
2806        //
2807
2808        const HBH_EXT_HDR_LEN: usize = 8;
2809        #[rustfmt::skip]
2810        let mut bytes = [
2811            // FixedHeader (will be replaced later)
2812            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2813            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2814
2815            // HopByHop Options Extension Header
2816            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2817            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2818            0,                       // Pad1
2819            1, 0,                    // Pad2
2820            1, 1, 0,                 // Pad3
2821
2822            // Fragment Extension Header
2823            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2824            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2825            0, 0,                    // Fragment Offset, Res, M (M_flag)
2826            1, 1, 1, 1,              // Identification
2827
2828            // Destination Options Extension Header (part of fragmentable payload)
2829            IpProto::Tcp.into(),    // Next Header
2830            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2831            0,                      // Pad1
2832            1, 0,                   // Pad2
2833            1, 1, 0,                // Pad3
2834            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2835
2836            // Body
2837            1, 2, 3, 4, 5,
2838        ];
2839        let mut fixed_hdr = new_fixed_hdr();
2840        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2841        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2842        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2843        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2844        let mut buf = &bytes[..];
2845        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2846        let copied_bytes = packet.copy_header_bytes_for_fragment();
2847        let mut expected_bytes = Vec::new();
2848        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN + HBH_EXT_HDR_LEN]);
2849        expected_bytes[IPV6_FIXED_HDR_LEN] = Ipv6ExtHdrType::DestinationOptions.into();
2850        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2851        // The Destination Options header is in the packet's body.
2852        assert_eq!(
2853            packet.body(),
2854            &bytes[IPV6_FIXED_HDR_LEN + HBH_EXT_HDR_LEN + IPV6_FRAGMENT_EXT_HDR_LEN..]
2855        );
2856
2857        //
2858        // Multiple fragment extension headers
2859        //
2860
2861        #[rustfmt::skip]
2862        let mut bytes = [
2863            // FixedHeader (will be replaced later)
2864            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2865            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2866
2867            // Fragment Extension Header
2868            Ipv6ExtHdrType::Fragment.into(),     // Next Header
2869            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2870            0, 0,                    // Fragment Offset, Res, M (M_flag)
2871            1, 1, 1, 1,              // Identification
2872
2873            // Fragment Extension Header (part of fragmentable payload)
2874            IpProto::Tcp.into(),     // Next Header
2875            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2876            0, 0,                    // Fragment Offset, Res, M (M_flag)
2877            2, 2, 2, 2,              // Identification
2878
2879            // Body
2880            1, 2, 3, 4, 5,
2881        ];
2882        let mut fixed_hdr = new_fixed_hdr();
2883        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2884        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2885        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2886        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2887        let mut buf = &bytes[..];
2888        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2889        let copied_bytes = packet.copy_header_bytes_for_fragment();
2890        let mut expected_bytes = Vec::new();
2891        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2892        expected_bytes[usize::from(NEXT_HEADER_OFFSET)] = Ipv6ExtHdrType::Fragment.into();
2893        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2894        assert_eq!(packet.body(), &bytes[IPV6_FIXED_HDR_LEN + IPV6_FRAGMENT_EXT_HDR_LEN..]);
2895
2896        //
2897        // Fragment header immediately following Routing header.
2898        // Regression test for https://fxbug.dev/517297331.
2899        //
2900
2901        #[rustfmt::skip]
2902        let mut bytes = [
2903            // FixedHeader (will be replaced later)
2904            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2905            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2906
2907            // HopByHop Options Extension Header
2908            Ipv6ExtHdrType::Routing.into(), // Next Header (Routing)
2909            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2910            0,                       // Pad1
2911            1, 0,                    // Pad2
2912            1, 1, 0,                 // Pad3
2913
2914            // Routing extension header
2915            Ipv6ExtHdrType::Fragment.into(), // Next Header (Fragment)
2916            4,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2917            0,                       // Routing Type
2918            0,                       // Segments Left
2919            0, 0, 0, 0,              // Reserved
2920            // Addresses for Routing Header w/ Type 0
2921            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2922            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2923
2924            // Fragment Extension Header
2925            IpProto::Tcp.into(),     // Next Header (TCP)
2926            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2927            0, 0,                    // Fragment Offset, Res, M (M_flag)
2928            1, 1, 1, 1,              // Identification
2929
2930            // Body (TCP packet mock bytes)
2931            1, 2, 3, 4, 5,
2932        ];
2933        let mut fixed_hdr = new_fixed_hdr();
2934        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2935        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2936        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2937        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2938        let mut buf = &bytes[..];
2939        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2940        let copied_bytes = packet.copy_header_bytes_for_fragment();
2941        let mut expected_bytes = Vec::new();
2942        // 8 (HopByHop) + (8 + 16 + 16) (Routing).
2943        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN + 48]);
2944        expected_bytes[IPV6_FIXED_HDR_LEN + 8] = IpProto::Tcp.into();
2945        assert_eq!(copied_bytes, expected_bytes);
2946    }
2947
2948    #[test_case(
2949        &[],
2950        &[],
2951        None;
2952        "no_ext_hdrs"
2953    )]
2954    #[test_case(
2955        &[Ipv6ExtHdrType::DestinationOptions],
2956        &[],
2957        Some(Ipv6ExtHdrType::DestinationOptions);
2958        "ignore_dst_options"
2959    )]
2960    #[test_case(
2961        &[
2962            Ipv6ExtHdrType::DestinationOptions,
2963            Ipv6ExtHdrType::Routing,
2964            Ipv6ExtHdrType::DestinationOptions
2965        ],
2966        &[Ipv6ExtHdrType::DestinationOptions, Ipv6ExtHdrType::Routing],
2967        Some(Ipv6ExtHdrType::DestinationOptions);
2968        "include_routing_and_everything_before"
2969    )]
2970    #[test_case(
2971        &[Ipv6ExtHdrType::HopByHopOptions, Ipv6ExtHdrType::DestinationOptions],
2972        &[Ipv6ExtHdrType::HopByHopOptions],
2973        Some(Ipv6ExtHdrType::DestinationOptions);
2974        "include_hop_by_hop_if_first"
2975    )]
2976    #[test_case(
2977        &[
2978            Ipv6ExtHdrType::HopByHopOptions,
2979            Ipv6ExtHdrType::DestinationOptions,
2980            Ipv6ExtHdrType::Routing
2981        ],
2982        &[
2983            Ipv6ExtHdrType::HopByHopOptions,
2984            Ipv6ExtHdrType::DestinationOptions,
2985            Ipv6ExtHdrType::Routing
2986        ],
2987        None;
2988        "routing_header_takes_precedence_over_hop_by_hop"
2989    )]
2990    fn test_per_fragment_header_builder(
2991        original_ext_hdrs: &[Ipv6ExtHdrType],
2992        expected_ext_hdrs: &[Ipv6ExtHdrType],
2993        expected_next_hdr: Option<Ipv6ExtHdrType>,
2994    ) {
2995        #[rustfmt::skip]
2996        fn build_routing_header(nh: u8) -> [u8; 40] {
2997            [
2998                nh, 4,  0,  0,  0,  0,  0,  0,
2999                1,  2,  3,  4,  5,  6,  7,  8,
3000                9,  10, 11, 12, 13, 14, 15, 16,
3001                17, 18, 19, 20, 21, 22, 23, 24,
3002                25, 26, 27, 28, 29, 30, 31, 32
3003            ]
3004        }
3005        fn build_hop_by_hop_header(nh: u8) -> [u8; 8] {
3006            [nh, 0, 0, 1, 0, 1, 1, 0]
3007        }
3008        #[rustfmt::skip]
3009        fn build_destination_options_header(nh: u8) -> [u8; 16] {
3010            [
3011                nh, 1, 0, 1, 0, 1, 1, 0,
3012                1,  6, 0, 0, 0, 0, 0, 0
3013            ]
3014        }
3015        fn build_fragment_header(nh: u8, id: u32) -> [u8; 8] {
3016            let [id1, id2, id3, id4] = id.to_be_bytes();
3017            [nh, 0, 0, 0, id1, id2, id3, id4]
3018        }
3019        fn build_header_bytes(ext_hdrs: &[Ipv6ExtHdrType], final_header: u8) -> Vec<u8> {
3020            // Prepare the fixed header.
3021            let mut fixed_hdr = new_fixed_hdr();
3022            if ext_hdrs.is_empty() {
3023                fixed_hdr.next_hdr = final_header;
3024            } else {
3025                fixed_hdr.next_hdr = u8::from(ext_hdrs[0]);
3026            }
3027
3028            // Prepare the extension headers.
3029            let mut ext_hdr_bytes = Vec::new();
3030            for i in 0..ext_hdrs.len() {
3031                let next_header =
3032                    if i + 1 >= ext_hdrs.len() { final_header } else { u8::from(ext_hdrs[i + 1]) };
3033                match ext_hdrs[i] {
3034                    Ipv6ExtHdrType::DestinationOptions => ext_hdr_bytes
3035                        .extend_from_slice(&build_destination_options_header(next_header)),
3036                    Ipv6ExtHdrType::Routing => {
3037                        ext_hdr_bytes.extend_from_slice(&build_routing_header(next_header))
3038                    }
3039                    Ipv6ExtHdrType::HopByHopOptions => {
3040                        ext_hdr_bytes.extend_from_slice(&build_hop_by_hop_header(next_header))
3041                    }
3042                    h => panic!("unexpected header type: {h}"),
3043                }
3044            }
3045
3046            let mut bytes = fixed_hdr_to_bytes(fixed_hdr).to_vec();
3047            bytes.extend_from_slice(&ext_hdr_bytes[..]);
3048            bytes
3049        }
3050
3051        // Generate the original packet.
3052        const BODY: [u8; 5] = [1, 2, 3, 4, 5];
3053        let payload_header = u8::from(IpProto::Tcp);
3054        let mut bytes = build_header_bytes(original_ext_hdrs, payload_header);
3055        bytes.extend_from_slice(&BODY);
3056        let len = u16::try_from(bytes.len() - IPV6_FIXED_HDR_LEN).expect("should fit in a u16");
3057        bytes.as_mut_slice()[IPV6_PAYLOAD_LEN_BYTE_RANGE].copy_from_slice(&len.to_be_bytes());
3058        let mut buf = &bytes[..];
3059        let packet = buf.parse::<Ipv6Packet<_>>().expect("parse should succeed");
3060
3061        // Serialize the header directly.
3062        let serialized = packet
3063            .per_fragment_builder()
3064            .wrap_body(EmptyBuf)
3065            .serialize_vec_outer(&mut NoOpSerializationContext)
3066            .unwrap()
3067            .unwrap_b();
3068        let expected_next_hdr = expected_next_hdr.map(u8::from).unwrap_or(payload_header);
3069        let mut expected_bytes = build_header_bytes(expected_ext_hdrs, expected_next_hdr);
3070        let len =
3071            u16::try_from(expected_bytes.len() - IPV6_FIXED_HDR_LEN).expect("should fit in a u16");
3072        expected_bytes.as_mut_slice()[IPV6_PAYLOAD_LEN_BYTE_RANGE]
3073            .copy_from_slice(&len.to_be_bytes());
3074        assert_eq!(serialized.as_ref(), &expected_bytes[..]);
3075
3076        // Serialize the per fragment header, followed by a fragment header.
3077        // NB: Everything from the original packet that wasn't included in the
3078        // header is part of the body (i.e. skipped extension headers).
3079        let builder = packet.per_fragment_builder();
3080        let body = &bytes[builder.header_len()..];
3081        const ID: u32 = 0x12345678;
3082        let frag_builder =
3083            Ipv6PacketBuilderWithFragmentHeader::new(builder, FragmentOffset::ZERO, false, ID);
3084        let serialized = frag_builder
3085            .wrap_body(body.into_serializer())
3086            .serialize_vec_outer(&mut NoOpSerializationContext)
3087            .unwrap()
3088            .unwrap_b();
3089        let mut expected_bytes =
3090            build_header_bytes(expected_ext_hdrs, u8::from(Ipv6ExtHdrType::Fragment));
3091        expected_bytes.extend_from_slice(&build_fragment_header(expected_next_hdr, ID));
3092        expected_bytes.extend_from_slice(body);
3093        let len =
3094            u16::try_from(expected_bytes.len() - IPV6_FIXED_HDR_LEN).expect("should fit in a u16");
3095        expected_bytes.as_mut_slice()[IPV6_PAYLOAD_LEN_BYTE_RANGE]
3096            .copy_from_slice(&len.to_be_bytes());
3097        assert_eq!(serialized.as_ref(), &expected_bytes[..]);
3098    }
3099
3100    #[test]
3101    fn test_next_multiple_of_eight() {
3102        for x in 0usize..=IPV6_HBH_OPTIONS_MAX_LEN {
3103            let y = next_multiple_of_eight(x);
3104            assert_eq!(y % 8, 0);
3105            assert!(y >= x);
3106            if x % 8 == 0 {
3107                assert_eq!(x, y);
3108            } else {
3109                assert_eq!(x + (8 - x % 8), y);
3110            }
3111        }
3112    }
3113
3114    fn create_ipv4_and_ipv6_builders(
3115        proto_v4: Ipv4Proto,
3116        proto_v6: Ipv6Proto,
3117    ) -> (Ipv4PacketBuilder, Ipv6PacketBuilder) {
3118        const IP_DSCP_AND_ECN: DscpAndEcn = DscpAndEcn::new(0x12, 3);
3119        const IP_TTL: u8 = 64;
3120
3121        let mut ipv4_builder =
3122            Ipv4PacketBuilder::new(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP, IP_TTL, proto_v4);
3123        ipv4_builder.dscp_and_ecn(IP_DSCP_AND_ECN);
3124        ipv4_builder.df_flag(false);
3125        ipv4_builder.mf_flag(false);
3126        ipv4_builder.fragment_offset(FragmentOffset::ZERO);
3127
3128        let mut ipv6_builder =
3129            Ipv6PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, IP_TTL, proto_v6);
3130        ipv6_builder.dscp_and_ecn(IP_DSCP_AND_ECN);
3131        ipv6_builder.flowlabel(0x456);
3132
3133        (ipv4_builder, ipv6_builder)
3134    }
3135
3136    fn create_tcp_ipv4_and_ipv6_pkt()
3137    -> (packet::Either<EmptyBuf, Buf<Vec<u8>>>, packet::Either<EmptyBuf, Buf<Vec<u8>>>) {
3138        use crate::tcp::TcpSegmentBuilder;
3139        use core::num::NonZeroU16;
3140
3141        let tcp_src_port: NonZeroU16 = NonZeroU16::new(20).unwrap();
3142        let tcp_dst_port: NonZeroU16 = NonZeroU16::new(30).unwrap();
3143        const TCP_SEQ_NUM: u32 = 4321;
3144        const TCP_ACK_NUM: Option<u32> = Some(1234);
3145        const TCP_WINDOW_SIZE: u16 = 12345;
3146        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
3147
3148        let (ipv4_builder, ipv6_builder) =
3149            create_ipv4_and_ipv6_builders(IpProto::Tcp.into(), IpProto::Tcp.into());
3150
3151        let tcp_builder = TcpSegmentBuilder::new(
3152            DEFAULT_V4_SRC_IP,
3153            DEFAULT_V4_DST_IP,
3154            tcp_src_port,
3155            tcp_dst_port,
3156            TCP_SEQ_NUM,
3157            TCP_ACK_NUM,
3158            TCP_WINDOW_SIZE,
3159        );
3160
3161        let v4_pkt_buf = (&PAYLOAD)
3162            .into_serializer()
3163            .wrap_in(tcp_builder)
3164            .wrap_in(ipv4_builder)
3165            .serialize_vec_outer(&mut NoOpSerializationContext)
3166            .expect("Failed to serialize to v4_pkt_buf");
3167
3168        let v6_tcp_builder = TcpSegmentBuilder::new(
3169            DEFAULT_SRC_IP,
3170            DEFAULT_DST_IP,
3171            tcp_src_port,
3172            tcp_dst_port,
3173            TCP_SEQ_NUM,
3174            TCP_ACK_NUM,
3175            TCP_WINDOW_SIZE,
3176        );
3177
3178        let v6_pkt_buf = (&PAYLOAD)
3179            .into_serializer()
3180            .wrap_in(v6_tcp_builder)
3181            .wrap_in(ipv6_builder)
3182            .serialize_vec_outer(&mut NoOpSerializationContext)
3183            .expect("Failed to serialize to v4_pkt_buf");
3184
3185        (v4_pkt_buf, v6_pkt_buf)
3186    }
3187
3188    #[test]
3189    fn test_nat64_translate_tcp() {
3190        let (expected_v4_pkt_buf, mut v6_pkt_buf) = create_tcp_ipv4_and_ipv6_pkt();
3191
3192        let parsed_v6_packet =
3193            v6_pkt_buf.parse::<Ipv6Packet<_>>().expect("Failed to parse v6_pkt_buf");
3194        let nat64_translation_result =
3195            parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
3196
3197        let serializable_pkt =
3198            assert_matches!(nat64_translation_result, Nat64TranslationResult::Forward(s) => s);
3199
3200        let translated_v4_pkt_buf = serializable_pkt
3201            .serialize_vec_outer(&mut NoOpSerializationContext)
3202            .expect("Failed to serialize to translated_v4_pkt_buf");
3203
3204        assert_eq!(
3205            expected_v4_pkt_buf.to_flattened_vec(),
3206            translated_v4_pkt_buf.to_flattened_vec()
3207        );
3208    }
3209
3210    fn create_udp_ipv4_and_ipv6_pkt()
3211    -> (packet::Either<EmptyBuf, Buf<Vec<u8>>>, packet::Either<EmptyBuf, Buf<Vec<u8>>>) {
3212        use crate::udp::UdpPacketBuilder;
3213        use core::num::NonZeroU16;
3214
3215        let udp_src_port: NonZeroU16 = NonZeroU16::new(35000).unwrap();
3216        let udp_dst_port: NonZeroU16 = NonZeroU16::new(53).unwrap();
3217        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
3218
3219        let (ipv4_builder, ipv6_builder) =
3220            create_ipv4_and_ipv6_builders(IpProto::Udp.into(), IpProto::Udp.into());
3221
3222        let v4_udp_builder = UdpPacketBuilder::new(
3223            DEFAULT_V4_SRC_IP,
3224            DEFAULT_V4_DST_IP,
3225            Some(udp_src_port),
3226            udp_dst_port,
3227        );
3228
3229        let v4_pkt_buf = (&PAYLOAD)
3230            .into_serializer()
3231            .wrap_in(v4_udp_builder)
3232            .wrap_in(ipv4_builder)
3233            .serialize_vec_outer(&mut NoOpSerializationContext)
3234            .expect("Unable to serialize to v4_pkt_buf");
3235
3236        let v6_udp_builder =
3237            UdpPacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, Some(udp_src_port), udp_dst_port);
3238
3239        let v6_pkt_buf = (&PAYLOAD)
3240            .into_serializer()
3241            .wrap_in(v6_udp_builder)
3242            .wrap_in(ipv6_builder)
3243            .serialize_vec_outer(&mut NoOpSerializationContext)
3244            .expect("Unable to serialize to v6_pkt_buf");
3245
3246        (v4_pkt_buf, v6_pkt_buf)
3247    }
3248
3249    #[test]
3250    fn test_nat64_translate_udp() {
3251        let (expected_v4_pkt_buf, mut v6_pkt_buf) = create_udp_ipv4_and_ipv6_pkt();
3252
3253        let parsed_v6_packet =
3254            v6_pkt_buf.parse::<Ipv6Packet<_>>().expect("Unable to parse Ipv6Packet");
3255        let nat64_translation_result =
3256            parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
3257
3258        let serializable_pkt = assert_matches!(nat64_translation_result,
3259                                               Nat64TranslationResult::Forward(s) => s);
3260
3261        let translated_v4_pkt_buf = serializable_pkt
3262            .serialize_vec_outer(&mut NoOpSerializationContext)
3263            .expect("Unable to serialize to translated_v4_pkt_buf");
3264
3265        assert_eq!(
3266            expected_v4_pkt_buf.to_flattened_vec(),
3267            translated_v4_pkt_buf.to_flattened_vec()
3268        );
3269    }
3270
3271    #[test]
3272    fn test_nat64_translate_non_tcp_udp_icmp() {
3273        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
3274
3275        let (ipv4_builder, ipv6_builder) =
3276            create_ipv4_and_ipv6_builders(Ipv4Proto::Other(59), Ipv6Proto::Other(59));
3277
3278        let expected_v4_pkt_buf = (&PAYLOAD)
3279            .into_serializer()
3280            .wrap_in(ipv4_builder)
3281            .serialize_vec_outer(&mut NoOpSerializationContext)
3282            .expect("Unable to serialize to expected_v4_pkt_buf");
3283
3284        let mut v6_pkt_buf = (&PAYLOAD)
3285            .into_serializer()
3286            .wrap_in(ipv6_builder)
3287            .serialize_vec_outer(&mut NoOpSerializationContext)
3288            .expect("Unable to serialize to v6_pkt_buf");
3289
3290        let translated_v4_pkt_buf = {
3291            let parsed_v6_packet = v6_pkt_buf
3292                .parse::<Ipv6Packet<_>>()
3293                .expect("Unable to serialize to translated_v4_pkt_buf");
3294
3295            let nat64_translation_result =
3296                parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
3297
3298            let serializable_pkt = assert_matches!(nat64_translation_result,
3299                                                   Nat64TranslationResult::Forward(s) => s);
3300
3301            let translated_buf = serializable_pkt
3302                .serialize_vec_outer(&mut NoOpSerializationContext)
3303                .expect("Unable to serialize to translated_buf");
3304
3305            translated_buf
3306        };
3307
3308        assert_eq!(
3309            expected_v4_pkt_buf.to_flattened_vec(),
3310            translated_v4_pkt_buf.to_flattened_vec()
3311        );
3312    }
3313
3314    #[test_case(new_builder(), true; "fixed header more frags")]
3315    #[test_case(Ipv6PacketBuilderWithHbhOptions::new(
3316        new_builder(),
3317        &[HopByHopOption {
3318            action: ExtensionHeaderOptionAction::SkipAndContinue,
3319            mutable: false,
3320            data: HopByHopOptionData::RouterAlert { data: 0 },
3321        }]).unwrap(), false; "hbh last frag")]
3322    fn ipv6_packet_builder_with_fragment_header<
3323        B: Ipv6HeaderBuilder + Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<B>> + Debug,
3324    >(
3325        inner: B,
3326        more_fragments: bool,
3327    ) {
3328        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
3329        let fragment_offset = FragmentOffset::new(13).unwrap();
3330        let identification = 0xABCDABCD;
3331        let builder = Ipv6PacketBuilderWithFragmentHeader::new(
3332            inner,
3333            fragment_offset,
3334            more_fragments,
3335            identification,
3336        );
3337        let mut serialized = builder
3338            .wrap_body(PAYLOAD.into_serializer())
3339            .serialize_vec_outer(&mut NoOpSerializationContext)
3340            .unwrap()
3341            .unwrap_b();
3342        let packet = serialized.parse::<Ipv6Packet<_>>().unwrap();
3343        assert!(packet.fragment_header_present());
3344        assert_eq!(packet.proto(), Ipv6Proto::Proto(IpProto::Tcp));
3345        let fragment_data = packet
3346            .extension_hdrs
3347            .into_iter()
3348            .find_map(|ext_hdr| match ext_hdr {
3349                Ipv6ExtensionHeader::Fragment { fragment_data } => Some(fragment_data),
3350                _ => None,
3351            })
3352            .unwrap();
3353        assert_eq!(fragment_data.fragment_offset(), fragment_offset);
3354        assert_eq!(fragment_data.identification(), identification);
3355        assert_eq!(fragment_data.m_flag(), more_fragments);
3356    }
3357
3358    // Tests that the PacketBuilder implementations correct the maximum body
3359    // length in PacketConstraints to remove any extension header bytes used.
3360    #[test]
3361    fn extension_headers_take_from_max_body_size() {
3362        let builder = new_builder();
3363        assert_eq!(builder.constraints().max_body_len(), IPV6_MAX_PAYLOAD_LENGTH);
3364        let builder =
3365            Ipv6PacketBuilderWithFragmentHeader::new(builder, FragmentOffset::ZERO, false, 1234);
3366        assert_eq!(
3367            builder.constraints().max_body_len(),
3368            IPV6_MAX_PAYLOAD_LENGTH - IPV6_FRAGMENT_EXT_HDR_LEN
3369        );
3370    }
3371
3372    #[test]
3373    fn test_partial_serialize_parsed() {
3374        const PACKET_BYTES: &[u8] = &[
3375            100, 177, 4, 5, 0, 10, 6, 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
3376            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, 1, 2, 3, 4, 5, 6, 7,
3377            8, 9,
3378        ];
3379        const PACKET_LEN: usize = PACKET_BYTES.len();
3380        let mut packet_bytes_copy = Vec::from(PACKET_BYTES);
3381        let mut packet_bytes_ref: &mut [u8] = &mut packet_bytes_copy[..];
3382        let packet = packet_bytes_ref.parse::<Ipv6Packet<_>>().unwrap();
3383
3384        let buf = assert_matches!(
3385            packet.partial_serialize(&mut NoOpSerializationContext, packet::new_buf_vec),
3386            Ok(PartialSerializeResult::NewBuffer { buffer, total_size: PACKET_LEN }) => buffer
3387        );
3388        assert_eq!(buf.as_ref(), PACKET_BYTES);
3389    }
3390
3391    #[test]
3392    fn test_fragmented_packet_with_destination_options_reassembly() {
3393        const ID: u32 = 12345;
3394        let tcp_payload_part0 = [1u8, 2, 3, 4, 5, 6, 7, 8];
3395        // The first 8 bytes resemble a Destination Option header to test extension header
3396        // parsing stopping at the Fragment header.
3397        let tcp_payload_part1 =
3398            [Ipv6ExtHdrType::DestinationOptions.into(), 0, 0, 0, 0, 0, 0, 0, 99, 100];
3399
3400        // Fragment #0 (offset 0, M=true):
3401        // Fixed Header -> Fragment Header (Next Header = DestinationOptions) ->
3402        // Destination Options (8 bytes) -> TCP payload (8 bytes).
3403        let builder_0 = Ipv6PacketBuilder::new(
3404            DEFAULT_SRC_IP,
3405            DEFAULT_DST_IP,
3406            64,
3407            Ipv6Proto::Other(Ipv6ExtHdrType::DestinationOptions.into()),
3408        );
3409        let builder_0 = Ipv6PacketBuilderWithFragmentHeader::new(
3410            builder_0,
3411            FragmentOffset::ZERO,
3412            /* more_fragments */ true,
3413            ID,
3414        );
3415        // Destination Options (8 octets): Next Header = TCP, Hdr Ext Len = 0, Pad with 6 zeroes
3416        // (Pad1).
3417        let body_0: Vec<u8> = [IpProto::Tcp.into(), 0, 0, 0, 0, 0, 0, 0]
3418            .into_iter()
3419            .chain(tcp_payload_part0)
3420            .collect();
3421
3422        let mut buf_0 = (&body_0[..])
3423            .into_serializer()
3424            .wrap_in(builder_0)
3425            .serialize_vec_outer(&mut NoOpSerializationContext)
3426            .unwrap();
3427        let packet_0 = buf_0.parse::<Ipv6Packet<_>>().unwrap();
3428
3429        // Only the Fragment header should be in extension_hdrs.
3430        assert_matches!(
3431            &packet_0.iter_extension_hdrs().collect::<Vec<_>>()[..],
3432            [Ipv6ExtensionHeader::Fragment { .. }]
3433        );
3434        // Proto should be DestinationOptions (Next Header from Fragment header).
3435        assert_eq!(packet_0.proto(), Ipv6Proto::Other(Ipv6ExtHdrType::DestinationOptions.into()));
3436
3437        // Body must contain Destination Options AND the TCP data.
3438        assert_eq!(packet_0.body(), &body_0[..]);
3439
3440        // Header bytes for fragment should strip the Fragment header and patch Next Header.
3441        let header = packet_0.copy_header_bytes_for_fragment();
3442        assert_eq!(header.len(), IPV6_FIXED_HDR_LEN);
3443        assert_eq!(
3444            header[usize::from(NEXT_HEADER_OFFSET)],
3445            Ipv6ExtHdrType::DestinationOptions.into()
3446        );
3447
3448        // Fragment #1 (offset 2 blocks = 16 bytes, M=false):
3449        // Non-initial fragment whose payload in the middle of the TCP stream happens to
3450        // start with bytes that match the Destination Options header format (Next Header = 60).
3451        let builder_1 =
3452            Ipv6PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, 64, IpProto::Tcp.into());
3453        let builder_1 = Ipv6PacketBuilderWithFragmentHeader::new(
3454            builder_1,
3455            FragmentOffset::new(2).unwrap(),
3456            /* more_fragments */ false,
3457            ID,
3458        );
3459        let body_1 = tcp_payload_part1.to_vec();
3460
3461        let mut buf_1 = (&body_1[..])
3462            .into_serializer()
3463            .wrap_in(builder_1)
3464            .serialize_vec_outer(&mut NoOpSerializationContext)
3465            .unwrap();
3466        let packet_1 = buf_1.parse::<Ipv6Packet<_>>().unwrap();
3467
3468        // Must only have the Fragment header.
3469        assert_matches!(
3470            &packet_1.iter_extension_hdrs().collect::<Vec<_>>()[..],
3471            [Ipv6ExtensionHeader::Fragment { .. }]
3472        );
3473        // All payload bytes must be in packet_1.body() intact (not stripped as fake ext hdrs).
3474        assert_eq!(packet_1.body(), &body_1[..]);
3475
3476        // Reassemble the packet.
3477        let mut reassembled_buf =
3478            vec![0u8; header.len() + packet_0.body().len() + packet_1.body().len()];
3479        let mut reassembled_slice = &mut reassembled_buf[..];
3480        reassemble_fragmented_packet(
3481            &mut reassembled_slice,
3482            &header,
3483            [packet_0.body(), packet_1.body()].into_iter(),
3484        )
3485        .unwrap();
3486
3487        let mut reassembled_ref = &reassembled_buf[..];
3488        let reassembled_packet = reassembled_ref.parse::<Ipv6Packet<_>>().unwrap();
3489
3490        assert_matches!(
3491            &reassembled_packet.iter_extension_hdrs().collect::<Vec<_>>()[..],
3492            [Ipv6ExtensionHeader::DestinationOptions { .. }]
3493        );
3494        assert_eq!(reassembled_packet.proto(), IpProto::Tcp.into());
3495        let expected_reassembled_body: Vec<u8> =
3496            tcp_payload_part0.into_iter().chain(tcp_payload_part1).collect();
3497        assert_eq!(reassembled_packet.body(), &expected_reassembled_body[..]);
3498    }
3499}