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
1134/// A next header that may be either a next layer header or an IPv6 extension
1135/// header.
1136pub enum NextHeader {
1137    /// A next layer header follows.
1138    NextLayer(Ipv6Proto),
1139    /// An extension header follows.
1140    Extension(Ipv6ExtHdrType),
1141}
1142
1143impl From<NextHeader> for u8 {
1144    fn from(next_hdr: NextHeader) -> Self {
1145        match next_hdr {
1146            NextHeader::NextLayer(n) => n.into(),
1147            NextHeader::Extension(e) => e.into(),
1148        }
1149    }
1150}
1151
1152mod sealed {
1153    use super::*;
1154    /// A marker trait for IPv6 headers that can be serialized before header
1155    /// `T`.
1156    ///
1157    /// This trait is used to enforce IPv6 extension header ordering according
1158    /// to [RFC 8200 Section 4.1].
1159    ///
1160    /// [RFC 8200 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc8200#section-4.1
1161    pub trait Ipv6HeaderBefore<T> {}
1162
1163    impl<'a, O, T> Ipv6HeaderBefore<T> for &'a O where O: Ipv6HeaderBefore<T> {}
1164
1165    /// A trait abstracting all types of IPv6 header builders.
1166    pub trait Ipv6HeaderBuilder {
1167        /// Returns an immutable reference to the fixed header builder.
1168        fn fixed_header(&self) -> &Ipv6PacketBuilder;
1169
1170        /// Returns the total header length of the extension headers, including
1171        /// previous extension headers, but excluding the fixed header size.
1172        fn extension_headers_len(&self) -> usize;
1173
1174        /// Serializes the header into `buffer`.
1175        ///
1176        /// `next_header` is the header immediately after the current one.
1177        /// `payload_len` is the total size of the frame after this header.
1178        fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1179            &self,
1180            buffer: &mut BV,
1181            next_header: NextHeader,
1182            payload_len: usize,
1183        );
1184    }
1185}
1186use sealed::{Ipv6HeaderBefore, Ipv6HeaderBuilder};
1187
1188impl<'a, O> Ipv6HeaderBuilder for &'a O
1189where
1190    O: Ipv6HeaderBuilder,
1191{
1192    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1193        O::fixed_header(self)
1194    }
1195
1196    fn extension_headers_len(&self) -> usize {
1197        O::extension_headers_len(self)
1198    }
1199
1200    fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1201        &self,
1202        buffer: &mut BV,
1203        next_header: NextHeader,
1204        payload_len: usize,
1205    ) {
1206        O::serialize_header(self, buffer, next_header, payload_len)
1207    }
1208}
1209
1210/// A helper macro to implement `PacketBuilder` methods for implementers of
1211/// `Ipv6HeaderBuilder`.
1212///
1213/// This can't be a blanket impl because `PacketBuilder` is a foreign trait.
1214macro_rules! impl_packet_builder_base {
1215    {} => {
1216        fn constraints(&self) -> PacketConstraints {
1217            let ext_headers = self.extension_headers_len();
1218            let header_len = IPV6_FIXED_HDR_LEN + ext_headers;
1219            let footer_len = 0;
1220            let min_body_len = 0;
1221            // Extension headers take from the IPv6 available payload size.
1222            // See RFC 8200 Section 3 for details.
1223            let max_body_len = IPV6_MAX_PAYLOAD_LENGTH - ext_headers;
1224            PacketConstraints::new(header_len, footer_len, min_body_len, max_body_len)
1225        }
1226    }
1227}
1228
1229macro_rules! impl_packet_builder {
1230    {} => {
1231        fn context_state(&self) -> C::ContextState {
1232            C::envelope_to_state(IpEnvelope::new(self.extension_headers_len() > 0))
1233        }
1234
1235        fn serialize(
1236            &self,
1237            _context: &mut C,
1238            target: &mut SerializeTarget<'_>,
1239            body: FragmentedBytesMut<'_, '_>,
1240        ) {
1241            let mut bv = &mut target.header;
1242            self.serialize_header(
1243                &mut bv,
1244                NextHeader::NextLayer(
1245                    <Ipv6PacketBuilder as IpPacketBuilder<C, Ipv6>>::proto(self.fixed_header())
1246                ),
1247                body.len(),
1248            );
1249        }
1250    }
1251}
1252
1253macro_rules! impl_partial_packet_builder {
1254    {} => {
1255        fn partial_serialize(
1256            &self,
1257            _context: &mut C,
1258            body_len: usize,
1259            mut buffer: &mut [u8],
1260        ) {
1261            self.serialize_header(
1262                &mut &mut buffer,
1263                NextHeader::NextLayer(
1264                    <Ipv6PacketBuilder as IpPacketBuilder<C, Ipv6>>::proto(self.fixed_header())
1265                ),
1266                body_len,
1267            );
1268        }
1269    }
1270}
1271/// A builder for IPv6 packets.
1272#[derive(Debug, Clone, Eq, PartialEq)]
1273pub struct Ipv6PacketBuilder {
1274    dscp_and_ecn: DscpAndEcn,
1275    flowlabel: u32,
1276    hop_limit: u8,
1277    // The protocol number of the upper layer protocol, not the Next Header
1278    // value of the first extension header (if one exists).
1279    proto: Ipv6Proto,
1280    src_ip: Ipv6Addr,
1281    dst_ip: Ipv6Addr,
1282}
1283
1284impl Ipv6PacketBuilder {
1285    /// Constructs a new `Ipv6PacketBuilder`.
1286    ///
1287    /// The `proto` field encodes the protocol number identifying the upper
1288    /// layer payload, not the Next Header value of the first extension header
1289    /// (if one exists).
1290    pub fn new<S: Into<Ipv6Addr>, D: Into<Ipv6Addr>>(
1291        src_ip: S,
1292        dst_ip: D,
1293        hop_limit: u8,
1294        proto: Ipv6Proto,
1295    ) -> Ipv6PacketBuilder {
1296        Ipv6PacketBuilder {
1297            dscp_and_ecn: DscpAndEcn::default(),
1298            flowlabel: 0,
1299            hop_limit,
1300            proto,
1301            src_ip: src_ip.into(),
1302            dst_ip: dst_ip.into(),
1303        }
1304    }
1305
1306    /// Set the Differentiated Services Code Point (DSCP) and the Explicit
1307    /// Congestion Notification (ECN).
1308    pub fn dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
1309        self.dscp_and_ecn = dscp_and_ecn;
1310    }
1311
1312    /// Set the flowlabel.
1313    ///
1314    /// # Panics
1315    ///
1316    /// `flowlabel` panics if `flowlabel` is greater than 2^20 - 1.
1317    pub fn flowlabel(&mut self, flowlabel: u32) {
1318        assert!(flowlabel <= 1 << 20, "invalid flowlabel: {:x}", flowlabel);
1319        self.flowlabel = flowlabel;
1320    }
1321}
1322
1323impl Ipv6HeaderBuilder for Ipv6PacketBuilder {
1324    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1325        self
1326    }
1327
1328    fn extension_headers_len(&self) -> usize {
1329        0
1330    }
1331
1332    fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1333        &self,
1334        buffer: &mut BV,
1335        next_header: NextHeader,
1336        payload_len: usize,
1337    ) {
1338        buffer
1339            .write_obj_front(&FixedHeader::new(
1340                self.dscp_and_ecn,
1341                self.flowlabel,
1342                {
1343                    // The caller promises to supply a body whose length
1344                    // does not exceed max_body_len. Doing this as a
1345                    // debug_assert (rather than an assert) is fine because,
1346                    // with debug assertions disabled, we'll just write an
1347                    // incorrect header value, which is acceptable if the
1348                    // caller has violated their contract.
1349                    debug_assert!(payload_len <= u16::MAX as usize);
1350                    payload_len as u16
1351                },
1352                next_header.into(),
1353                self.hop_limit,
1354                self.src_ip,
1355                self.dst_ip,
1356            ))
1357            .expect("not enough bytes for IPv6 fixed header");
1358    }
1359}
1360
1361impl NestablePacketBuilder for Ipv6PacketBuilder {
1362    impl_packet_builder_base! {}
1363}
1364
1365impl<C: IpSerializationContext<Ipv6>> PacketBuilder<C> for Ipv6PacketBuilder {
1366    impl_packet_builder! {}
1367}
1368
1369impl<C: IpSerializationContext<Ipv6>> PartialPacketBuilder<C> for Ipv6PacketBuilder {
1370    impl_partial_packet_builder! {}
1371}
1372
1373/// A builder for Ipv6 packets with HBH Options.
1374#[derive(Debug, Clone)]
1375pub struct Ipv6PacketBuilderWithHbhOptions<'a, I> {
1376    prefix_builder: Ipv6PacketBuilder,
1377    hbh_options: AlignedRecordSequenceBuilder<HopByHopOption<'a>, I>,
1378}
1379
1380impl<'a, I> Ipv6PacketBuilderWithHbhOptions<'a, I>
1381where
1382    I: Iterator + Clone,
1383    I::Item: Borrow<HopByHopOption<'a>>,
1384{
1385    /// Creates a IPv6 packet builder with a Hop By Hop Options extension header.
1386    pub fn new<T: IntoIterator<Item = I::Item, IntoIter = I>>(
1387        prefix_builder: Ipv6PacketBuilder,
1388        options: T,
1389    ) -> Option<Ipv6PacketBuilderWithHbhOptions<'a, I>> {
1390        let iter = options.into_iter();
1391        // https://tools.ietf.org/html/rfc2711#section-2.1 specifies that
1392        // an RouterAlert option can only appear once.
1393        if iter
1394            .clone()
1395            .filter(|r| matches!(r.borrow().data, HopByHopOptionData::RouterAlert { .. }))
1396            .count()
1397            > 1
1398        {
1399            return None;
1400        }
1401        let hbh_options = AlignedRecordSequenceBuilder::new(2, iter);
1402        // And we don't want our options to become too long.
1403        if next_multiple_of_eight(2 + hbh_options.serialized_len()) > IPV6_HBH_OPTIONS_MAX_LEN {
1404            return None;
1405        }
1406        Some(Ipv6PacketBuilderWithHbhOptions { prefix_builder, hbh_options })
1407    }
1408
1409    fn aligned_hbh_len(&self) -> usize {
1410        let opt_len = self.hbh_options.serialized_len();
1411        let hbh_len = opt_len + 2;
1412        next_multiple_of_eight(hbh_len)
1413    }
1414}
1415
1416fn next_multiple_of_eight(x: usize) -> usize {
1417    (x + 7) & (!7)
1418}
1419
1420impl<C: IpSerializationContext<Ipv6>> IpPacketBuilder<C, Ipv6> for Ipv6PacketBuilder {
1421    fn new(src_ip: Ipv6Addr, dst_ip: Ipv6Addr, ttl: u8, proto: Ipv6Proto) -> Self {
1422        Ipv6PacketBuilder::new(src_ip, dst_ip, ttl, proto)
1423    }
1424
1425    fn src_ip(&self) -> Ipv6Addr {
1426        self.src_ip
1427    }
1428
1429    fn set_src_ip(&mut self, addr: Ipv6Addr) {
1430        self.src_ip = addr;
1431    }
1432
1433    fn dst_ip(&self) -> Ipv6Addr {
1434        self.dst_ip
1435    }
1436
1437    fn set_dst_ip(&mut self, addr: Ipv6Addr) {
1438        self.dst_ip = addr;
1439    }
1440
1441    fn proto(&self) -> Ipv6Proto {
1442        self.proto
1443    }
1444
1445    fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
1446        self.dscp_and_ecn = dscp_and_ecn;
1447    }
1448}
1449
1450impl<'a, I> Ipv6HeaderBuilder for Ipv6PacketBuilderWithHbhOptions<'a, I>
1451where
1452    I: Iterator + Clone,
1453    I::Item: Borrow<HopByHopOption<'a>>,
1454{
1455    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1456        &self.prefix_builder
1457    }
1458
1459    fn extension_headers_len(&self) -> usize {
1460        self.prefix_builder.extension_headers_len() + self.aligned_hbh_len()
1461    }
1462
1463    fn serialize_header<B: SplitByteSliceMut, BV: BufferViewMut<B>>(
1464        &self,
1465        buffer: &mut BV,
1466        next_header: NextHeader,
1467        payload_len: usize,
1468    ) {
1469        let aligned_hbh_len = self.aligned_hbh_len();
1470        // The next header in the fixed header now should be 0 (Hop-by-Hop Extension Header)
1471        self.prefix_builder.serialize_header(
1472            buffer,
1473            NextHeader::Extension(Ipv6ExtHdrType::HopByHopOptions),
1474            payload_len + aligned_hbh_len,
1475        );
1476        // take the first two bytes to write in proto and length information.
1477        let mut hbh_header = buffer.take_front(aligned_hbh_len).unwrap();
1478        let hbh_header: &mut [u8] = hbh_header.as_mut();
1479        hbh_header[0] = next_header.into();
1480        hbh_header[1] = u8::try_from((aligned_hbh_len - 8) / 8).expect("extension header too big");
1481        self.hbh_options.serialize_into(&mut hbh_header[2..]);
1482    }
1483}
1484
1485impl<'a, I> NestablePacketBuilder for Ipv6PacketBuilderWithHbhOptions<'a, I>
1486where
1487    I: Iterator + Clone,
1488    I::Item: Borrow<HopByHopOption<'a>>,
1489{
1490    impl_packet_builder_base! {}
1491}
1492
1493impl<'a, I, C: IpSerializationContext<Ipv6>> PacketBuilder<C>
1494    for Ipv6PacketBuilderWithHbhOptions<'a, I>
1495where
1496    I: Iterator + Clone,
1497    I::Item: Borrow<HopByHopOption<'a>>,
1498{
1499    impl_packet_builder! {}
1500}
1501
1502impl<'a, I, C: IpSerializationContext<Ipv6>> PartialPacketBuilder<C>
1503    for Ipv6PacketBuilderWithHbhOptions<'a, I>
1504where
1505    I: Iterator + Clone,
1506    I::Item: Borrow<HopByHopOption<'a>>,
1507{
1508    impl_partial_packet_builder! {}
1509}
1510
1511impl<'a, C: IpSerializationContext<Ipv6>, I> IpPacketBuilder<C, Ipv6>
1512    for Ipv6PacketBuilderWithHbhOptions<'a, I>
1513where
1514    I: Iterator<Item: Borrow<HopByHopOption<'a>>> + Debug + Default + Clone,
1515{
1516    fn new(src_ip: Ipv6Addr, dst_ip: Ipv6Addr, ttl: u8, proto: Ipv6Proto) -> Self {
1517        Ipv6PacketBuilderWithHbhOptions::new(
1518            Ipv6PacketBuilder::new(src_ip, dst_ip, ttl, proto),
1519            I::default(),
1520        )
1521        .expect("packet builder with no options should be valid")
1522    }
1523
1524    fn src_ip(&self) -> Ipv6Addr {
1525        self.prefix_builder.src_ip
1526    }
1527
1528    fn set_src_ip(&mut self, addr: Ipv6Addr) {
1529        self.prefix_builder.src_ip = addr;
1530    }
1531
1532    fn dst_ip(&self) -> Ipv6Addr {
1533        self.prefix_builder.dst_ip
1534    }
1535
1536    fn set_dst_ip(&mut self, addr: Ipv6Addr) {
1537        self.prefix_builder.dst_ip = addr;
1538    }
1539
1540    fn proto(&self) -> Ipv6Proto {
1541        self.prefix_builder.proto
1542    }
1543
1544    fn set_dscp_and_ecn(&mut self, dscp_and_ecn: DscpAndEcn) {
1545        <Ipv6PacketBuilder as IpPacketBuilder<C, Ipv6>>::set_dscp_and_ecn(
1546            &mut self.prefix_builder,
1547            dscp_and_ecn,
1548        )
1549    }
1550}
1551
1552/// Metadata about extension headers for the `Ipv6PerFragmentHeaderBuilder`.
1553#[derive(Debug, Clone, Eq, PartialEq)]
1554struct Ipv6PerFragmentMeta<B> {
1555    ext_hdrs: B,
1556    first_ext_hdr: Ipv6ExtHdrType,
1557    last_next_hdr_offset: usize,
1558}
1559
1560/// A builder for IPv6 packets containing the per-fragment extension headers.
1561///
1562/// Generally, this should be wrapped with an
1563/// [`Ipv6PacketBuilderWithFragmentHeader`].
1564#[derive(Debug, Clone, Eq, PartialEq)]
1565pub struct Ipv6PerFragmentHeaderBuilder<B> {
1566    prefix_builder: Ipv6PacketBuilder,
1567    meta: Option<Ipv6PerFragmentMeta<B>>,
1568}
1569
1570impl<B: AsRef<[u8]>> Ipv6PerFragmentHeaderBuilder<B> {
1571    /// Returns the length of the header (fixed header and extension headers).
1572    pub fn header_len(&self) -> usize {
1573        self.extension_headers_len() + IPV6_FIXED_HDR_LEN
1574    }
1575
1576    /// Converts `self` into an identical builder with references to the
1577    /// underlying extension header bytes.
1578    pub fn as_ref(&self) -> Ipv6PerFragmentHeaderBuilder<&[u8]> {
1579        let Self { prefix_builder, meta } = self;
1580        let meta = meta.as_ref().map(
1581            |Ipv6PerFragmentMeta { ext_hdrs, first_ext_hdr, last_next_hdr_offset }| {
1582                Ipv6PerFragmentMeta {
1583                    ext_hdrs: ext_hdrs.as_ref(),
1584                    first_ext_hdr: *first_ext_hdr,
1585                    last_next_hdr_offset: *last_next_hdr_offset,
1586                }
1587            },
1588        );
1589        Ipv6PerFragmentHeaderBuilder { prefix_builder: prefix_builder.clone(), meta }
1590    }
1591}
1592
1593impl<B: AsRef<[u8]>> Ipv6HeaderBuilder for Ipv6PerFragmentHeaderBuilder<B> {
1594    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1595        &self.prefix_builder
1596    }
1597
1598    fn extension_headers_len(&self) -> usize {
1599        self.meta
1600            .as_ref()
1601            .map(|Ipv6PerFragmentMeta { ext_hdrs, .. }| ext_hdrs.as_ref().len())
1602            .unwrap_or(0)
1603    }
1604
1605    fn serialize_header<BB: SplitByteSliceMut, BV: BufferViewMut<BB>>(
1606        &self,
1607        buffer: &mut BV,
1608        next_header: NextHeader,
1609        payload_len: usize,
1610    ) {
1611        let Self { prefix_builder, meta } = self;
1612        match meta {
1613            None => prefix_builder.serialize_header(buffer, next_header, payload_len),
1614            Some(Ipv6PerFragmentMeta { ext_hdrs, first_ext_hdr, last_next_hdr_offset }) => {
1615                let ext_hdrs = ext_hdrs.as_ref();
1616                let ext_hdrs_len = ext_hdrs.len();
1617                prefix_builder.serialize_header(
1618                    buffer,
1619                    NextHeader::Extension(*first_ext_hdr),
1620                    payload_len + ext_hdrs_len,
1621                );
1622                let mut ext_hdr_buf =
1623                    buffer.take_front(ext_hdrs_len).expect("buffer should be long enough");
1624                let ext_hdr_buf: &mut [u8] = ext_hdr_buf.as_mut();
1625                ext_hdr_buf.copy_from_slice(ext_hdrs);
1626                ext_hdr_buf[*last_next_hdr_offset] = u8::from(next_header);
1627            }
1628        }
1629    }
1630}
1631
1632impl<B: AsRef<[u8]>> NestablePacketBuilder for Ipv6PerFragmentHeaderBuilder<B> {
1633    impl_packet_builder_base! {}
1634}
1635
1636impl<B: AsRef<[u8]>, C: IpSerializationContext<Ipv6>> PacketBuilder<C>
1637    for Ipv6PerFragmentHeaderBuilder<B>
1638{
1639    impl_packet_builder! {}
1640}
1641
1642impl<B: AsRef<[u8]>, C: IpSerializationContext<Ipv6>> PartialPacketBuilder<C>
1643    for Ipv6PerFragmentHeaderBuilder<B>
1644{
1645    impl_partial_packet_builder! {}
1646}
1647
1648/// An IPv6 packet builder that includes the fragmentation header.
1649///
1650/// `Ipv6PacketBuilderWithFragmentHeader` wraps another compatible packet
1651/// builder to attach the fragment header on it.
1652///
1653/// See [RFC 8200 Section 2.5] for the fragment header format.
1654///
1655/// [RFC 8200 Section 2.5]: https://datatracker.ietf.org/doc/html/rfc8200#section-4.5
1656#[derive(Debug, Eq, PartialEq)]
1657pub struct Ipv6PacketBuilderWithFragmentHeader<B> {
1658    header_builder: B,
1659    fragment_offset: FragmentOffset,
1660    more_fragments: bool,
1661    identification: u32,
1662}
1663
1664impl<B: Ipv6HeaderBefore<Self>> Ipv6PacketBuilderWithFragmentHeader<B> {
1665    /// Creates a new `Ipv6PacketBuilderWithFragmentHeader`.
1666    pub fn new(
1667        header_builder: B,
1668        fragment_offset: FragmentOffset,
1669        more_fragments: bool,
1670        identification: u32,
1671    ) -> Self {
1672        Self { header_builder, fragment_offset, more_fragments, identification }
1673    }
1674}
1675
1676impl<B> Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<B>> for Ipv6PacketBuilder {}
1677impl<B, I> Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<B>>
1678    for Ipv6PacketBuilderWithHbhOptions<'_, I>
1679{
1680}
1681impl<HB, B> Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<HB>>
1682    for Ipv6PerFragmentHeaderBuilder<B>
1683{
1684}
1685
1686/// A marker trait for all header builder types that can be used to construct
1687/// and serialize IPv6 headers using [`Ipv6PacketBuilderWithFragmentHeader`].
1688pub trait Ipv6PacketBuilderBeforeFragment:
1689    Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<Self>> + Ipv6HeaderBuilder + Sized
1690{
1691}
1692impl<B> Ipv6PacketBuilderBeforeFragment for B where
1693    B: Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<Self>> + Ipv6HeaderBuilder + Sized
1694{
1695}
1696
1697impl<B: Ipv6HeaderBuilder> Ipv6HeaderBuilder for Ipv6PacketBuilderWithFragmentHeader<B> {
1698    fn fixed_header(&self) -> &Ipv6PacketBuilder {
1699        self.header_builder.fixed_header()
1700    }
1701
1702    fn extension_headers_len(&self) -> usize {
1703        self.header_builder.extension_headers_len() + IPV6_FRAGMENT_EXT_HDR_LEN
1704    }
1705
1706    fn serialize_header<BB: SplitByteSliceMut, BV: BufferViewMut<BB>>(
1707        &self,
1708        buffer: &mut BV,
1709        next_header: NextHeader,
1710        payload_len: usize,
1711    ) {
1712        let Self { header_builder, fragment_offset, more_fragments, identification } = self;
1713        let payload_len = payload_len + IPV6_FRAGMENT_EXT_HDR_LEN;
1714        header_builder.serialize_header(
1715            buffer,
1716            NextHeader::Extension(Ipv6ExtHdrType::Fragment),
1717            payload_len,
1718        );
1719        buffer.write_obj_front(&u8::from(next_header)).unwrap();
1720        // Reserved.
1721        let _: BB = buffer.take_front_zero(1).unwrap();
1722        let more_fragments = u16::from(*more_fragments);
1723        buffer
1724            .write_obj_front(&U16::new(fragment_offset.into_raw() << 3 | more_fragments))
1725            .unwrap();
1726        buffer.write_obj_front(&U32::new(*identification)).unwrap();
1727    }
1728}
1729
1730impl<B: Ipv6HeaderBuilder> NestablePacketBuilder for Ipv6PacketBuilderWithFragmentHeader<B> {
1731    impl_packet_builder_base! {}
1732}
1733
1734impl<B: Ipv6HeaderBuilder, C: IpSerializationContext<Ipv6>> PacketBuilder<C>
1735    for Ipv6PacketBuilderWithFragmentHeader<B>
1736{
1737    impl_packet_builder! {}
1738}
1739
1740impl<B: Ipv6HeaderBuilder, C: IpSerializationContext<Ipv6>> PartialPacketBuilder<C>
1741    for Ipv6PacketBuilderWithFragmentHeader<B>
1742{
1743    impl_partial_packet_builder! {}
1744}
1745
1746/// Reassembles a fragmented packet into a parsed IP packet.
1747///
1748/// # Panics
1749///
1750/// Panics if the provided header is too small to hold a valid header.
1751pub(crate) fn reassemble_fragmented_packet<
1752    'a,
1753    B: SplitByteSliceMut,
1754    BV: BufferViewMut<B>,
1755    I: Iterator<Item = &'a [u8]>,
1756>(
1757    mut buffer: BV,
1758    header: &[u8],
1759    body_fragments: I,
1760) -> IpParseResult<Ipv6, ()> {
1761    assert!(header.len() >= IPV6_FIXED_HDR_LEN);
1762
1763    let bytes = buffer.as_mut();
1764
1765    // First, copy over the header data.
1766    bytes[0..header.len()].copy_from_slice(header);
1767    let mut byte_count = header.len();
1768
1769    // Next, copy over the body fragments.
1770    for p in body_fragments {
1771        bytes[byte_count..byte_count + p.len()].copy_from_slice(p);
1772        byte_count += p.len();
1773    }
1774
1775    //
1776    // Fix up the IPv6 header
1777    //
1778
1779    // For IPv6, the payload length is the sum of the length of the
1780    // extension headers and the packet body. The header as it is stored
1781    // includes the IPv6 fixed header and all extension headers, so
1782    // `bytes_count` is the sum of the size of the fixed header,
1783    // extension headers and packet body. To calculate the payload
1784    // length we subtract the size of the fixed header from the total
1785    // byte count of a reassembled packet.
1786    let payload_length = byte_count - IPV6_FIXED_HDR_LEN;
1787
1788    // Make sure that the payload length is not more than the maximum
1789    // possible IPv6 packet length.
1790    if payload_length > usize::from(u16::MAX) {
1791        return debug_err!(
1792            Err(ParseError::Format.into()),
1793            "fragmented packet payload length of {} bytes is too large",
1794            payload_length
1795        );
1796    }
1797
1798    // We know the call to `unwrap` will not fail because we verified the length
1799    // of `header` and copied it's bytes into `bytes`.
1800    let mut header = Ref::<_, FixedHeader>::from_prefix(bytes).unwrap().0;
1801
1802    // Update the payload length field.
1803    header.payload_len.set(u16::try_from(payload_length).unwrap());
1804
1805    Ok(())
1806}
1807
1808#[cfg(test)]
1809mod tests {
1810    use assert_matches::assert_matches;
1811    use packet::{Buf, FragmentedBuffer, ParseBuffer, PartialSerializeResult};
1812    use test_case::test_case;
1813
1814    use crate::ethernet::{EthernetFrame, EthernetFrameLengthCheck};
1815    use crate::testutil::*;
1816
1817    use super::ext_hdrs::*;
1818    use super::*;
1819
1820    const DEFAULT_SRC_IP: Ipv6Addr =
1821        Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
1822    const DEFAULT_DST_IP: Ipv6Addr =
1823        Ipv6Addr::from_bytes([17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]);
1824
1825    const DEFAULT_V4_SRC_IP: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
1826    const DEFAULT_V4_DST_IP: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
1827
1828    #[test]
1829    fn test_parse_serialize_full_tcp() {
1830        use crate::testdata::syn_v6::*;
1831
1832        let mut buf = ETHERNET_FRAME.bytes;
1833        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
1834        verify_ethernet_frame(&frame, ETHERNET_FRAME);
1835
1836        let mut body = frame.body();
1837        let packet = body.parse::<Ipv6Packet<_>>().unwrap();
1838        verify_ipv6_packet(&packet, IPV6_PACKET);
1839
1840        // Verify serialization via builders.
1841        let buffer = packet
1842            .body()
1843            .into_serializer()
1844            .wrap_in(packet.builder())
1845            .wrap_in(frame.builder())
1846            .serialize_vec_outer(&mut NoOpSerializationContext)
1847            .unwrap();
1848        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
1849
1850        // Verify serialization via `to_vec`.
1851        assert_eq!(&packet.to_vec()[..], IPV6_PACKET.bytes);
1852    }
1853
1854    #[test]
1855    fn test_parse_serialize_full_udp() {
1856        use crate::testdata::dns_request_v6::*;
1857
1858        let mut buf = ETHERNET_FRAME.bytes;
1859        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
1860        verify_ethernet_frame(&frame, ETHERNET_FRAME);
1861
1862        let mut body = frame.body();
1863        let packet = body.parse::<Ipv6Packet<_>>().unwrap();
1864        verify_ipv6_packet(&packet, IPV6_PACKET);
1865
1866        // Verify serialization via builders.
1867        let buffer = packet
1868            .body()
1869            .into_serializer()
1870            .wrap_in(packet.builder())
1871            .wrap_in(frame.builder())
1872            .serialize_vec_outer(&mut NoOpSerializationContext)
1873            .unwrap();
1874        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
1875
1876        // Verify serialization via `to_vec`.
1877        assert_eq!(&packet.to_vec()[..], IPV6_PACKET.bytes);
1878    }
1879
1880    #[test]
1881    fn test_parse_serialize_with_extension_headers() {
1882        // NB; Use MLD as test data arbitrarily, because it includes IPv6
1883        // extension headers.
1884        use crate::testdata::mld_router_report::*;
1885
1886        let mut buf = REPORT;
1887        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1888        assert_eq!(packet.iter_extension_hdrs().count(), 1);
1889
1890        // NB: Don't verify serialization via builders, as they omit IPv6
1891        // extension headers.
1892
1893        // Verify serialization via `to_vec`.
1894        assert_eq!(&packet.to_vec()[..], REPORT);
1895    }
1896
1897    fn fixed_hdr_to_bytes(fixed_hdr: FixedHeader) -> [u8; IPV6_FIXED_HDR_LEN] {
1898        zerocopy::transmute!(fixed_hdr)
1899    }
1900
1901    // Return a new FixedHeader with reasonable defaults.
1902    fn new_fixed_hdr() -> FixedHeader {
1903        FixedHeader::new(
1904            DscpAndEcn::new(0, 2),
1905            0x77,
1906            0,
1907            IpProto::Tcp.into(),
1908            64,
1909            DEFAULT_SRC_IP,
1910            DEFAULT_DST_IP,
1911        )
1912    }
1913
1914    #[test]
1915    fn test_parse() {
1916        let mut buf = &fixed_hdr_to_bytes(new_fixed_hdr())[..];
1917        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1918        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
1919        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
1920        assert_eq!(packet.flowlabel(), 0x77);
1921        assert_eq!(packet.hop_limit(), 64);
1922        assert_eq!(packet.fixed_hdr.next_hdr, IpProto::Tcp.into());
1923        assert_eq!(packet.proto(), IpProto::Tcp.into());
1924        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
1925        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
1926        assert_eq!(packet.body(), []);
1927    }
1928
1929    #[test]
1930    fn test_parse_with_ext_hdrs() {
1931        #[rustfmt::skip]
1932        let mut buf = [
1933            // FixedHeader (will be replaced later)
1934            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1935            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1936
1937            // HopByHop Options Extension Header
1938            Ipv6ExtHdrType::Routing.into(), // Next Header
1939            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1940            0,                       // Pad1
1941            1, 0,                    // Pad2
1942            1, 1, 0,                 // Pad3
1943
1944            // Routing Extension Header
1945            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
1946            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1947            0,                                  // Routing Type (Deprecated as per RFC 5095)
1948            0,                                  // Segments Left
1949            0, 0, 0, 0,                         // Reserved
1950            // Addresses for Routing Header w/ Type 0
1951            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
1952            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1953
1954            // Destination Options Extension Header
1955            IpProto::Tcp.into(),    // Next Header
1956            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
1957            0,                      // Pad1
1958            1, 0,                   // Pad2
1959            1, 1, 0,                // Pad3
1960            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
1961
1962            // Body
1963            1, 2, 3, 4, 5,
1964        ];
1965        let mut fixed_hdr = new_fixed_hdr();
1966        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
1967        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
1968        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
1969        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
1970        let mut buf = &buf[..];
1971        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
1972        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
1973        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
1974        assert_eq!(packet.flowlabel(), 0x77);
1975        assert_eq!(packet.hop_limit(), 64);
1976        assert_eq!(packet.fixed_hdr.next_hdr, Ipv6ExtHdrType::HopByHopOptions.into());
1977        assert_eq!(packet.proto(), IpProto::Tcp.into());
1978        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
1979        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
1980        assert_eq!(packet.body(), [1, 2, 3, 4, 5]);
1981        let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = packet.iter_extension_hdrs().collect();
1982        assert_eq!(ext_hdrs.len(), 3);
1983        // Check first extension header (hop-by-hop options)
1984        if let Ipv6ExtensionHeader::HopByHopOptions { options } = &ext_hdrs[0] {
1985            // Everything should have been a NOP/ignore
1986            assert_eq!(options.iter().count(), 0);
1987        } else {
1988            panic!("Should have matched HopByHopOptions!");
1989        }
1990
1991        // Check second extension header (routing)
1992        if let Ipv6ExtensionHeader::Routing { routing_data } = &ext_hdrs[1] {
1993            assert_eq!(routing_data.routing_type(), Err(RoutingTypeParseError::UnsupportedType(0)));
1994            assert_eq!(routing_data.segments_left(), 0);
1995        } else {
1996            panic!("Should have matched RoutingExtensionHeader: {:?}", &ext_hdrs[1]);
1997        }
1998
1999        // Check the third extension header (destination options)
2000        if let Ipv6ExtensionHeader::DestinationOptions { options } = &ext_hdrs[2] {
2001            // Everything should have been a NOP/ignore
2002            assert_eq!(options.iter().count(), 0);
2003        } else {
2004            panic!("Should have matched DestinationOptions!");
2005        }
2006
2007        // Test with a NoNextHeader as the final Next Header
2008        #[rustfmt::skip]
2009        let mut buf = [
2010            // FixedHeader (will be replaced later)
2011            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2012            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2013
2014            // HopByHop Options Extension Header w/ NoNextHeader as the next header
2015            Ipv6Proto::NoNextHeader.into(), // Next Header
2016            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2017            0,                       // Pad1
2018            1, 0,                    // Pad2
2019            1, 1, 0,                 // Pad3
2020
2021            // Body
2022            1, 2, 3, 4, 5,
2023        ];
2024        let mut fixed_hdr = new_fixed_hdr();
2025        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2026        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2027        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2028        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2029        let mut buf = &buf[..];
2030        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2031        assert_eq!(packet.dscp_and_ecn().dscp(), 0);
2032        assert_eq!(packet.dscp_and_ecn().ecn(), 2);
2033        assert_eq!(packet.flowlabel(), 0x77);
2034        assert_eq!(packet.hop_limit(), 64);
2035        assert_eq!(packet.fixed_hdr.next_hdr, Ipv6ExtHdrType::HopByHopOptions.into());
2036        assert_eq!(packet.proto(), Ipv6Proto::NoNextHeader);
2037        assert_eq!(packet.src_ip(), DEFAULT_SRC_IP);
2038        assert_eq!(packet.dst_ip(), DEFAULT_DST_IP);
2039        assert_eq!(packet.body(), [1, 2, 3, 4, 5]);
2040        let ext_hdrs: Vec<Ipv6ExtensionHeader<'_>> = packet.iter_extension_hdrs().collect();
2041        assert_eq!(ext_hdrs.len(), 1);
2042        // Check first extension header (hop-by-hop options)
2043        if let Ipv6ExtensionHeader::HopByHopOptions { options } = &ext_hdrs[0] {
2044            // Everything should have been a NOP/ignore
2045            assert_eq!(options.iter().count(), 0);
2046        } else {
2047            panic!("Should have matched HopByHopOptions!");
2048        }
2049    }
2050
2051    #[test]
2052    fn test_parse_error() {
2053        // Set the version to 5. The version must be 6.
2054        let mut fixed_hdr = new_fixed_hdr();
2055        fixed_hdr.version_tc_flowlabel[0] = 0x50;
2056        assert_eq!(
2057            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
2058            ParseError::Format.into()
2059        );
2060
2061        // Set the payload len to 2, even though there's no payload.
2062        let mut fixed_hdr = new_fixed_hdr();
2063        fixed_hdr.payload_len = U16::new(2);
2064        assert_eq!(
2065            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
2066            ParseError::Format.into()
2067        );
2068
2069        // Use invalid next header.
2070        let mut fixed_hdr = new_fixed_hdr();
2071        fixed_hdr.next_hdr = 255;
2072        let packet = fixed_hdr_to_bytes(fixed_hdr);
2073
2074        // Raw parsing should succeed even with unrecognized Next Header.
2075        assert!((&packet[..]).parse::<Ipv6PacketRaw<_>>().is_ok());
2076
2077        // Full parse should fail with unrecognized next header error.
2078        assert_eq!(
2079            (&packet[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
2080            Ipv6ParseError::ParameterProblem {
2081                src_ip: DEFAULT_SRC_IP,
2082                dst_ip: DEFAULT_DST_IP,
2083                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2084                pointer: u32::from(NEXT_HEADER_OFFSET),
2085                must_send_icmp: false,
2086                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2087            }
2088        );
2089
2090        // Use ICMP(v4) as next header.
2091        let mut fixed_hdr = new_fixed_hdr();
2092        fixed_hdr.next_hdr = Ipv4Proto::Icmp.into();
2093        assert_eq!(
2094            (&fixed_hdr_to_bytes(fixed_hdr)[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
2095            Ipv6ParseError::ParameterProblem {
2096                src_ip: DEFAULT_SRC_IP,
2097                dst_ip: DEFAULT_DST_IP,
2098                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2099                pointer: u32::from(NEXT_HEADER_OFFSET),
2100                must_send_icmp: false,
2101                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2102            }
2103        );
2104
2105        // Test HopByHop extension header not being the very first extension header
2106        #[rustfmt::skip]
2107        let mut buf = [
2108            // FixedHeader (will be replaced later)
2109            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2110            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2111
2112            // Routing Extension Header
2113            Ipv6ExtHdrType::HopByHopOptions.into(),    // Next Header (Valid but HopByHop restricted to first extension header)
2114            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2115            0,                                  // Routing Type
2116            0,                                  // Segments Left
2117            0, 0, 0, 0,                         // Reserved
2118            // Addresses for Routing Header w/ Type 0
2119            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2120            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2121
2122            // HopByHop Options Extension Header
2123            IpProto::Tcp.into(),             // Next Header
2124            0,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2125            0,                                  // Pad1
2126            1, 0,                               // Pad2
2127            1, 1, 0,                            // Pad3
2128
2129            // Body
2130            1, 2, 3, 4, 5,
2131        ];
2132        let mut fixed_hdr = new_fixed_hdr();
2133        fixed_hdr.next_hdr = Ipv6ExtHdrType::Routing.into();
2134        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2135        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2136        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2137        let mut buf = &buf[..];
2138        assert_eq!(
2139            buf.parse::<Ipv6Packet<_>>().unwrap_err(),
2140            Ipv6ParseError::ParameterProblem {
2141                src_ip: DEFAULT_SRC_IP,
2142                dst_ip: DEFAULT_DST_IP,
2143                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2144                pointer: IPV6_FIXED_HDR_LEN as u32,
2145                must_send_icmp: false,
2146                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2147            }
2148        );
2149
2150        // Test Unrecognized Routing Type
2151        #[rustfmt::skip]
2152        let mut buf = [
2153            // FixedHeader (will be replaced later)
2154            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2155            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2156
2157            // Routing Extension Header
2158            IpProto::Tcp.into(),                // Next Header
2159            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2160            255,                                // Routing Type (Invalid)
2161            1,                                  // Segments Left
2162            0, 0, 0, 0,                         // Reserved
2163            // Addresses for Routing Header w/ Type 0
2164            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2165            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2166
2167            // Body
2168            1, 2, 3, 4, 5,
2169        ];
2170        let mut fixed_hdr = new_fixed_hdr();
2171        fixed_hdr.next_hdr = Ipv6ExtHdrType::Routing.into();
2172        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2173        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2174        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2175        let expected_error = Ipv6ParseError::ParameterProblem {
2176            src_ip: DEFAULT_SRC_IP,
2177            dst_ip: DEFAULT_DST_IP,
2178            code: Icmpv6ParameterProblemCode::ErroneousHeaderField,
2179            pointer: (IPV6_FIXED_HDR_LEN as u32) + 2,
2180            must_send_icmp: true,
2181            action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2182        };
2183        assert_eq!((&buf[..]).parse::<Ipv6Packet<_>>().unwrap_err(), expected_error);
2184
2185        // Test an unrecognized Routing Type with an unrecognized Next Header.
2186        // This shouldn't change the result: each header should be processed
2187        // before validating the Next Header field.
2188        buf[IPV6_FIXED_HDR_LEN] = 250; // Next Header (Invalid)
2189
2190        assert_eq!((&buf[..]).parse::<Ipv6Packet<_>>().unwrap_err(), expected_error);
2191    }
2192
2193    #[test]
2194    fn test_parse_all_next_header_values() {
2195        // Test that, when parsing a packet with the fixed header's Next Header
2196        // field set to any value, parsing does not panic. A previous version
2197        // of this code would panic on some Next Header values.
2198
2199        // This packet was found via fuzzing to trigger a panic.
2200        let mut buf = [
2201            0x81, 0x13, 0x27, 0xeb, 0x75, 0x92, 0x33, 0x89, 0x01, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc,
2202            0x03, 0x70, 0x00, 0x22, 0xf7, 0x30, 0x2c, 0x06, 0xfe, 0xc9, 0x00, 0x2d, 0x3b, 0xeb,
2203            0xad, 0x3e, 0x5c, 0x41, 0xc8, 0x70, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x11, 0x00,
2204            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x4f, 0x4f, 0x6f, 0x4f, 0x4f, 0x4f, 0x4f,
2205            0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x19, 0x19,
2206            0x19, 0x19, 0x19, 0x4f, 0x4f, 0x4f, 0x4f, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2207            0x00, 0x4f, 0x4f, 0x5a, 0x5a, 0x5a, 0xc9, 0x5a, 0x46, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
2208            0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0xe4, 0x5a, 0x5a, 0x5a, 0x5a,
2209        ];
2210
2211        // First, assert that the Next Header value found by the fuzzer (51)
2212        // produces the error we expect.
2213        assert_matches!(
2214            (&buf[..]).parse::<Ipv6Packet<_>>(),
2215            Err(Ipv6ParseError::ParameterProblem {
2216                src_ip: _,
2217                dst_ip: _,
2218                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2219                pointer: 6,
2220                must_send_icmp: false,
2221                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2222            })
2223        );
2224
2225        // Second, ensure that, regardless of the exact result produced, no Next
2226        // Header value causes parsing to panic.
2227        for b in 0u8..=255 {
2228            // Overwrite the Next Header field.
2229            buf[6] = b;
2230            let _: Result<_, _> = (&buf[..]).parse::<Ipv6Packet<_>>();
2231        }
2232    }
2233
2234    #[test]
2235    fn test_esp_packet() {
2236        // Encapsulating Security Payload (ESP) is not supported yet. Verify
2237        // that for ESP packets Ipv6Packet parsing fails, but Ipv6PacketRaw
2238        // parser succeeds.
2239
2240        const ESP_NEXT_HEADER: u8 = 50;
2241
2242        // 1. ESP as first extension header (Next Header in Fixed Header = ESP)
2243        let mut fixed_hdr = new_fixed_hdr();
2244        fixed_hdr.next_hdr = ESP_NEXT_HEADER;
2245        fixed_hdr.payload_len = U16::new(8);
2246        let mut buf = fixed_hdr_to_bytes(fixed_hdr).to_vec();
2247        buf.extend_from_slice(&[0; 8]);
2248
2249        // Ipv6Packet parsing fails.
2250        assert_matches!(
2251            (&buf[..]).parse::<Ipv6Packet<_>>(),
2252            Err(Ipv6ParseError::ParameterProblem {
2253                src_ip: _,
2254                dst_ip: _,
2255                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2256                pointer: 6, // Next Header field in Fixed Header.
2257                must_send_icmp: false,
2258                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2259            })
2260        );
2261
2262        // Ipv6PacketRaw parsing succeeds
2263        let mut buf_ref = &buf[..];
2264        assert!(buf_ref.parse::<Ipv6PacketRaw<_>>().is_ok());
2265
2266        // 2. ESP in middle (after Hop-by-Hop)
2267        let mut fixed_hdr = new_fixed_hdr();
2268        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2269        fixed_hdr.payload_len = U16::new(16);
2270        let mut buf = fixed_hdr_to_bytes(fixed_hdr).to_vec();
2271        // Hop-by-Hop header: Next Header = ESP (50), Hdr Ext Len = 0 (8 bytes total)
2272        buf.extend_from_slice(&[ESP_NEXT_HEADER, 0, 0, 0, 0, 0, 0, 0]);
2273        // ESP body
2274        buf.extend_from_slice(&[0; 8]);
2275
2276        // Ipv6Packet parsing fails
2277        assert_matches!(
2278            (&buf[..]).parse::<Ipv6Packet<_>>(),
2279            Err(Ipv6ParseError::ParameterProblem {
2280                src_ip: _,
2281                dst_ip: _,
2282                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2283                pointer: 40, // Next Header in the Hop-by-Hop header.
2284                must_send_icmp: false,
2285                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2286            })
2287        );
2288
2289        // Ipv6PacketRaw parsing succeeds
2290        let mut buf_ref = &buf[..];
2291        assert!(buf_ref.parse::<Ipv6PacketRaw<_>>().is_ok());
2292    }
2293
2294    #[test]
2295    fn test_parse_ext_hdr_unrecognized_next_header() {
2296        // Test that parsing an IPv6 packet with an unrecognized Next Header value
2297        // in an extension header succeeds for Ipv6PacketRaw, but fails for Ipv6Packet.
2298
2299        #[rustfmt::skip]
2300        let mut buf = [
2301            // FixedHeader (will be replaced later)
2302            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2303            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2304
2305            // HopByHop Options Extension Header
2306            250,                     // Next Header (unrecognized next header type)
2307            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2308            0,                       // Pad1
2309            1, 0,                    // Pad2
2310            1, 1, 0,                 // Pad3
2311
2312            // Body
2313            1, 2, 3, 4, 5,
2314        ];
2315        let mut fixed_hdr = new_fixed_hdr();
2316        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2317        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2318        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2319        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2320
2321        // Raw parsing should succeed.
2322        assert!((&buf[..]).parse::<Ipv6PacketRaw<_>>().is_ok());
2323
2324        // Full packet validation should fail.
2325        assert_eq!(
2326            (&buf[..]).parse::<Ipv6Packet<_>>().unwrap_err(),
2327            Ipv6ParseError::ParameterProblem {
2328                src_ip: DEFAULT_SRC_IP,
2329                dst_ip: DEFAULT_DST_IP,
2330                code: Icmpv6ParameterProblemCode::UnrecognizedNextHeaderType,
2331                pointer: IPV6_FIXED_HDR_LEN as u32,
2332                must_send_icmp: false,
2333                action: IpParseErrorAction::DiscardPacketSendIcmpNoMulticast,
2334            }
2335        );
2336    }
2337
2338    #[test]
2339    fn test_partial_parse() {
2340        use core::convert::TryInto as _;
2341        use core::ops::Deref as _;
2342
2343        // Can't partial parse extension headers:
2344        #[rustfmt::skip]
2345        let mut buf = [
2346            // FixedHeader (will be replaced later)
2347            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2348            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2349
2350            // HopByHop Options Extension Header
2351            IpProto::Tcp.into(), // Next Header
2352            0,                   // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2353            0,                   // Pad1
2354            1, 0,                // Pad2
2355            1, 1, 0,             // Pad3
2356
2357            // Body
2358            1, 2, 3, 4, 5,
2359        ];
2360        let len = buf.len() - IPV6_FIXED_HDR_LEN;
2361        let len = len.try_into().unwrap();
2362        let make_fixed_hdr = || {
2363            let mut fixed_hdr = new_fixed_hdr();
2364            fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2365            fixed_hdr.payload_len = U16::new(len);
2366            fixed_hdr
2367        };
2368        // make HopByHop malformed:
2369        const MALFORMED_BYTE: u8 = 10;
2370        buf[IPV6_FIXED_HDR_LEN + 1] = MALFORMED_BYTE;
2371        let fixed_hdr = fixed_hdr_to_bytes(make_fixed_hdr());
2372        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr);
2373        let mut buf = &buf[..];
2374        let partial = buf.parse::<Ipv6PacketRaw<_>>().unwrap();
2375        let Ipv6PacketRaw { fixed_hdr, extension_hdrs, body_proto } = &partial;
2376        assert_eq!(fixed_hdr.deref(), &make_fixed_hdr());
2377        let b = extension_hdrs.as_ref().incomplete().unwrap();
2378        assert_eq!(*b, &[IpProto::Tcp.into(), MALFORMED_BYTE][..]);
2379        assert_eq!(body_proto, &Err(ExtHdrParseError));
2380        assert!(Ipv6Packet::try_from_raw(partial).is_err());
2381
2382        // Incomplete body:
2383        let mut buf = [
2384            // FixedHeader (will be replaced later)
2385            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2386            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Body
2387            1, 2, 3, 4, 5,
2388        ];
2389        let make_fixed_hdr = || {
2390            let mut fixed_hdr = new_fixed_hdr();
2391            fixed_hdr.next_hdr = IpProto::Tcp.into();
2392            fixed_hdr.payload_len = U16::new(10);
2393            fixed_hdr
2394        };
2395        let fixed_hdr = fixed_hdr_to_bytes(make_fixed_hdr());
2396        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr);
2397        let mut parsebuff = &buf[..];
2398        let partial = parsebuff.parse::<Ipv6PacketRaw<_>>().unwrap();
2399        let Ipv6PacketRaw { fixed_hdr, extension_hdrs, body_proto } = &partial;
2400        assert_eq!(fixed_hdr.deref(), &make_fixed_hdr());
2401        assert_eq!(extension_hdrs.as_ref().complete().unwrap().deref(), []);
2402        let (body, proto) = body_proto.unwrap();
2403        assert_eq!(body.incomplete().unwrap(), &buf[IPV6_FIXED_HDR_LEN..]);
2404        assert_eq!(proto, IpProto::Tcp.into());
2405        assert!(Ipv6Packet::try_from_raw(partial).is_err());
2406    }
2407
2408    // Return a stock Ipv6PacketBuilder with reasonable default values.
2409    fn new_builder() -> Ipv6PacketBuilder {
2410        Ipv6PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, 64, IpProto::Tcp.into())
2411    }
2412
2413    #[test]
2414    fn test_serialize() {
2415        let mut builder = new_builder();
2416        builder.dscp_and_ecn(DscpAndEcn::new(0x12, 3));
2417        builder.flowlabel(0x10405);
2418        let mut buf = (&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
2419            .into_serializer()
2420            .wrap_in(builder)
2421            .serialize_vec_outer(&mut NoOpSerializationContext)
2422            .unwrap();
2423        // assert that we get the literal bytes we expected
2424        assert_eq!(
2425            buf.as_ref(),
2426            &[
2427                100, 177, 4, 5, 0, 10, 6, 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
2428                16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, 1, 2, 3, 4,
2429                5, 6, 7, 8, 9
2430            ][..],
2431        );
2432
2433        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2434        // assert that when we parse those bytes, we get the values we set in
2435        // the builder
2436        assert_eq!(packet.dscp_and_ecn().dscp(), 0x12);
2437        assert_eq!(packet.dscp_and_ecn().ecn(), 3);
2438        assert_eq!(packet.flowlabel(), 0x10405);
2439    }
2440
2441    #[test]
2442    fn test_partial_serialize() {
2443        let mut builder = new_builder();
2444        builder.dscp_and_ecn(DscpAndEcn::new(0x12, 3));
2445        builder.flowlabel(0x10405);
2446        const BODY: &[u8] = &[0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
2447        let packet = (&BODY).into_serializer().wrap_in(builder);
2448
2449        // Note that this header is different from the one in test_serialize
2450        // because the checksum is not calculated.
2451        const HEADER: &[u8] = &[
2452            100, 177, 4, 5, 0, 10, 6, 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
2453            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
2454        ];
2455        const PACKET_SIZE: usize = HEADER.len() + BODY.len();
2456
2457        // PartialSerializer serializes the header only if the buffer is
2458        // large enough to fit the whole header.
2459        let buf = assert_matches!(
2460            packet.partial_serialize(&mut NoOpSerializationContext, packet::new_buf_vec),
2461            Ok(PartialSerializeResult::NewBuffer { buffer, total_size: PACKET_SIZE }) => buffer
2462        );
2463        assert_eq!(buf.as_ref(), HEADER);
2464    }
2465
2466    #[test]
2467    fn test_serialize_zeroes() {
2468        // Test that Ipv6PacketBuilder::serialize properly zeroes memory before
2469        // serializing the header.
2470        let mut buf_0 = [0; IPV6_FIXED_HDR_LEN];
2471        let _: Buf<&mut [u8]> = Buf::new(&mut buf_0[..], IPV6_FIXED_HDR_LEN..)
2472            .wrap_in(new_builder())
2473            .serialize_vec_outer(&mut NoOpSerializationContext)
2474            .unwrap()
2475            .unwrap_a();
2476        let mut buf_1 = [0xFF; IPV6_FIXED_HDR_LEN];
2477        let _: Buf<&mut [u8]> = Buf::new(&mut buf_1[..], IPV6_FIXED_HDR_LEN..)
2478            .wrap_in(new_builder())
2479            .serialize_vec_outer(&mut NoOpSerializationContext)
2480            .unwrap()
2481            .unwrap_a();
2482        assert_eq!(&buf_0[..], &buf_1[..]);
2483    }
2484
2485    #[test]
2486    fn test_packet_builder_proto_not_next_header() {
2487        // Test that Ipv6PacketBuilder's `proto` field is used as the Protocol
2488        // Number for the upper layer payload, not the Next Header value for the
2489        // extension header.
2490        let mut buf = (&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
2491            .into_serializer()
2492            .wrap_in(
2493                Ipv6PacketBuilderWithHbhOptions::new(
2494                    new_builder(),
2495                    &[HopByHopOption {
2496                        action: ExtensionHeaderOptionAction::SkipAndContinue,
2497                        mutable: false,
2498                        data: HopByHopOptionData::RouterAlert { data: 0 },
2499                    }],
2500                )
2501                .unwrap(),
2502            )
2503            .serialize_vec_outer(&mut NoOpSerializationContext)
2504            .unwrap();
2505        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2506        assert_eq!(packet.proto(), IpProto::Tcp.into());
2507        assert_eq!(packet.next_header(), Ipv6ExtHdrType::HopByHopOptions.into());
2508    }
2509
2510    #[test]
2511    #[should_panic(expected = "SizeLimitExceeded, Nested { inner: Buf { buf:")]
2512    fn test_serialize_panic_packet_length() {
2513        // Test that a packet whose payload is longer than 2^16 - 1 bytes is
2514        // rejected.
2515        let _: Buf<&mut [u8]> = Buf::new(&mut [0; 1 << 16][..], ..)
2516            .wrap_in(new_builder())
2517            .serialize_vec_outer(&mut NoOpSerializationContext)
2518            .unwrap()
2519            .unwrap_a();
2520    }
2521
2522    #[test]
2523    #[should_panic(expected = "packet must have at least one extension header")]
2524    fn test_copy_header_bytes_for_fragment_without_ext_hdrs() {
2525        let mut buf = &fixed_hdr_to_bytes(new_fixed_hdr())[..];
2526        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2527        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2528    }
2529
2530    #[test]
2531    #[should_panic(expected = "exhausted all extension headers without finding fragment header")]
2532    fn test_copy_header_bytes_for_fragment_with_1_ext_hdr_no_fragment() {
2533        #[rustfmt::skip]
2534        let mut buf = [
2535            // FixedHeader (will be replaced later)
2536            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2537            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2538
2539            // HopByHop Options Extension Header
2540            IpProto::Tcp.into(),     // Next Header
2541            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2542            0,                       // Pad1
2543            1, 0,                    // Pad2
2544            1, 1, 0,                 // Pad3
2545
2546            // Body
2547            1, 2, 3, 4, 5,
2548        ];
2549        let mut fixed_hdr = new_fixed_hdr();
2550        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2551        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2552        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2553        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2554        let mut buf = &buf[..];
2555        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2556        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2557    }
2558
2559    #[test]
2560    #[should_panic(expected = "exhausted all extension headers without finding fragment header")]
2561    fn test_copy_header_bytes_for_fragment_with_2_ext_hdr_no_fragment() {
2562        #[rustfmt::skip]
2563        let mut buf = [
2564            // FixedHeader (will be replaced later)
2565            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2566            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2567
2568            // HopByHop Options Extension Header
2569            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2570            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2571            0,                       // Pad1
2572            1, 0,                    // Pad2
2573            1, 1, 0,                 // Pad3
2574
2575            // Destination Options Extension Header
2576            IpProto::Tcp.into(),    // Next Header
2577            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2578            0,                      // Pad1
2579            1, 0,                   // Pad2
2580            1, 1, 0,                // Pad3
2581            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2582
2583            // Body
2584            1, 2, 3, 4, 5,
2585        ];
2586        let mut fixed_hdr = new_fixed_hdr();
2587        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2588        fixed_hdr.payload_len = U16::new((buf.len() - IPV6_FIXED_HDR_LEN) as u16);
2589        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2590        buf[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2591        let mut buf = &buf[..];
2592        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2593        let _: Vec<_> = packet.copy_header_bytes_for_fragment();
2594    }
2595
2596    #[test]
2597    fn test_copy_header_bytes_for_fragment() {
2598        //
2599        // Only a fragment extension header
2600        //
2601
2602        #[rustfmt::skip]
2603        let mut bytes = [
2604            // FixedHeader (will be replaced later)
2605            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2606            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2607
2608            // Fragment Extension Header
2609            IpProto::Tcp.into(),     // Next Header
2610            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2611            0, 0,                    // Fragment Offset, Res, M (M_flag)
2612            1, 1, 1, 1,              // Identification
2613
2614            // Body
2615            1, 2, 3, 4, 5,
2616        ];
2617        let mut fixed_hdr = new_fixed_hdr();
2618        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2619        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2620        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2621        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2622        let mut buf = &bytes[..];
2623        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2624        let copied_bytes = packet.copy_header_bytes_for_fragment();
2625        bytes[6] = IpProto::Tcp.into();
2626        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN]);
2627
2628        //
2629        // Fragment header after a single extension header
2630        //
2631
2632        #[rustfmt::skip]
2633        let mut bytes = [
2634            // FixedHeader (will be replaced later)
2635            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2636            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2637
2638            // HopByHop Options Extension Header
2639            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2640            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2641            0,                       // Pad1
2642            1, 0,                    // Pad2
2643            1, 1, 0,                 // Pad3
2644
2645            // Fragment Extension Header
2646            IpProto::Tcp.into(),     // Next Header
2647            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2648            0, 0,                    // Fragment Offset, Res, M (M_flag)
2649            1, 1, 1, 1,              // Identification
2650
2651            // Body
2652            1, 2, 3, 4, 5,
2653        ];
2654        let mut fixed_hdr = new_fixed_hdr();
2655        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2656        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2657        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2658        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2659        let mut buf = &bytes[..];
2660        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2661        let copied_bytes = packet.copy_header_bytes_for_fragment();
2662        bytes[IPV6_FIXED_HDR_LEN] = IpProto::Tcp.into();
2663        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN + 8]);
2664
2665        //
2666        // Fragment header after many extension headers (many = 2)
2667        //
2668
2669        #[rustfmt::skip]
2670        let mut bytes = [
2671            // FixedHeader (will be replaced later)
2672            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2673            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2674
2675            // HopByHop Options Extension Header
2676            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2677            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2678            0,                       // Pad1
2679            1, 0,                    // Pad2
2680            1, 1, 0,                 // Pad3
2681
2682            // Destination Options Extension Header
2683            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2684            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2685            0,                      // Pad1
2686            1, 0,                   // Pad2
2687            1, 1, 0,                // Pad3
2688            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2689
2690            // Fragment Extension Header
2691            IpProto::Tcp.into(),     // Next Header
2692            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2693            0, 0,                    // Fragment Offset, Res, M (M_flag)
2694            1, 1, 1, 1,              // Identification
2695
2696            // Body
2697            1, 2, 3, 4, 5,
2698        ];
2699        let mut fixed_hdr = new_fixed_hdr();
2700        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2701        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2702        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2703        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2704        let mut buf = &bytes[..];
2705        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2706        let copied_bytes = packet.copy_header_bytes_for_fragment();
2707        bytes[IPV6_FIXED_HDR_LEN + 8] = IpProto::Tcp.into();
2708        assert_eq!(&copied_bytes[..], &bytes[..IPV6_FIXED_HDR_LEN + 24]);
2709
2710        //
2711        // Fragment header before an extension header
2712        //
2713
2714        #[rustfmt::skip]
2715        let mut bytes = [
2716            // FixedHeader (will be replaced later)
2717            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2718            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2719
2720            // Fragment Extension Header
2721            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2722            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2723            0, 0,                    // Fragment Offset, Res, M (M_flag)
2724            1, 1, 1, 1,              // Identification
2725
2726            // Destination Options Extension Header
2727            IpProto::Tcp.into(),    // Next Header
2728            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2729            0,                      // Pad1
2730            1, 0,                   // Pad2
2731            1, 1, 0,                // Pad3
2732            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2733
2734            // Body
2735            1, 2, 3, 4, 5,
2736        ];
2737        let mut fixed_hdr = new_fixed_hdr();
2738        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2739        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2740        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2741        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2742        let mut buf = &bytes[..];
2743        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2744        let copied_bytes = packet.copy_header_bytes_for_fragment();
2745        let mut expected_bytes = Vec::new();
2746        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2747        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 8..bytes.len() - 5]);
2748        expected_bytes[6] = Ipv6ExtHdrType::DestinationOptions.into();
2749        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2750
2751        //
2752        // Fragment header before many extension headers (many = 2)
2753        //
2754
2755        #[rustfmt::skip]
2756        let mut bytes = [
2757            // FixedHeader (will be replaced later)
2758            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2759            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2760
2761            // Fragment Extension Header
2762            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2763            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2764            0, 0,                    // Fragment Offset, Res, M (M_flag)
2765            1, 1, 1, 1,              // Identification
2766
2767            // Destination Options Extension Header
2768            Ipv6ExtHdrType::Routing.into(),    // Next Header
2769            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2770            0,                      // Pad1
2771            1, 0,                   // Pad2
2772            1, 1, 0,                // Pad3
2773            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2774
2775            // Routing extension header
2776            IpProto::Tcp.into(),                // Next Header
2777            4,                                  // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2778            0,                                  // Routing Type (Deprecated as per RFC 5095)
2779            0,                                  // Segments Left
2780            0, 0, 0, 0,                         // Reserved
2781            // Addresses for Routing Header w/ Type 0
2782            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2783            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2784
2785            // Body
2786            1, 2, 3, 4, 5,
2787        ];
2788        let mut fixed_hdr = new_fixed_hdr();
2789        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2790        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2791        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2792        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2793        let mut buf = &bytes[..];
2794        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2795        let copied_bytes = packet.copy_header_bytes_for_fragment();
2796        let mut expected_bytes = Vec::new();
2797        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2798        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 8..bytes.len() - 5]);
2799        expected_bytes[6] = Ipv6ExtHdrType::DestinationOptions.into();
2800        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2801
2802        //
2803        // Fragment header between extension headers
2804        //
2805
2806        #[rustfmt::skip]
2807        let mut bytes = [
2808            // FixedHeader (will be replaced later)
2809            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2810            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2811
2812            // HopByHop Options Extension Header
2813            Ipv6ExtHdrType::Fragment.into(),    // Next Header
2814            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2815            0,                       // Pad1
2816            1, 0,                    // Pad2
2817            1, 1, 0,                 // Pad3
2818
2819            // Fragment Extension Header
2820            Ipv6ExtHdrType::DestinationOptions.into(), // Next Header
2821            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2822            0, 0,                    // Fragment Offset, Res, M (M_flag)
2823            1, 1, 1, 1,              // Identification
2824
2825            // Destination Options Extension Header
2826            IpProto::Tcp.into(),    // Next Header
2827            1,                      // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2828            0,                      // Pad1
2829            1, 0,                   // Pad2
2830            1, 1, 0,                // Pad3
2831            1, 6, 0, 0, 0, 0, 0, 0, // Pad8
2832
2833            // Body
2834            1, 2, 3, 4, 5,
2835        ];
2836        let mut fixed_hdr = new_fixed_hdr();
2837        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2838        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2839        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2840        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2841        let mut buf = &bytes[..];
2842        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2843        let copied_bytes = packet.copy_header_bytes_for_fragment();
2844        let mut expected_bytes = Vec::new();
2845        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN + 8]);
2846        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 16..bytes.len() - 5]);
2847        expected_bytes[IPV6_FIXED_HDR_LEN] = Ipv6ExtHdrType::DestinationOptions.into();
2848        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2849
2850        //
2851        // Multiple fragment extension headers
2852        //
2853
2854        #[rustfmt::skip]
2855        let mut bytes = [
2856            // FixedHeader (will be replaced later)
2857            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2858            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2859
2860            // Fragment Extension Header
2861            Ipv6ExtHdrType::Fragment.into(),     // Next Header
2862            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2863            0, 0,                    // Fragment Offset, Res, M (M_flag)
2864            1, 1, 1, 1,              // Identification
2865
2866            // Fragment Extension Header
2867            IpProto::Tcp.into(),     // Next Header
2868            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2869            0, 0,                    // Fragment Offset, Res, M (M_flag)
2870            2, 2, 2, 2,              // Identification
2871
2872            // Body
2873            1, 2, 3, 4, 5,
2874        ];
2875        let mut fixed_hdr = new_fixed_hdr();
2876        fixed_hdr.next_hdr = Ipv6ExtHdrType::Fragment.into();
2877        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2878        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2879        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2880        let mut buf = &bytes[..];
2881        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2882        let copied_bytes = packet.copy_header_bytes_for_fragment();
2883        let mut expected_bytes = Vec::new();
2884        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN]);
2885        expected_bytes.extend_from_slice(&bytes[IPV6_FIXED_HDR_LEN + 8..bytes.len() - 5]);
2886        assert_eq!(&copied_bytes[..], &expected_bytes[..]);
2887
2888        //
2889        // Fragment header immediately following Routing header.
2890        // Regression test for https://fxbug.dev/517297331.
2891        //
2892
2893        #[rustfmt::skip]
2894        let mut bytes = [
2895            // FixedHeader (will be replaced later)
2896            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2897            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2898
2899            // HopByHop Options Extension Header
2900            Ipv6ExtHdrType::Routing.into(), // Next Header (Routing)
2901            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2902            0,                       // Pad1
2903            1, 0,                    // Pad2
2904            1, 1, 0,                 // Pad3
2905
2906            // Routing extension header
2907            Ipv6ExtHdrType::Fragment.into(), // Next Header (Fragment)
2908            4,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2909            0,                       // Routing Type
2910            0,                       // Segments Left
2911            0, 0, 0, 0,              // Reserved
2912            // Addresses for Routing Header w/ Type 0
2913            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,
2914            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
2915
2916            // Fragment Extension Header
2917            IpProto::Tcp.into(),     // Next Header (TCP)
2918            0,                       // Hdr Ext Len (In 8-octet units, not including first 8 octets)
2919            0, 0,                    // Fragment Offset, Res, M (M_flag)
2920            1, 1, 1, 1,              // Identification
2921
2922            // Body (TCP packet mock bytes)
2923            1, 2, 3, 4, 5,
2924        ];
2925        let mut fixed_hdr = new_fixed_hdr();
2926        fixed_hdr.next_hdr = Ipv6ExtHdrType::HopByHopOptions.into();
2927        fixed_hdr.payload_len = U16::new((bytes.len() - IPV6_FIXED_HDR_LEN) as u16);
2928        let fixed_hdr_buf = fixed_hdr_to_bytes(fixed_hdr);
2929        bytes[..IPV6_FIXED_HDR_LEN].copy_from_slice(&fixed_hdr_buf);
2930        let mut buf = &bytes[..];
2931        let packet = buf.parse::<Ipv6Packet<_>>().unwrap();
2932        let copied_bytes = packet.copy_header_bytes_for_fragment();
2933        let mut expected_bytes = Vec::new();
2934        // 8 (HopByHop) + (8 + 16 + 16) (Routing).
2935        expected_bytes.extend_from_slice(&bytes[..IPV6_FIXED_HDR_LEN + 48]);
2936        expected_bytes[IPV6_FIXED_HDR_LEN + 8] = IpProto::Tcp.into();
2937        assert_eq!(copied_bytes, expected_bytes);
2938    }
2939
2940    #[test_case(
2941        &[],
2942        &[],
2943        None;
2944        "no_ext_hdrs"
2945    )]
2946    #[test_case(
2947        &[Ipv6ExtHdrType::DestinationOptions],
2948        &[],
2949        Some(Ipv6ExtHdrType::DestinationOptions);
2950        "ignore_dst_options"
2951    )]
2952    #[test_case(
2953        &[
2954            Ipv6ExtHdrType::DestinationOptions,
2955            Ipv6ExtHdrType::Routing,
2956            Ipv6ExtHdrType::DestinationOptions
2957        ],
2958        &[Ipv6ExtHdrType::DestinationOptions, Ipv6ExtHdrType::Routing],
2959        Some(Ipv6ExtHdrType::DestinationOptions);
2960        "include_routing_and_everything_before"
2961    )]
2962    #[test_case(
2963        &[Ipv6ExtHdrType::HopByHopOptions, Ipv6ExtHdrType::DestinationOptions],
2964        &[Ipv6ExtHdrType::HopByHopOptions],
2965        Some(Ipv6ExtHdrType::DestinationOptions);
2966        "include_hop_by_hop_if_first"
2967    )]
2968    #[test_case(
2969        &[
2970            Ipv6ExtHdrType::HopByHopOptions,
2971            Ipv6ExtHdrType::DestinationOptions,
2972            Ipv6ExtHdrType::Routing
2973        ],
2974        &[
2975            Ipv6ExtHdrType::HopByHopOptions,
2976            Ipv6ExtHdrType::DestinationOptions,
2977            Ipv6ExtHdrType::Routing
2978        ],
2979        None;
2980        "routing_header_takes_precedence_over_hop_by_hop"
2981    )]
2982    fn test_per_fragment_header_builder(
2983        original_ext_hdrs: &[Ipv6ExtHdrType],
2984        expected_ext_hdrs: &[Ipv6ExtHdrType],
2985        expected_next_hdr: Option<Ipv6ExtHdrType>,
2986    ) {
2987        #[rustfmt::skip]
2988        fn build_routing_header(nh: u8) -> [u8; 40] {
2989            [
2990                nh, 4,  0,  0,  0,  0,  0,  0,
2991                1,  2,  3,  4,  5,  6,  7,  8,
2992                9,  10, 11, 12, 13, 14, 15, 16,
2993                17, 18, 19, 20, 21, 22, 23, 24,
2994                25, 26, 27, 28, 29, 30, 31, 32
2995            ]
2996        }
2997        fn build_hop_by_hop_header(nh: u8) -> [u8; 8] {
2998            [nh, 0, 0, 1, 0, 1, 1, 0]
2999        }
3000        #[rustfmt::skip]
3001        fn build_destination_options_header(nh: u8) -> [u8; 16] {
3002            [
3003                nh, 1, 0, 1, 0, 1, 1, 0,
3004                1,  6, 0, 0, 0, 0, 0, 0
3005            ]
3006        }
3007        fn build_fragment_header(nh: u8, id: u32) -> [u8; 8] {
3008            let [id1, id2, id3, id4] = id.to_be_bytes();
3009            [nh, 0, 0, 0, id1, id2, id3, id4]
3010        }
3011        fn build_header_bytes(ext_hdrs: &[Ipv6ExtHdrType], final_header: u8) -> Vec<u8> {
3012            // Prepare the fixed header.
3013            let mut fixed_hdr = new_fixed_hdr();
3014            if ext_hdrs.is_empty() {
3015                fixed_hdr.next_hdr = final_header;
3016            } else {
3017                fixed_hdr.next_hdr = u8::from(ext_hdrs[0]);
3018            }
3019
3020            // Prepare the extension headers.
3021            let mut ext_hdr_bytes = Vec::new();
3022            for i in 0..ext_hdrs.len() {
3023                let next_header =
3024                    if i + 1 >= ext_hdrs.len() { final_header } else { u8::from(ext_hdrs[i + 1]) };
3025                match ext_hdrs[i] {
3026                    Ipv6ExtHdrType::DestinationOptions => ext_hdr_bytes
3027                        .extend_from_slice(&build_destination_options_header(next_header)),
3028                    Ipv6ExtHdrType::Routing => {
3029                        ext_hdr_bytes.extend_from_slice(&build_routing_header(next_header))
3030                    }
3031                    Ipv6ExtHdrType::HopByHopOptions => {
3032                        ext_hdr_bytes.extend_from_slice(&build_hop_by_hop_header(next_header))
3033                    }
3034                    h => panic!("unexpected header type: {h}"),
3035                }
3036            }
3037
3038            let mut bytes = fixed_hdr_to_bytes(fixed_hdr).to_vec();
3039            bytes.extend_from_slice(&ext_hdr_bytes[..]);
3040            bytes
3041        }
3042
3043        // Generate the original packet.
3044        const BODY: [u8; 5] = [1, 2, 3, 4, 5];
3045        let payload_header = u8::from(IpProto::Tcp);
3046        let mut bytes = build_header_bytes(original_ext_hdrs, payload_header);
3047        bytes.extend_from_slice(&BODY);
3048        let len = u16::try_from(bytes.len() - IPV6_FIXED_HDR_LEN).expect("should fit in a u16");
3049        bytes.as_mut_slice()[IPV6_PAYLOAD_LEN_BYTE_RANGE].copy_from_slice(&len.to_be_bytes());
3050        let mut buf = &bytes[..];
3051        let packet = buf.parse::<Ipv6Packet<_>>().expect("parse should succeed");
3052
3053        // Serialize the header directly.
3054        let serialized = packet
3055            .per_fragment_builder()
3056            .wrap_body(EmptyBuf)
3057            .serialize_vec_outer(&mut NoOpSerializationContext)
3058            .unwrap()
3059            .unwrap_b();
3060        let expected_next_hdr = expected_next_hdr.map(u8::from).unwrap_or(payload_header);
3061        let mut expected_bytes = build_header_bytes(expected_ext_hdrs, expected_next_hdr);
3062        let len =
3063            u16::try_from(expected_bytes.len() - IPV6_FIXED_HDR_LEN).expect("should fit in a u16");
3064        expected_bytes.as_mut_slice()[IPV6_PAYLOAD_LEN_BYTE_RANGE]
3065            .copy_from_slice(&len.to_be_bytes());
3066        assert_eq!(serialized.as_ref(), &expected_bytes[..]);
3067
3068        // Serialize the per fragment header, followed by a fragment header.
3069        // NB: Everything from the original packet that wasn't included in the
3070        // header is part of the body (i.e. skipped extension headers).
3071        let builder = packet.per_fragment_builder();
3072        let body = &bytes[builder.header_len()..];
3073        const ID: u32 = 0x12345678;
3074        let frag_builder =
3075            Ipv6PacketBuilderWithFragmentHeader::new(builder, FragmentOffset::ZERO, false, ID);
3076        let serialized = frag_builder
3077            .wrap_body(body.into_serializer())
3078            .serialize_vec_outer(&mut NoOpSerializationContext)
3079            .unwrap()
3080            .unwrap_b();
3081        let mut expected_bytes =
3082            build_header_bytes(expected_ext_hdrs, u8::from(Ipv6ExtHdrType::Fragment));
3083        expected_bytes.extend_from_slice(&build_fragment_header(expected_next_hdr, ID));
3084        expected_bytes.extend_from_slice(body);
3085        let len =
3086            u16::try_from(expected_bytes.len() - IPV6_FIXED_HDR_LEN).expect("should fit in a u16");
3087        expected_bytes.as_mut_slice()[IPV6_PAYLOAD_LEN_BYTE_RANGE]
3088            .copy_from_slice(&len.to_be_bytes());
3089        assert_eq!(serialized.as_ref(), &expected_bytes[..]);
3090    }
3091
3092    #[test]
3093    fn test_next_multiple_of_eight() {
3094        for x in 0usize..=IPV6_HBH_OPTIONS_MAX_LEN {
3095            let y = next_multiple_of_eight(x);
3096            assert_eq!(y % 8, 0);
3097            assert!(y >= x);
3098            if x % 8 == 0 {
3099                assert_eq!(x, y);
3100            } else {
3101                assert_eq!(x + (8 - x % 8), y);
3102            }
3103        }
3104    }
3105
3106    fn create_ipv4_and_ipv6_builders(
3107        proto_v4: Ipv4Proto,
3108        proto_v6: Ipv6Proto,
3109    ) -> (Ipv4PacketBuilder, Ipv6PacketBuilder) {
3110        const IP_DSCP_AND_ECN: DscpAndEcn = DscpAndEcn::new(0x12, 3);
3111        const IP_TTL: u8 = 64;
3112
3113        let mut ipv4_builder =
3114            Ipv4PacketBuilder::new(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP, IP_TTL, proto_v4);
3115        ipv4_builder.dscp_and_ecn(IP_DSCP_AND_ECN);
3116        ipv4_builder.df_flag(false);
3117        ipv4_builder.mf_flag(false);
3118        ipv4_builder.fragment_offset(FragmentOffset::ZERO);
3119
3120        let mut ipv6_builder =
3121            Ipv6PacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, IP_TTL, proto_v6);
3122        ipv6_builder.dscp_and_ecn(IP_DSCP_AND_ECN);
3123        ipv6_builder.flowlabel(0x456);
3124
3125        (ipv4_builder, ipv6_builder)
3126    }
3127
3128    fn create_tcp_ipv4_and_ipv6_pkt()
3129    -> (packet::Either<EmptyBuf, Buf<Vec<u8>>>, packet::Either<EmptyBuf, Buf<Vec<u8>>>) {
3130        use crate::tcp::TcpSegmentBuilder;
3131        use core::num::NonZeroU16;
3132
3133        let tcp_src_port: NonZeroU16 = NonZeroU16::new(20).unwrap();
3134        let tcp_dst_port: NonZeroU16 = NonZeroU16::new(30).unwrap();
3135        const TCP_SEQ_NUM: u32 = 4321;
3136        const TCP_ACK_NUM: Option<u32> = Some(1234);
3137        const TCP_WINDOW_SIZE: u16 = 12345;
3138        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
3139
3140        let (ipv4_builder, ipv6_builder) =
3141            create_ipv4_and_ipv6_builders(IpProto::Tcp.into(), IpProto::Tcp.into());
3142
3143        let tcp_builder = TcpSegmentBuilder::new(
3144            DEFAULT_V4_SRC_IP,
3145            DEFAULT_V4_DST_IP,
3146            tcp_src_port,
3147            tcp_dst_port,
3148            TCP_SEQ_NUM,
3149            TCP_ACK_NUM,
3150            TCP_WINDOW_SIZE,
3151        );
3152
3153        let v4_pkt_buf = (&PAYLOAD)
3154            .into_serializer()
3155            .wrap_in(tcp_builder)
3156            .wrap_in(ipv4_builder)
3157            .serialize_vec_outer(&mut NoOpSerializationContext)
3158            .expect("Failed to serialize to v4_pkt_buf");
3159
3160        let v6_tcp_builder = TcpSegmentBuilder::new(
3161            DEFAULT_SRC_IP,
3162            DEFAULT_DST_IP,
3163            tcp_src_port,
3164            tcp_dst_port,
3165            TCP_SEQ_NUM,
3166            TCP_ACK_NUM,
3167            TCP_WINDOW_SIZE,
3168        );
3169
3170        let v6_pkt_buf = (&PAYLOAD)
3171            .into_serializer()
3172            .wrap_in(v6_tcp_builder)
3173            .wrap_in(ipv6_builder)
3174            .serialize_vec_outer(&mut NoOpSerializationContext)
3175            .expect("Failed to serialize to v4_pkt_buf");
3176
3177        (v4_pkt_buf, v6_pkt_buf)
3178    }
3179
3180    #[test]
3181    fn test_nat64_translate_tcp() {
3182        let (expected_v4_pkt_buf, mut v6_pkt_buf) = create_tcp_ipv4_and_ipv6_pkt();
3183
3184        let parsed_v6_packet =
3185            v6_pkt_buf.parse::<Ipv6Packet<_>>().expect("Failed to parse v6_pkt_buf");
3186        let nat64_translation_result =
3187            parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
3188
3189        let serializable_pkt =
3190            assert_matches!(nat64_translation_result, Nat64TranslationResult::Forward(s) => s);
3191
3192        let translated_v4_pkt_buf = serializable_pkt
3193            .serialize_vec_outer(&mut NoOpSerializationContext)
3194            .expect("Failed to serialize to translated_v4_pkt_buf");
3195
3196        assert_eq!(
3197            expected_v4_pkt_buf.to_flattened_vec(),
3198            translated_v4_pkt_buf.to_flattened_vec()
3199        );
3200    }
3201
3202    fn create_udp_ipv4_and_ipv6_pkt()
3203    -> (packet::Either<EmptyBuf, Buf<Vec<u8>>>, packet::Either<EmptyBuf, Buf<Vec<u8>>>) {
3204        use crate::udp::UdpPacketBuilder;
3205        use core::num::NonZeroU16;
3206
3207        let udp_src_port: NonZeroU16 = NonZeroU16::new(35000).unwrap();
3208        let udp_dst_port: NonZeroU16 = NonZeroU16::new(53).unwrap();
3209        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
3210
3211        let (ipv4_builder, ipv6_builder) =
3212            create_ipv4_and_ipv6_builders(IpProto::Udp.into(), IpProto::Udp.into());
3213
3214        let v4_udp_builder = UdpPacketBuilder::new(
3215            DEFAULT_V4_SRC_IP,
3216            DEFAULT_V4_DST_IP,
3217            Some(udp_src_port),
3218            udp_dst_port,
3219        );
3220
3221        let v4_pkt_buf = (&PAYLOAD)
3222            .into_serializer()
3223            .wrap_in(v4_udp_builder)
3224            .wrap_in(ipv4_builder)
3225            .serialize_vec_outer(&mut NoOpSerializationContext)
3226            .expect("Unable to serialize to v4_pkt_buf");
3227
3228        let v6_udp_builder =
3229            UdpPacketBuilder::new(DEFAULT_SRC_IP, DEFAULT_DST_IP, Some(udp_src_port), udp_dst_port);
3230
3231        let v6_pkt_buf = (&PAYLOAD)
3232            .into_serializer()
3233            .wrap_in(v6_udp_builder)
3234            .wrap_in(ipv6_builder)
3235            .serialize_vec_outer(&mut NoOpSerializationContext)
3236            .expect("Unable to serialize to v6_pkt_buf");
3237
3238        (v4_pkt_buf, v6_pkt_buf)
3239    }
3240
3241    #[test]
3242    fn test_nat64_translate_udp() {
3243        let (expected_v4_pkt_buf, mut v6_pkt_buf) = create_udp_ipv4_and_ipv6_pkt();
3244
3245        let parsed_v6_packet =
3246            v6_pkt_buf.parse::<Ipv6Packet<_>>().expect("Unable to parse Ipv6Packet");
3247        let nat64_translation_result =
3248            parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
3249
3250        let serializable_pkt = assert_matches!(nat64_translation_result,
3251                                               Nat64TranslationResult::Forward(s) => s);
3252
3253        let translated_v4_pkt_buf = serializable_pkt
3254            .serialize_vec_outer(&mut NoOpSerializationContext)
3255            .expect("Unable to serialize to translated_v4_pkt_buf");
3256
3257        assert_eq!(
3258            expected_v4_pkt_buf.to_flattened_vec(),
3259            translated_v4_pkt_buf.to_flattened_vec()
3260        );
3261    }
3262
3263    #[test]
3264    fn test_nat64_translate_non_tcp_udp_icmp() {
3265        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
3266
3267        let (ipv4_builder, ipv6_builder) =
3268            create_ipv4_and_ipv6_builders(Ipv4Proto::Other(59), Ipv6Proto::Other(59));
3269
3270        let expected_v4_pkt_buf = (&PAYLOAD)
3271            .into_serializer()
3272            .wrap_in(ipv4_builder)
3273            .serialize_vec_outer(&mut NoOpSerializationContext)
3274            .expect("Unable to serialize to expected_v4_pkt_buf");
3275
3276        let mut v6_pkt_buf = (&PAYLOAD)
3277            .into_serializer()
3278            .wrap_in(ipv6_builder)
3279            .serialize_vec_outer(&mut NoOpSerializationContext)
3280            .expect("Unable to serialize to v6_pkt_buf");
3281
3282        let translated_v4_pkt_buf = {
3283            let parsed_v6_packet = v6_pkt_buf
3284                .parse::<Ipv6Packet<_>>()
3285                .expect("Unable to serialize to translated_v4_pkt_buf");
3286
3287            let nat64_translation_result =
3288                parsed_v6_packet.nat64_translate(DEFAULT_V4_SRC_IP, DEFAULT_V4_DST_IP);
3289
3290            let serializable_pkt = assert_matches!(nat64_translation_result,
3291                                                   Nat64TranslationResult::Forward(s) => s);
3292
3293            let translated_buf = serializable_pkt
3294                .serialize_vec_outer(&mut NoOpSerializationContext)
3295                .expect("Unable to serialize to translated_buf");
3296
3297            translated_buf
3298        };
3299
3300        assert_eq!(
3301            expected_v4_pkt_buf.to_flattened_vec(),
3302            translated_v4_pkt_buf.to_flattened_vec()
3303        );
3304    }
3305
3306    #[test_case(new_builder(), true; "fixed header more frags")]
3307    #[test_case(Ipv6PacketBuilderWithHbhOptions::new(
3308        new_builder(),
3309        &[HopByHopOption {
3310            action: ExtensionHeaderOptionAction::SkipAndContinue,
3311            mutable: false,
3312            data: HopByHopOptionData::RouterAlert { data: 0 },
3313        }]).unwrap(), false; "hbh last frag")]
3314    fn ipv6_packet_builder_with_fragment_header<
3315        B: Ipv6HeaderBuilder + Ipv6HeaderBefore<Ipv6PacketBuilderWithFragmentHeader<B>> + Debug,
3316    >(
3317        inner: B,
3318        more_fragments: bool,
3319    ) {
3320        const PAYLOAD: [u8; 10] = [0, 1, 2, 3, 3, 4, 5, 7, 8, 9];
3321        let fragment_offset = FragmentOffset::new(13).unwrap();
3322        let identification = 0xABCDABCD;
3323        let builder = Ipv6PacketBuilderWithFragmentHeader::new(
3324            inner,
3325            fragment_offset,
3326            more_fragments,
3327            identification,
3328        );
3329        let mut serialized = builder
3330            .wrap_body(PAYLOAD.into_serializer())
3331            .serialize_vec_outer(&mut NoOpSerializationContext)
3332            .unwrap()
3333            .unwrap_b();
3334        let packet = serialized.parse::<Ipv6Packet<_>>().unwrap();
3335        assert!(packet.fragment_header_present());
3336        assert_eq!(packet.proto(), Ipv6Proto::Proto(IpProto::Tcp));
3337        let fragment_data = packet
3338            .extension_hdrs
3339            .into_iter()
3340            .find_map(|ext_hdr| match ext_hdr {
3341                Ipv6ExtensionHeader::Fragment { fragment_data } => Some(fragment_data),
3342                _ => None,
3343            })
3344            .unwrap();
3345        assert_eq!(fragment_data.fragment_offset(), fragment_offset);
3346        assert_eq!(fragment_data.identification(), identification);
3347        assert_eq!(fragment_data.m_flag(), more_fragments);
3348    }
3349
3350    // Tests that the PacketBuilder implementations correct the maximum body
3351    // length in PacketConstraints to remove any extension header bytes used.
3352    #[test]
3353    fn extension_headers_take_from_max_body_size() {
3354        let builder = new_builder();
3355        assert_eq!(builder.constraints().max_body_len(), IPV6_MAX_PAYLOAD_LENGTH);
3356        let builder =
3357            Ipv6PacketBuilderWithFragmentHeader::new(builder, FragmentOffset::ZERO, false, 1234);
3358        assert_eq!(
3359            builder.constraints().max_body_len(),
3360            IPV6_MAX_PAYLOAD_LENGTH - IPV6_FRAGMENT_EXT_HDR_LEN
3361        );
3362    }
3363
3364    #[test]
3365    fn test_partial_serialize_parsed() {
3366        const PACKET_BYTES: &[u8] = &[
3367            100, 177, 4, 5, 0, 10, 6, 64, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
3368            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 0, 1, 2, 3, 4, 5, 6, 7,
3369            8, 9,
3370        ];
3371        const PACKET_LEN: usize = PACKET_BYTES.len();
3372        let mut packet_bytes_copy = Vec::from(PACKET_BYTES);
3373        let mut packet_bytes_ref: &mut [u8] = &mut packet_bytes_copy[..];
3374        let packet = packet_bytes_ref.parse::<Ipv6Packet<_>>().unwrap();
3375
3376        let buf = assert_matches!(
3377            packet.partial_serialize(&mut NoOpSerializationContext, packet::new_buf_vec),
3378            Ok(PartialSerializeResult::NewBuffer { buffer, total_size: PACKET_LEN }) => buffer
3379        );
3380        assert_eq!(buf.as_ref(), PACKET_BYTES);
3381    }
3382}