Skip to main content

packet_formats/
error.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//! Custom error types for the packet formats.
6
7use core::convert::Infallible as Never;
8
9use crate::icmp::Icmpv6ParameterProblemCode;
10use net_types::MulticastAddress;
11use net_types::ip::{IpAddress, Ipv6Addr};
12use packet::records::options::OptionParseErr;
13use thiserror::Error;
14
15/// Result returned from packet parsing functions.
16pub type ParseResult<T> = core::result::Result<T, ParseError>;
17
18/// Results returned from IP packet parsing functions in the netstack.
19pub type IpParseResult<I, T> = core::result::Result<T, <I as crate::ip::IpExt>::PacketParseError>;
20
21/// Error type for packet parsing.
22#[derive(Copy, Clone, Error, Debug, PartialEq)]
23pub enum ParseError {
24    /// Operation is not supported.
25    #[error("Operation is not supported")]
26    NotSupported,
27    /// Operation is not expected in this context.
28    #[error("Operation is not expected in this context")]
29    NotExpected,
30    /// Checksum is invalid.
31    #[error("Invalid checksum")]
32    Checksum,
33    /// Packet is not formatted properly.
34    #[error("Packet is not formatted properly")]
35    Format,
36}
37
38impl From<Never> for ParseError {
39    fn from(err: Never) -> ParseError {
40        match err {}
41    }
42}
43
44impl From<OptionParseErr> for ParseError {
45    fn from(OptionParseErr: OptionParseErr) -> ParseError {
46        ParseError::Format
47    }
48}
49
50/// Action to take when an IP node fails to parse a received IP packet.
51///
52/// These actions are taken from [RFC 8200 section 4.2]. Although these actions
53/// are defined by an IPv6 RFC, IPv4 nodes that fail to parse a received packet
54/// will take similar actions.
55///
56/// [RFC 8200 section 4.2]: https://tools.ietf.org/html/rfc8200#section-4.2
57#[derive(Copy, Clone, Debug, PartialEq)]
58pub enum IpParseErrorAction {
59    /// Discard the packet and do nothing further.
60    DiscardPacket,
61
62    /// Discard the packet and send an ICMP response.
63    DiscardPacketSendIcmp,
64
65    /// Discard the packet and send an ICMP response if the packet's
66    /// destination address was not a multicast address.
67    DiscardPacketSendIcmpNoMulticast,
68}
69
70impl IpParseErrorAction {
71    /// Determines whether or not an ICMP message should be sent.
72    ///
73    /// Returns `true` if the caller should send an ICMP response. The caller should
74    /// send an ICMP response if an action is set to `DiscardPacketSendIcmp`, or
75    /// if an action is set to `DiscardPacketSendIcmpNoMulticast` and `dst_addr`
76    /// (the destination address of the original packet that lead to a parsing
77    /// error) is not a multicast address.
78    pub fn should_send_icmp<A: IpAddress>(&self, dst_addr: &A) -> bool {
79        match *self {
80            IpParseErrorAction::DiscardPacket => false,
81            IpParseErrorAction::DiscardPacketSendIcmp => true,
82            IpParseErrorAction::DiscardPacketSendIcmpNoMulticast => !dst_addr.is_multicast(),
83        }
84    }
85
86    /// Determines whether or not an ICMP message should be sent even if the original
87    /// packet's destination address is a multicast.
88    ///
89    /// Per [RFC 1122 section 3.2.2] and [RFC 4443 section 2.4], ICMP messages MUST NOT
90    /// be sent in response to packets destined to a multicast or broadcast address.
91    /// However, RFC 4443 section 2.4 includes an exception to this rule if certain
92    /// criteria are met when parsing IPv6 extension header options.
93    /// `should_send_icmp_to_multicast` returns `true` if the criteria are met.
94    /// See RFC 4443 section 2.4 for more details about the exception.
95    ///
96    /// [RFC 1122 section 3.2.2]: https://tools.ietf.org/html/rfc1122#section-3.2.2
97    /// [RFC 4443 section 2.4]: https://tools.ietf.org/html/rfc4443#section-2.4
98    pub fn should_send_icmp_to_multicast(&self) -> bool {
99        match *self {
100            IpParseErrorAction::DiscardPacketSendIcmp => true,
101            IpParseErrorAction::DiscardPacket
102            | IpParseErrorAction::DiscardPacketSendIcmpNoMulticast => false,
103        }
104    }
105}
106
107/// Error type for IP packet parsing.
108#[allow(missing_docs)]
109/// Error when parsing an IPv6 packet.
110#[derive(Debug, Error, PartialEq, Clone)]
111pub enum Ipv6ParseError {
112    #[error("Parsing Error: {error:?}")]
113    Parse {
114        #[from]
115        error: ParseError,
116    },
117    /// For errors where an ICMP Parameter Problem error needs to be sent to the
118    /// source of a packet.
119    #[error("Parameter Problem")]
120    ParameterProblem {
121        /// The packet's source IP address.
122        src_ip: Ipv6Addr,
123
124        /// The packet's destination IP address.
125        dst_ip: Ipv6Addr,
126
127        /// The ICMPv6 parameter problem code that provides more
128        /// granular information about the parameter problem encountered.
129        code: Icmpv6ParameterProblemCode,
130
131        /// The offset of the erroneous value within the IP packet.
132        pointer: u32,
133
134        /// Whether an IP node MUST send an ICMP response if [`action`]
135        /// specifies it.
136        ///
137        /// See [`action`] for more details.
138        ///
139        /// [`action`]: crate::error::Ipv6ParseError::ParameterProblem::action
140        must_send_icmp: bool,
141
142        /// The action IP nodes should take upon encountering this error.
143        ///
144        /// If [`must_send_icmp`] is `true`, IP nodes MUST send an ICMP response
145        /// if `action` specifies it. Otherwise, the node MAY choose to discard
146        /// the packet and do nothing further.
147        ///
148        /// [`must_send_icmp`]: crate::error::Ipv6ParseError::ParameterProblem::must_send_icmp
149        action: IpParseErrorAction,
150    },
151}
152
153impl From<OptionParseErr> for Ipv6ParseError {
154    fn from(error: OptionParseErr) -> Self {
155        Ipv6ParseError::Parse { error: error.into() }
156    }
157}
158
159/// Error type for an unrecognized protocol code of type `T`.
160#[derive(Debug, Eq, PartialEq)]
161pub struct UnrecognizedProtocolCode<T>(pub T);
162
163/// A not zero value for `T` was observed, but zero was expected.
164#[derive(Debug, Eq, PartialEq)]
165pub struct NotZeroError<T>(pub T);