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