Skip to main content

packet_formats/
udp.rs

1// Copyright 2018 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 UDP packets.
6//!
7//! The UDP packet format is defined in [RFC 768].
8//!
9//! [RFC 768]: https://datatracker.ietf.org/doc/html/rfc768
10
11use core::fmt::Debug;
12#[cfg(test)]
13use core::fmt::{self, Formatter};
14use core::num::NonZeroU16;
15use core::ops::Range;
16
17use net_types::ip::{Ip, IpAddress, IpVersionMarker};
18use packet::{
19    BufferView, BufferViewMut, ByteSliceInnerPacketBuilder, EmptyBuf, FragmentedBytesMut, FromRaw,
20    InnerPacketBuilder, MaybeParsed, NestablePacketBuilder, NoOpParsingContext,
21    NoOpSerializationContext, PacketBuilder, PacketConstraints, ParsablePacket, ParseMetadata,
22    PartialPacketBuilder, SerializationContext, SerializeTarget, Serializer,
23};
24use zerocopy::byteorder::network_endian::U16;
25use zerocopy::{
26    FromBytes, Immutable, IntoBytes, KnownLayout, Ref, SplitByteSlice, SplitByteSliceMut, Unaligned,
27};
28
29use crate::error::{ParseError, ParseResult};
30use crate::ip::IpProto;
31use crate::{
32    TransportChecksumAction, compute_transport_checksum_parts,
33    compute_transport_checksum_serialize, compute_transport_pseudo_header_partial_checksum,
34};
35
36/// The size of a UDP header in bytes.
37pub const HEADER_BYTES: usize = 8;
38
39/// The offset of the checksum field, in bytes, from the start of a UDP header.
40pub const CHECKSUM_OFFSET: usize = 6;
41
42const CHECKSUM_RANGE: Range<usize> = CHECKSUM_OFFSET..CHECKSUM_OFFSET + 2;
43
44#[derive(Debug, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned)]
45#[repr(C)]
46struct Header {
47    src_port: U16,
48    dst_port: U16,
49    length: U16,
50    checksum: [u8; 2],
51}
52
53impl Header {
54    fn checksummed(&self) -> bool {
55        self.checksum != U16::ZERO
56    }
57
58    pub fn set_src_port(&mut self, new: u16) {
59        let old = self.src_port;
60        let new = U16::from(new);
61        if old == new {
62            return; // Short-circuit to skip checksum work.
63        }
64
65        self.src_port = new;
66        if self.checksummed() {
67            self.checksum =
68                internet_checksum::update(self.checksum, old.as_bytes(), new.as_bytes());
69            sanitize_checksum(&mut self.checksum);
70        }
71    }
72
73    pub fn set_dst_port(&mut self, new: NonZeroU16) {
74        let old = self.dst_port;
75        let new = U16::from(new.get());
76        if old == new {
77            return; // Short-circuit to skip checksum work.
78        }
79
80        self.dst_port = new;
81        if self.checksummed() {
82            self.checksum =
83                internet_checksum::update(self.checksum, old.as_bytes(), new.as_bytes());
84            sanitize_checksum(&mut self.checksum);
85        }
86    }
87
88    pub fn update_checksum_pseudo_header_address<A: IpAddress>(&mut self, old: A, new: A) {
89        if old == new {
90            return; // Short-circuit to skip checksum work.
91        }
92
93        if self.checksummed() {
94            self.checksum = internet_checksum::update(self.checksum, old.bytes(), new.bytes());
95            sanitize_checksum(&mut self.checksum);
96        }
97    }
98}
99
100/// A UDP packet.
101///
102/// A `UdpPacket` shares its underlying memory with the byte slice it was parsed
103/// from or serialized to, meaning that no copying or extra allocation is
104/// necessary.
105///
106/// A `UdpPacket` - whether parsed using `parse` or created using `serialize` -
107/// maintains the invariant that the checksum is always valid.
108pub struct UdpPacket<B> {
109    header: Ref<B, Header>,
110    body: B,
111}
112
113/// Context for parsing UDP packets that may be subject to hardware checksum offloading.
114pub trait UdpParseContext {
115    /// Returns true if the checksum verification should be skipped.
116    fn skip_checksum_verification(&mut self) -> bool;
117}
118
119impl UdpParseContext for NoOpParsingContext {
120    fn skip_checksum_verification(&mut self) -> bool {
121        false
122    }
123}
124
125/// Arguments required to parse a UDP packet.
126pub struct UdpParseArgs<A: IpAddress, C> {
127    src_ip: A,
128    dst_ip: A,
129    context: C,
130}
131
132impl<A: IpAddress> UdpParseArgs<A, NoOpParsingContext> {
133    /// Construct a new `UdpParseArgs`.
134    pub fn new(src_ip: A, dst_ip: A) -> Self {
135        UdpParseArgs { src_ip, dst_ip, context: NoOpParsingContext }
136    }
137}
138
139impl<A: IpAddress, C> UdpParseArgs<A, C> {
140    /// Construct a new `UdpParseArgs` with a parsing context.
141    pub fn with_context(src_ip: A, dst_ip: A, context: C) -> Self {
142        UdpParseArgs { src_ip, dst_ip, context }
143    }
144}
145
146impl<B: SplitByteSlice, A: IpAddress, C: UdpParseContext>
147    FromRaw<UdpPacketRaw<B>, UdpParseArgs<A, C>> for UdpPacket<B>
148{
149    type Error = ParseError;
150
151    fn try_from_raw_with(
152        raw: UdpPacketRaw<B>,
153        UdpParseArgs { src_ip, dst_ip, mut context }: UdpParseArgs<A, C>,
154    ) -> Result<Self, Self::Error> {
155        // See for details: https://en.wikipedia.org/wiki/User_Datagram_Protocol#Packet_structure
156        let header = raw
157            .header
158            .ok_or_else(|_| debug_err!(ParseError::Format, "too few bytes for header"))?;
159        let body = raw.body.ok_or_else(|_| debug_err!(ParseError::Format, "incomplete body"))?;
160
161        if !context.skip_checksum_verification() {
162            let checksum = header.checksum;
163            // A 0 checksum indicates that the checksum wasn't computed. In
164            // IPv4, this means that it shouldn't be validated. In IPv6, the
165            // checksum is mandatory, so this is an error.
166            if checksum != [0, 0] {
167                let parts = [Ref::bytes(&header), body.deref().as_ref()];
168                let checksum = compute_transport_checksum_parts(
169                    src_ip,
170                    dst_ip,
171                    IpProto::Udp.into(),
172                    parts.iter(),
173                )
174                .ok_or_else(debug_err_fn!(ParseError::Format, "packet too large"))?;
175
176                // Even the checksum is transmitted as 0xFFFF, the checksum of
177                // the whole UDP packet should still be 0. This is because in
178                // 1's complement, it is not possible to produce +0(0) from
179                // adding non-zero 16-bit words. Since our 0xFFFF ensures there
180                // is at least one non-zero 16-bit word, the addition can only
181                // produce -0(0xFFFF) and after negation, it is still 0. A test
182                // `test_udp_checksum_0xffff` is included to make sure this is
183                // true.
184                if checksum != [0, 0] {
185                    return debug_err!(
186                        Err(ParseError::Checksum),
187                        "invalid checksum {:X?}",
188                        header.checksum,
189                    );
190                }
191            } else if A::Version::VERSION.is_v6() {
192                return debug_err!(Err(ParseError::Format), "missing checksum");
193            }
194        }
195
196        if header.dst_port.get() == 0 {
197            return debug_err!(Err(ParseError::Format), "zero destination port");
198        }
199
200        Ok(UdpPacket { header, body })
201    }
202}
203
204impl<B: SplitByteSlice, A: IpAddress, C: UdpParseContext> ParsablePacket<B, UdpParseArgs<A, C>>
205    for UdpPacket<B>
206{
207    type Error = ParseError;
208
209    fn parse_metadata(&self) -> ParseMetadata {
210        ParseMetadata::from_packet(Ref::bytes(&self.header).len(), self.body.len(), 0)
211    }
212
213    fn parse<BV: BufferView<B>>(buffer: BV, args: UdpParseArgs<A, C>) -> ParseResult<Self> {
214        UdpPacketRaw::<B>::parse(buffer, IpVersionMarker::<A::Version>::default())
215            .and_then(|u| UdpPacket::try_from_raw_with(u, args))
216    }
217}
218
219impl<B: SplitByteSlice> UdpPacket<B> {
220    /// The packet body.
221    pub fn body(&self) -> &[u8] {
222        self.body.deref()
223    }
224
225    /// Returns the contents of the packet as a pair of slices.
226    pub fn as_bytes(&self) -> [&[u8]; 2] {
227        [&Ref::bytes(&self.header), self.body.deref()]
228    }
229
230    /// Consumes this packet and returns the body.
231    ///
232    /// Note that the returned `B` has the same lifetime as the buffer from
233    /// which this packet was parsed. By contrast, the [`body`] method returns a
234    /// slice with the same lifetime as the receiver.
235    ///
236    /// [`body`]: UdpPacket::body
237    pub fn into_body(self) -> B {
238        self.body
239    }
240
241    /// The source UDP port, if any.
242    ///
243    /// The source port is optional, and may have been omitted by the sender.
244    pub fn src_port(&self) -> Option<NonZeroU16> {
245        NonZeroU16::new(self.header.src_port.get())
246    }
247
248    /// The destination UDP port.
249    pub fn dst_port(&self) -> NonZeroU16 {
250        // Infallible because it was validated in parse.
251        NonZeroU16::new(self.header.dst_port.get()).unwrap()
252    }
253
254    /// Did this packet have a checksum?
255    ///
256    /// On IPv4, the sender may optionally omit the checksum. If this function
257    /// returns false, the sender omitted the checksum, and `parse` will not
258    /// have validated it.
259    ///
260    /// On IPv6, it is guaranteed that `checksummed` will return true because
261    /// IPv6 requires a checksum, and so any UDP packet missing one will fail
262    /// validation in `parse`.
263    pub fn checksummed(&self) -> bool {
264        self.header.checksummed()
265    }
266
267    /// Constructs a builder with the same contents as this packet.
268    pub fn builder<A: IpAddress>(&self, src_ip: A, dst_ip: A) -> UdpPacketBuilder<A> {
269        UdpPacketBuilder {
270            src_ip,
271            dst_ip,
272            src_port: self.src_port(),
273            dst_port: Some(self.dst_port()),
274        }
275    }
276
277    /// Consumes this packet and constructs a [`Serializer`] with the same
278    /// contents.
279    ///
280    /// The returned `Serializer` has the [`Buffer`] type [`EmptyBuf`], which
281    /// means it is not able to reuse the buffer backing this `UdpPacket` when
282    /// serializing, and will always need to allocate a new buffer.
283    ///
284    /// By consuming `self` instead of taking it by-reference, `into_serializer`
285    /// is able to return a `Serializer` whose lifetime is restricted by the
286    /// lifetime of the buffer from which this `UdpPacket` was parsed rather
287    /// than by the lifetime on `&self`, which may be more restricted.
288    ///
289    /// [`Buffer`]: packet::Serializer::Buffer
290    pub fn into_serializer<'a, A: IpAddress>(
291        self,
292        src_ip: A,
293        dst_ip: A,
294    ) -> impl Serializer<NoOpSerializationContext, Buffer = EmptyBuf> + Debug + 'a
295    where
296        B: 'a,
297    {
298        self.builder(src_ip, dst_ip)
299            .wrap_body(ByteSliceInnerPacketBuilder(self.body).into_serializer())
300    }
301}
302
303impl<B: SplitByteSliceMut> UdpPacket<B> {
304    /// Set the source port of the UDP packet.
305    pub fn set_src_port(&mut self, new: u16) {
306        self.header.set_src_port(new)
307    }
308
309    /// Set the destination port of the UDP packet.
310    pub fn set_dst_port(&mut self, new: NonZeroU16) {
311        self.header.set_dst_port(new);
312    }
313
314    /// Update the checksum to reflect an updated address in the pseudo header.
315    pub fn update_checksum_pseudo_header_address<A: IpAddress>(&mut self, old: A, new: A) {
316        self.header.update_checksum_pseudo_header_address(old, new);
317    }
318}
319
320impl<B: zerocopy::CloneableByteSlice + Clone> Clone for UdpPacket<B> {
321    fn clone(&self) -> Self {
322        UdpPacket { header: self.header.clone(), body: self.body.clone() }
323    }
324}
325
326/// The minimal information required from a UDP packet header.
327///
328/// A `UdpPacketHeader` may be the result of a partially parsed UDP packet in
329/// [`UdpPacketRaw`].
330#[derive(Debug, Default, KnownLayout, FromBytes, IntoBytes, Immutable, Unaligned, PartialEq)]
331#[repr(C)]
332struct UdpFlowHeader {
333    src_port: U16,
334    dst_port: U16,
335}
336
337/// A partially parsed UDP packet header.
338#[derive(Debug)]
339struct PartialHeader<B: SplitByteSlice> {
340    flow: Ref<B, UdpFlowHeader>,
341    rest: B,
342}
343
344/// A partially-parsed and not yet validated UDP packet.
345///
346/// A `UdpPacketRaw` shares its underlying memory with the byte slice it was
347/// parsed from or serialized to, meaning that no copying or extra allocation is
348/// necessary.
349///
350/// Parsing a `UdpPacketRaw` from raw data will succeed as long as at least 4
351/// bytes are available, which will be extracted as a [`UdpFlowHeader`] that
352/// contains the UDP source and destination ports. A `UdpPacketRaw` is, then,
353/// guaranteed to always have at least that minimal information available.
354///
355/// [`UdpPacket`] provides a [`FromRaw`] implementation that can be used to
356/// validate a `UdpPacketRaw`.
357pub struct UdpPacketRaw<B: SplitByteSlice> {
358    header: MaybeParsed<Ref<B, Header>, PartialHeader<B>>,
359    body: MaybeParsed<B, B>,
360}
361
362impl<B, I> ParsablePacket<B, IpVersionMarker<I>> for UdpPacketRaw<B>
363where
364    B: SplitByteSlice,
365    I: Ip,
366{
367    type Error = ParseError;
368
369    fn parse_metadata(&self) -> ParseMetadata {
370        let header_len = match &self.header {
371            MaybeParsed::Complete(h) => Ref::bytes(&h).len(),
372            MaybeParsed::Incomplete(h) => Ref::bytes(&h.flow).len() + h.rest.len(),
373        };
374        ParseMetadata::from_packet(header_len, self.body.len(), 0)
375    }
376
377    fn parse<BV: BufferView<B>>(mut buffer: BV, _args: IpVersionMarker<I>) -> ParseResult<Self> {
378        // See for details: https://en.wikipedia.org/wiki/User_Datagram_Protocol#Packet_structure
379
380        let header = if let Some(header) = buffer.take_obj_front::<Header>() {
381            header
382        } else {
383            let flow = buffer
384                .take_obj_front::<UdpFlowHeader>()
385                .ok_or_else(debug_err_fn!(ParseError::Format, "too few bytes for flow header"))?;
386            // if we can't parse an entire header, just return early since
387            // there's no way to look into how many body bytes to consume:
388            return Ok(UdpPacketRaw {
389                header: MaybeParsed::Incomplete(PartialHeader {
390                    flow,
391                    rest: buffer.take_rest_front(),
392                }),
393                body: MaybeParsed::Incomplete(buffer.into_rest()),
394            });
395        };
396        let buffer_len = buffer.len();
397
398        fn get_udp_body_length<I: Ip>(header: &Header, remaining_buff_len: usize) -> Option<usize> {
399            // IPv6 supports jumbograms, so a UDP packet may be greater than
400            // 2^16 bytes in size. In this case, the size doesn't fit in the
401            // 16-bit length field in the header, and so the length field is set
402            // to zero to indicate this.
403            //
404            // Per RFC 2675 Section 4, we only do that if the UDP header plus
405            // data is actually more than 65535.
406            if I::VERSION.is_v6()
407                && header.length.get() == 0
408                && remaining_buff_len.saturating_add(HEADER_BYTES) >= (core::u16::MAX as usize)
409            {
410                return Some(remaining_buff_len);
411            }
412
413            usize::from(header.length.get()).checked_sub(HEADER_BYTES)
414        }
415
416        let body = if let Some(body_len) = get_udp_body_length::<I>(&header, buffer_len) {
417            if body_len <= buffer_len {
418                // Discard any padding left by the previous layer. The unwrap is safe
419                // and the subtraction is always valid because body_len is guaranteed
420                // to not exceed buffer.len()
421                let _: B = buffer.take_back(buffer_len - body_len).unwrap();
422                MaybeParsed::Complete(buffer.into_rest())
423            } else {
424                // buffer does not contain all the body bytes
425                MaybeParsed::Incomplete(buffer.into_rest())
426            }
427        } else {
428            // body_len can't be calculated because it's less than the header
429            // length, consider all the rest of the buffer padding and return
430            // an incomplete empty body.
431            let _: B = buffer.take_rest_back();
432            MaybeParsed::Incomplete(buffer.into_rest())
433        };
434
435        Ok(UdpPacketRaw { header: MaybeParsed::Complete(header), body })
436    }
437}
438
439impl<B: SplitByteSlice> UdpPacketRaw<B> {
440    /// The source UDP port, if any.
441    ///
442    /// The source port is optional, and may have been omitted by the sender.
443    pub fn src_port(&self) -> Option<NonZeroU16> {
444        NonZeroU16::new(
445            self.header
446                .as_ref()
447                .map(|header| header.src_port)
448                .map_incomplete(|partial_header| partial_header.flow.src_port)
449                .into_inner()
450                .get(),
451        )
452    }
453
454    /// The destination UDP port.
455    ///
456    /// UDP packets must not have a destination port of 0; thus, if this
457    /// function returns `None`, then the packet is malformed.
458    pub fn dst_port(&self) -> Option<NonZeroU16> {
459        NonZeroU16::new(
460            self.header
461                .as_ref()
462                .map(|header| header.dst_port)
463                .map_incomplete(|partial_header| partial_header.flow.dst_port)
464                .into_inner()
465                .get(),
466        )
467    }
468
469    /// Constructs a builder with the same contents as this packet.
470    ///
471    /// Note that, since `UdpPacketRaw` does not validate its header fields,
472    /// it's possible for `builder` to produce a `UdpPacketBuilder` which
473    /// describes an invalid UDP packet. In particular, it's possible that its
474    /// destination port will be zero, which is illegal.
475    pub fn builder<A: IpAddress>(&self, src_ip: A, dst_ip: A) -> UdpPacketBuilder<A> {
476        UdpPacketBuilder { src_ip, dst_ip, src_port: self.src_port(), dst_port: self.dst_port() }
477    }
478
479    /// Consumes this packet and constructs a [`Serializer`] with the same
480    /// contents.
481    ///
482    /// Returns `None` if the body was not fully parsed.
483    ///
484    /// This method has the same validity caveats as [`builder`].
485    ///
486    /// The returned `Serializer` has the [`Buffer`] type [`EmptyBuf`], which
487    /// means it is not able to reuse the buffer backing this `UdpPacket` when
488    /// serializing, and will always need to allocate a new buffer.
489    ///
490    /// By consuming `self` instead of taking it by-reference, `into_serializer`
491    /// is able to return a `Serializer` whose lifetime is restricted by the
492    /// lifetime of the buffer from which this `UdpPacket` was parsed rather
493    /// than by the lifetime on `&self`, which may be more restricted.
494    ///
495    /// [`builder`]: UdpPacketRaw::builder
496    /// [`Buffer`]: packet::Serializer::Buffer
497    pub fn into_serializer<'a, A: IpAddress>(
498        self,
499        src_ip: A,
500        dst_ip: A,
501    ) -> Option<impl Serializer<NoOpSerializationContext, Buffer = EmptyBuf> + 'a>
502    where
503        B: 'a,
504    {
505        let builder = self.builder(src_ip, dst_ip);
506        self.body
507            .complete()
508            .ok()
509            .map(|body| builder.wrap_body(ByteSliceInnerPacketBuilder(body).into_serializer()))
510    }
511}
512
513impl<B: SplitByteSliceMut> UdpPacketRaw<B> {
514    /// Set the source port of the UDP packet.
515    pub fn set_src_port(&mut self, new: u16) {
516        match &mut self.header {
517            MaybeParsed::Complete(h) => h.set_src_port(new),
518            MaybeParsed::Incomplete(h) => {
519                h.flow.src_port = U16::from(new);
520
521                // We don't have the checksum, so there's nothing to update.
522            }
523        }
524    }
525
526    /// Set the destination port of the UDP packet.
527    pub fn set_dst_port(&mut self, new: NonZeroU16) {
528        match &mut self.header {
529            MaybeParsed::Complete(h) => h.set_dst_port(new),
530            MaybeParsed::Incomplete(h) => {
531                h.flow.dst_port = U16::from(new.get());
532
533                // We don't have the checksum, so there's nothing to update.
534            }
535        }
536    }
537
538    /// Update the checksum to reflect an updated address in the pseudo header.
539    pub fn update_checksum_pseudo_header_address<A: IpAddress>(&mut self, old: A, new: A) {
540        match &mut self.header {
541            MaybeParsed::Complete(h) => h.update_checksum_pseudo_header_address(old, new),
542            MaybeParsed::Incomplete(_) => {
543                // We don't have the checksum, so there's nothing to update.
544            }
545        }
546    }
547}
548
549// NOTE(joshlf): In order to ensure that the checksum is always valid, we don't
550// expose any setters for the fields of the UDP packet; the only way to set them
551// is via UdpPacketBuilder::serialize. This, combined with checksum validation
552// performed in UdpPacket::parse, provides the invariant that a UdpPacket always
553// has a valid checksum.
554
555/// UDP packet context relevant to serialization.
556pub struct UdpEnvelope;
557
558/// A trait for UDP serialization contexts.
559pub trait UdpSerializationContext: SerializationContext {
560    /// Converts a `UdpEnvelope` into the serialization context's state.
561    fn envelope_to_state(envelope: UdpEnvelope) -> Self::ContextState;
562
563    /// Returns the checksum action to take based on the serialization context.
564    fn checksum_action(&mut self) -> TransportChecksumAction;
565}
566
567impl UdpSerializationContext for NoOpSerializationContext {
568    fn envelope_to_state(_envelope: UdpEnvelope) -> Self::ContextState {
569        ()
570    }
571
572    fn checksum_action(&mut self) -> TransportChecksumAction {
573        TransportChecksumAction::ComputeFull
574    }
575}
576
577/// A builder for UDP packets.
578#[derive(Copy, Clone, Debug, PartialEq)]
579pub struct UdpPacketBuilder<A: IpAddress> {
580    src_ip: A,
581    dst_ip: A,
582    src_port: Option<NonZeroU16>,
583    dst_port: Option<NonZeroU16>,
584}
585
586impl<A: IpAddress> UdpPacketBuilder<A> {
587    /// Constructs a new `UdpPacketBuilder`.
588    pub fn new(
589        src_ip: A,
590        dst_ip: A,
591        src_port: Option<NonZeroU16>,
592        dst_port: NonZeroU16,
593    ) -> UdpPacketBuilder<A> {
594        UdpPacketBuilder { src_ip, dst_ip, src_port, dst_port: Some(dst_port) }
595    }
596
597    /// Returns the source port for the builder.
598    pub fn src_port(&self) -> Option<NonZeroU16> {
599        self.src_port
600    }
601
602    /// Returns the destination port for the builder.
603    pub fn dst_port(&self) -> Option<NonZeroU16> {
604        self.dst_port
605    }
606
607    /// Sets the source IP address for the builder.
608    pub fn set_src_ip(&mut self, addr: A) {
609        self.src_ip = addr;
610    }
611
612    /// Sets the destination IP address for the builder.
613    pub fn set_dst_ip(&mut self, addr: A) {
614        self.dst_ip = addr;
615    }
616
617    /// Sets the source port for the builder.
618    pub fn set_src_port(&mut self, port: u16) {
619        self.src_port = NonZeroU16::new(port);
620    }
621
622    /// Sets the destination port for the builder.
623    pub fn set_dst_port(&mut self, port: NonZeroU16) {
624        self.dst_port = Some(port);
625    }
626
627    fn serialize_header(&self, body_len: usize, mut buffer: &mut [u8]) {
628        // See for details: https://en.wikipedia.org/wiki/User_Datagram_Protocol#Packet_structure
629
630        let total_len = buffer.len() + body_len;
631
632        // `write_obj_front` consumes the extent of the receiving slice, but
633        // that behavior is undesirable here: at the end of this method, we
634        // write the checksum back into the header. To avoid this, we re-slice
635        // header before calling `write_obj_front`; the re-slice will be
636        // consumed, but `target.header` is unaffected.
637        (&mut buffer)
638            .write_obj_front(&Header {
639                src_port: U16::new(self.src_port.map_or(0, NonZeroU16::get)),
640                dst_port: U16::new(self.dst_port.map_or(0, NonZeroU16::get)),
641                length: U16::new(total_len.try_into().unwrap_or_else(|_| {
642                    if A::Version::VERSION.is_v6() {
643                        // See comment in `constraints()`.
644                        0u16
645                    } else {
646                        panic!(
647                            "total UDP packet length of {total_len} bytes \
648                            overflows 16-bit length field of UDP header"
649                        )
650                    }
651                })),
652                // Initialize the checksum to 0 so that we will get the correct
653                // value when we compute it below.
654                checksum: [0, 0],
655            })
656            .expect("too few bytes for UDP header");
657    }
658}
659
660impl<A: IpAddress> NestablePacketBuilder for UdpPacketBuilder<A> {
661    fn constraints(&self) -> PacketConstraints {
662        PacketConstraints::new(
663            HEADER_BYTES,
664            0,
665            0,
666            if A::Version::VERSION.is_v4() {
667                (1 << 16) - 1
668            } else {
669                // IPv6 supports jumbograms, so a UDP packet may be greater than
670                // 2^16 bytes. In this case, the size doesn't fit in the 16-bit
671                // length field in the header, and so the length field is set to
672                // zero. That means that, from this packet's perspective,
673                // there's no effective limit on the body size.
674                core::usize::MAX
675            },
676        )
677    }
678}
679
680impl<A: IpAddress, C: UdpSerializationContext> PacketBuilder<C> for UdpPacketBuilder<A> {
681    fn context_state(&self) -> C::ContextState {
682        C::envelope_to_state(UdpEnvelope)
683    }
684
685    fn serialize(
686        &self,
687        context: &mut C,
688        target: &mut SerializeTarget<'_>,
689        body: FragmentedBytesMut<'_, '_>,
690    ) {
691        self.serialize_header(body.len(), target.header);
692
693        let checksum = match context.checksum_action() {
694            TransportChecksumAction::ComputeFull => compute_transport_checksum_serialize(
695                self.src_ip,
696                self.dst_ip,
697                IpProto::Udp.into(),
698                target,
699                body,
700            )
701            .map(|mut c| {
702                sanitize_checksum(&mut c);
703                c
704            }),
705            TransportChecksumAction::ComputePartial => {
706                compute_transport_pseudo_header_partial_checksum(
707                    self.src_ip,
708                    self.dst_ip,
709                    IpProto::Udp.into(),
710                    target,
711                    body,
712                )
713            }
714        }
715        .unwrap(); // Not expected to fail since we were able to serialize the packet.
716
717        target.header[CHECKSUM_RANGE].copy_from_slice(&checksum[..]);
718    }
719}
720
721impl<A: IpAddress, C: UdpSerializationContext> PartialPacketBuilder<C> for UdpPacketBuilder<A> {
722    fn partial_serialize(&self, _context: &mut C, body_len: usize, buffer: &mut [u8]) {
723        self.serialize_header(body_len, buffer);
724    }
725}
726
727#[inline]
728fn sanitize_checksum(checksum_bytes: &mut [u8; 2]) {
729    // As Per RFC 768:
730    //   If the computed checksum is zero, it is transmitted as all ones
731    //   (the equivalent in one's complement arithmetic).
732    if *checksum_bytes == [0, 0] {
733        *checksum_bytes = [0xFF, 0xFF];
734    }
735}
736
737// needed by Result::unwrap_err in the tests below
738#[cfg(test)]
739impl<B> Debug for UdpPacket<B> {
740    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
741        write!(fmt, "UdpPacket")
742    }
743}
744
745#[cfg(test)]
746mod tests {
747    use assert_matches::assert_matches;
748    use byteorder::{ByteOrder, NetworkEndian};
749    use net_types::ip::{Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
750    use packet::{Buf, NestableSerializer as _, ParseBuffer, ParseBufferMut};
751    use test_case::test_case;
752
753    use super::*;
754    use crate::ethernet::{EthernetFrame, EthernetFrameLengthCheck};
755    use crate::ipv4::{Ipv4Header, Ipv4Packet};
756    use crate::ipv6::{Ipv6Header, Ipv6Packet};
757    use crate::testutil::*;
758    use crate::update_transport_checksum_pseudo_header;
759    use packet::NoOpSerializationContext;
760
761    const TEST_SRC_IPV4: Ipv4Addr = Ipv4Addr::new([1, 2, 3, 4]);
762    const TEST_DST_IPV4: Ipv4Addr = Ipv4Addr::new([5, 6, 7, 8]);
763    const TEST_SRC_IPV6: Ipv6Addr =
764        Ipv6Addr::from_bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
765    const TEST_DST_IPV6: Ipv6Addr =
766        Ipv6Addr::from_bytes([17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]);
767
768    #[test]
769    fn test_parse_serialize_full_ipv4() {
770        use crate::testdata::dns_request_v4::*;
771
772        let mut buf = ETHERNET_FRAME.bytes;
773        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
774        verify_ethernet_frame(&frame, ETHERNET_FRAME);
775
776        let mut body = frame.body();
777        let ip_packet = body.parse::<Ipv4Packet<_>>().unwrap();
778        verify_ipv4_packet(&ip_packet, IPV4_PACKET);
779
780        let mut body = ip_packet.body();
781        let udp_packet = body
782            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(
783                ip_packet.src_ip(),
784                ip_packet.dst_ip(),
785            ))
786            .unwrap();
787        verify_udp_packet(&udp_packet, UDP_PACKET);
788
789        let buffer = udp_packet
790            .body()
791            .into_serializer()
792            .wrap_in(udp_packet.builder(ip_packet.src_ip(), ip_packet.dst_ip()))
793            .wrap_in(ip_packet.builder())
794            .wrap_in(frame.builder())
795            .serialize_vec_outer(&mut NoOpSerializationContext)
796            .unwrap();
797        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
798    }
799
800    #[test]
801    fn test_parse_serialize_full_ipv6() {
802        use crate::testdata::dns_request_v6::*;
803
804        let mut buf = ETHERNET_FRAME.bytes;
805        let frame = buf.parse_with::<_, EthernetFrame<_>>(EthernetFrameLengthCheck::Check).unwrap();
806        verify_ethernet_frame(&frame, ETHERNET_FRAME);
807
808        let mut body = frame.body();
809        let ip_packet = body.parse::<Ipv6Packet<_>>().unwrap();
810        verify_ipv6_packet(&ip_packet, IPV6_PACKET);
811
812        let mut body = ip_packet.body();
813        let udp_packet = body
814            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(
815                ip_packet.src_ip(),
816                ip_packet.dst_ip(),
817            ))
818            .unwrap();
819        verify_udp_packet(&udp_packet, UDP_PACKET);
820
821        let buffer = udp_packet
822            .body()
823            .into_serializer()
824            .wrap_in(udp_packet.builder(ip_packet.src_ip(), ip_packet.dst_ip()))
825            .wrap_in(ip_packet.builder())
826            .wrap_in(frame.builder())
827            .serialize_vec_outer(&mut NoOpSerializationContext)
828            .unwrap();
829        assert_eq!(buffer.as_ref(), ETHERNET_FRAME.bytes);
830    }
831
832    #[test]
833    fn test_parse() {
834        // source port of 0 (meaning none) is allowed, as is a missing checksum
835        let mut buf = &[0, 0, 1, 2, 0, 8, 0, 0][..];
836        let packet = buf
837            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4))
838            .unwrap();
839        assert!(packet.src_port().is_none());
840        assert_eq!(packet.dst_port().get(), NetworkEndian::read_u16(&[1, 2]));
841        assert!(!packet.checksummed());
842        assert!(packet.body().is_empty());
843
844        // length of 0 is allowed in IPv6 if the body is long enough
845        let mut buf = vec![0_u8, 0, 1, 2, 0, 0, 0xBF, 0x12];
846        buf.extend((0..core::u16::MAX).into_iter().map(|p| p as u8));
847        let bv = &mut &buf[..];
848        let packet = bv
849            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(TEST_SRC_IPV6, TEST_DST_IPV6))
850            .unwrap();
851        assert!(packet.src_port().is_none());
852        assert_eq!(packet.dst_port().get(), NetworkEndian::read_u16(&[1, 2]));
853        assert!(packet.checksummed());
854        assert_eq!(packet.body().len(), core::u16::MAX as usize);
855    }
856
857    fn new_test_udp_builder() -> UdpPacketBuilder<Ipv4Addr> {
858        UdpPacketBuilder::new(
859            TEST_SRC_IPV4,
860            TEST_DST_IPV4,
861            NonZeroU16::new(1),
862            NonZeroU16::new(2).unwrap(),
863        )
864    }
865
866    #[test]
867    fn test_serialize() {
868        let mut buf = new_test_udp_builder()
869            .wrap_body(EmptyBuf)
870            .serialize_vec_outer(&mut NoOpSerializationContext)
871            .unwrap();
872        assert_eq!(buf.as_ref(), [0, 1, 0, 2, 0, 8, 239, 199]);
873        let packet = buf
874            .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4))
875            .unwrap();
876        // assert that when we parse those bytes, we get the values we set in
877        // the builder
878        assert_eq!(packet.src_port().unwrap().get(), 1);
879        assert_eq!(packet.dst_port().get(), 2);
880        assert!(packet.checksummed());
881    }
882
883    #[test]
884    fn test_serialize_zeroes() {
885        // Test that UdpPacket::serialize properly zeroes memory before serializing
886        // the header.
887        let mut buf_0 = [0; HEADER_BYTES];
888        let _: Buf<&mut [u8]> = new_test_udp_builder()
889            .wrap_body(Buf::new(&mut buf_0[..], HEADER_BYTES..))
890            .serialize_vec_outer(&mut NoOpSerializationContext)
891            .unwrap()
892            .unwrap_a();
893        let mut buf_1 = [0xFF; HEADER_BYTES];
894        let _: Buf<&mut [u8]> = new_test_udp_builder()
895            .wrap_body(Buf::new(&mut buf_1[..], HEADER_BYTES..))
896            .serialize_vec_outer(&mut NoOpSerializationContext)
897            .unwrap()
898            .unwrap_a();
899        assert_eq!(buf_0, buf_1);
900    }
901
902    #[test]
903    fn test_parse_error() {
904        // Test that while a given byte pattern optionally succeeds, zeroing out
905        // certain bytes causes failure. `zero` is a list of byte indices to
906        // zero out that should cause failure.
907        fn test_zero<I: IpAddress>(
908            src: I,
909            dst: I,
910            succeeds: bool,
911            zero: &[usize],
912            err: ParseError,
913        ) {
914            // Set checksum to zero so that, in IPV4, it will be ignored. In
915            // IPv6, this /is/ the test.
916            let mut buf = [1, 2, 3, 4, 0, 8, 0, 0];
917            if succeeds {
918                let mut buf = &buf[..];
919                assert!(buf.parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(src, dst)).is_ok());
920            }
921            for idx in zero {
922                buf[*idx] = 0;
923            }
924            let mut buf = &buf[..];
925            assert_eq!(
926                buf.parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(src, dst)).unwrap_err(),
927                err
928            );
929        }
930
931        // destination port of 0 is disallowed
932        test_zero(TEST_SRC_IPV4, TEST_DST_IPV4, true, &[2, 3], ParseError::Format);
933        // length of 0 is disallowed in IPv4
934        test_zero(TEST_SRC_IPV4, TEST_DST_IPV4, true, &[4, 5], ParseError::Format);
935        // missing checksum is disallowed in IPv6; this won't succeed ahead of
936        // time because the checksum bytes are already zero
937        test_zero(TEST_SRC_IPV6, TEST_DST_IPV6, false, &[], ParseError::Format);
938
939        // 2^32 overflows on 32-bit platforms
940        #[cfg(target_pointer_width = "64")]
941        {
942            // total length of 2^32 or greater is disallowed in IPv6
943            let mut buf = vec![0u8; 1 << 32];
944            (&mut buf[..HEADER_BYTES]).copy_from_slice(&[0, 0, 1, 2, 0, 0, 0xFF, 0xE4]);
945            assert_eq!(
946                (&buf[..])
947                    .parse_with::<_, UdpPacket<_>>(UdpParseArgs::new(TEST_SRC_IPV6, TEST_DST_IPV6))
948                    .unwrap_err(),
949                ParseError::Format
950            );
951        }
952    }
953
954    #[test_case(TEST_SRC_IPV4, TEST_DST_IPV4, true; "ipv4 skip")]
955    #[test_case(TEST_SRC_IPV4, TEST_DST_IPV4, false; "ipv4 validate")]
956    #[test_case(TEST_SRC_IPV6, TEST_DST_IPV6, true; "ipv6 skip")]
957    #[test_case(TEST_SRC_IPV6, TEST_DST_IPV6, false; "ipv6 validate")]
958    fn test_parse_invalid_checksum<A: IpAddress>(src: A, dst: A, skip: bool) {
959        let mut buf =
960            UdpPacketBuilder::new(src, dst, NonZeroU16::new(1), NonZeroU16::new(2).unwrap())
961                .wrap_body(EmptyBuf)
962                .serialize_vec_outer(&mut NoOpSerializationContext)
963                .unwrap()
964                .as_ref()
965                .to_vec();
966
967        // Corrupt the checksum.
968        buf[CHECKSUM_OFFSET] ^= 0xFF;
969        buf[CHECKSUM_OFFSET + 1] ^= 0xFF;
970
971        let mut bv = &buf[..];
972        let res = bv.parse_with::<_, UdpPacket<_>>(UdpParseArgs::with_context(
973            src,
974            dst,
975            ForceSkipChecksumValidation(skip),
976        ));
977        if skip {
978            assert_matches!(res, Ok(_));
979        } else {
980            assert_matches!(res, Err(ParseError::Checksum));
981        }
982    }
983
984    #[test]
985    #[should_panic(expected = "too few bytes for UDP header")]
986    fn test_serialize_fail_header_too_short() {
987        let mut buf = [0u8; 7];
988        let mut buf = [&mut buf[..]];
989        let buf = FragmentedBytesMut::new(&mut buf[..]);
990        let (header, body, footer) = buf.try_split_contiguous(..).unwrap();
991        let builder =
992            UdpPacketBuilder::new(TEST_SRC_IPV4, TEST_DST_IPV4, None, NonZeroU16::new(1).unwrap());
993        builder.serialize(
994            &mut NoOpSerializationContext,
995            &mut SerializeTarget { header, footer },
996            body,
997        );
998    }
999
1000    #[test]
1001    #[should_panic(expected = "total UDP packet length of 65536 bytes overflows 16-bit length \
1002                               field of UDP header")]
1003    fn test_serialize_fail_packet_too_long_ipv4() {
1004        let ser =
1005            UdpPacketBuilder::new(TEST_SRC_IPV4, TEST_DST_IPV4, None, NonZeroU16::new(1).unwrap())
1006                .wrap_body((&[0; (1 << 16) - HEADER_BYTES][..]).into_serializer());
1007        let _ = ser.serialize_vec_outer(&mut NoOpSerializationContext);
1008    }
1009
1010    #[test]
1011    fn test_partial_parse() {
1012        use core::ops::Deref as _;
1013
1014        // Try to get something with only the flow header:
1015        let buf = [0, 0, 1, 2, 10, 20];
1016        let mut bv = &buf[..];
1017        let packet =
1018            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv4>::default()).unwrap();
1019        let UdpPacketRaw { header, body } = &packet;
1020        let PartialHeader { flow, rest } = header.as_ref().incomplete().unwrap();
1021        assert_eq!(
1022            flow.deref(),
1023            &UdpFlowHeader { src_port: U16::new(0), dst_port: U16::new(0x0102) }
1024        );
1025        assert_eq!(*rest, &buf[4..]);
1026        assert_eq!(body.incomplete().unwrap(), []);
1027        assert!(
1028            UdpPacket::try_from_raw_with(packet, UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4))
1029                .is_err()
1030        );
1031
1032        // check that we fail if flow header is not retrievable:
1033        let mut buf = &[0, 0, 1][..];
1034        assert!(buf.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv4>::default()).is_err());
1035
1036        // Get an incomplete body:
1037        let buf = [0, 0, 1, 2, 0, 30, 0, 0, 10, 20];
1038        let mut bv = &buf[..];
1039        let packet =
1040            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv4>::default()).unwrap();
1041        let UdpPacketRaw { header, body } = &packet;
1042        assert_eq!(Ref::bytes(&header.as_ref().complete().unwrap()), &buf[..8]);
1043        assert_eq!(body.incomplete().unwrap(), &buf[8..]);
1044        assert!(
1045            UdpPacket::try_from_raw_with(packet, UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4))
1046                .is_err()
1047        );
1048
1049        // Incomplete empty body if total length in header is less than 8:
1050        let buf = [0, 0, 1, 2, 0, 6, 0, 0, 10, 20];
1051        let mut bv = &buf[..];
1052        let packet =
1053            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv4>::default()).unwrap();
1054        let UdpPacketRaw { header, body } = &packet;
1055        assert_eq!(Ref::bytes(&header.as_ref().complete().unwrap()), &buf[..8]);
1056        assert_eq!(body.incomplete().unwrap(), []);
1057        assert!(
1058            UdpPacket::try_from_raw_with(packet, UdpParseArgs::new(TEST_SRC_IPV4, TEST_DST_IPV4))
1059                .is_err()
1060        );
1061
1062        // IPv6 allows zero-length body, which will just be the rest of the
1063        // buffer, but only as long as it has more than 65535 bytes, otherwise
1064        // it'll just be interpreted as an invalid length:
1065        let buf = [0, 0, 1, 2, 0, 0, 0, 0, 10, 20];
1066        let mut bv = &buf[..];
1067        let packet =
1068            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv6>::default()).unwrap();
1069        let UdpPacketRaw { header, body } = &packet;
1070        assert_eq!(Ref::bytes(&header.as_ref().complete().unwrap()), &buf[..8]);
1071        assert_eq!(body.incomplete().unwrap(), []);
1072        // Now try same thing but with a body that's actually big enough to
1073        // justify len being 0.
1074        let mut buf = vec![0, 0, 1, 2, 0, 0, 0, 0, 10, 20];
1075        buf.extend((0..core::u16::MAX).into_iter().map(|x| x as u8));
1076        let bv = &mut &buf[..];
1077        let packet =
1078            bv.parse_with::<_, UdpPacketRaw<_>>(IpVersionMarker::<Ipv6>::default()).unwrap();
1079        let UdpPacketRaw { header, body } = &packet;
1080        assert_eq!(Ref::bytes(header.as_ref().complete().unwrap()), &buf[..8]);
1081        assert_eq!(body.complete().unwrap(), &buf[8..]);
1082    }
1083
1084    #[test]
1085    fn test_serialization_checksum_actions() {
1086        let body = [0x12, 0x34];
1087        let serializer = new_test_udp_builder().wrap_body(body.into_serializer());
1088
1089        // Create checksum over pseudo-header.
1090        let mut c = internet_checksum::Checksum::new();
1091        update_transport_checksum_pseudo_header::<Ipv4>(
1092            &mut c,
1093            TEST_SRC_IPV4,
1094            TEST_DST_IPV4,
1095            IpProto::Udp.into(),
1096            HEADER_BYTES + body.len(),
1097        )
1098        .expect("failed to update checksum");
1099
1100        // ComputePartial should produce the uncomplemented pseudo-header checksum.
1101        let buf = serializer
1102            .serialize_vec_outer(&mut ForceChecksumAction(TransportChecksumAction::ComputePartial))
1103            .unwrap();
1104        let [c0, c1] = c.checksum();
1105        assert_eq!(&buf.as_ref()[CHECKSUM_OFFSET..CHECKSUM_OFFSET + 2], [!c0, !c1]);
1106
1107        // ComputeFull should produce a checksum that verifies.
1108        let buf = serializer
1109            .serialize_vec_outer(&mut ForceChecksumAction(TransportChecksumAction::ComputeFull))
1110            .unwrap();
1111
1112        c.add_bytes(buf.as_ref());
1113        assert_eq!(c.checksum(), [0, 0]);
1114    }
1115
1116    #[test]
1117    fn test_udp_checksum_0xffff() {
1118        // Test the behavior when a UDP packet has to flip its checksum field.
1119        let serializer = UdpPacketBuilder::new(
1120            Ipv4Addr::new([0, 0, 0, 0]),
1121            Ipv4Addr::new([0, 0, 0, 0]),
1122            None,
1123            NonZeroU16::new(1).unwrap(),
1124        )
1125        .wrap_body((&[0xFF, 0xD9]).into_serializer());
1126        let buf = serializer.serialize_vec_outer(&mut NoOpSerializationContext).unwrap();
1127        // The serializer has flipped the bits for us.
1128        // Normally, 0xFFFF can't be checksum because -0
1129        // can not be produced by adding non-negtive 16-bit
1130        // words
1131        assert_eq!(&buf.as_ref()[CHECKSUM_OFFSET..CHECKSUM_OFFSET + 2], [0xFF, 0xFF]);
1132
1133        // When validating the checksum, just add'em up.
1134        let mut c = internet_checksum::Checksum::new();
1135        c.add_bytes(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 10]);
1136        c.add_bytes(buf.as_ref());
1137        assert!(c.checksum() == [0, 0]);
1138    }
1139
1140    #[test]
1141    fn test_udp_checksum_partial_update_0xffff() {
1142        const DST_PORT: NonZeroU16 = NonZeroU16::new(1).unwrap();
1143        const ADDR: Ipv4Addr = Ipv4::UNSPECIFIED_ADDRESS;
1144        let serializer = UdpPacketBuilder::new(ADDR, ADDR, None, DST_PORT)
1145            .wrap_body((&[0xff, 0xd9]).into_serializer());
1146        let mut buf = serializer.serialize_vec_outer(&mut NoOpSerializationContext).unwrap();
1147        let mut packet = buf
1148            .parse_with_mut::<_, UdpPacket<_>>(UdpParseArgs::new(ADDR, ADDR))
1149            .expect("parse should succeed");
1150        assert_eq!(packet.header.checksum, [0xFF, 0xFF]);
1151
1152        // Verify 0x0000 is set to 0xFFFF when updating the source port.
1153        packet.set_src_port(0); // No-Op.
1154        assert_eq!(packet.header.checksum, [0xFF, 0xFF]);
1155        packet.set_src_port(1234);
1156        assert_ne!(packet.header.checksum, [0xFF, 0xFF]);
1157        packet.set_src_port(0); // Real Change.
1158        assert_eq!(packet.header.checksum, [0xFF, 0xFF]);
1159
1160        // Verify 0x0000 is set to 0xFFFF when updating the destination port.
1161        packet.set_dst_port(DST_PORT); // No-Op.
1162        assert_eq!(packet.header.checksum, [0xFF, 0xFF]);
1163        packet.set_dst_port(NonZeroU16::new(1234).unwrap());
1164        assert_ne!(packet.header.checksum, [0xFF, 0xFF]);
1165        packet.set_dst_port(DST_PORT); // Real Change.
1166        assert_eq!(packet.header.checksum, [0xFF, 0xFF]);
1167
1168        // Verify 0x0000 is set to 0xFFFF when updating the pseudo header addr.
1169        packet.update_checksum_pseudo_header_address(ADDR, ADDR); // No-Op.
1170        assert_eq!(packet.header.checksum, [0xFF, 0xFF]);
1171        const OTHER_ADDR: Ipv4Addr = Ipv4Addr::new([123, 124, 125, 126]);
1172        packet.update_checksum_pseudo_header_address(ADDR, OTHER_ADDR);
1173        assert_ne!(packet.header.checksum, [0xFF, 0xFF]);
1174        packet.update_checksum_pseudo_header_address(OTHER_ADDR, ADDR); // Real Change.
1175        assert_eq!(packet.header.checksum, [0xFF, 0xFF]);
1176    }
1177}