Skip to main content

bacnet_encoding/npdu/
decode_error.rs

1//! Why [`decode_npdu`](super::decode_npdu) refused an NPDU.
2
3#[cfg(not(feature = "std"))]
4use alloc::string::ToString;
5
6use core::fmt;
7
8use bacnet_types::error::Error;
9
10use super::NpduAddress;
11
12/// The NPCI address an [`NpduDecodeError::AddressTooLong`] concerns.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub enum NpduAddressField {
15    /// DLEN/DADR: the ultimate destination.
16    Destination,
17    /// SLEN/SADR: the original source.
18    Source,
19}
20
21impl NpduAddressField {
22    /// The NPCI name of this address's length octet: `DLEN` or `SLEN`.
23    pub fn length_octet(self) -> &'static str {
24        match self {
25            Self::Destination => "DLEN",
26            Self::Source => "SLEN",
27        }
28    }
29}
30
31impl fmt::Display for NpduAddressField {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        f.write_str(match self {
34            Self::Destination => "destination",
35            Self::Source => "source",
36        })
37    }
38}
39
40/// Why [`decode_npdu`](super::decode_npdu) refused an NPDU.
41#[derive(Debug)]
42pub enum NpduDecodeError {
43    /// The DLEN or SLEN octet is larger than [`NpduAddress::MAX_MAC_LEN`]
44    /// (#1141), so the address names no node on a standard data link or on
45    /// one this stack serves.
46    ///
47    /// Clause 6.4.4 gives routers Reject-Message-To-Network reason 6
48    /// (`ADDRESSING_ERROR`) for an NPDU whose DADR or SADR length is invalid.
49    /// [`dnet`](Self::AddressTooLong::dnet) is the network the reject names,
50    /// and [`source`](Self::AddressTooLong::source) is where it goes when a
51    /// router relayed the refused NPDU (#1158).
52    AddressTooLong {
53        /// Which address the length octet introduces.
54        field: NpduAddressField,
55        /// The DLEN or SLEN octet as received.
56        length: u8,
57        /// The NPDU's DNET, when its control octet announces one. It precedes
58        /// both length octets on the wire, so it is always known here.
59        dnet: Option<u16>,
60        /// The NPDU's SNET/SADR, when the over-long field is the DADR and a
61        /// complete, valid source follows the DLEN octets the frame announces.
62        /// It is `None` when the SADR itself is the over-long field, since
63        /// that source names no node.
64        source: Option<NpduAddress>,
65    },
66    /// Any other malformation: a short buffer, an unknown protocol version, a
67    /// reserved network number, SLEN 0, or a truncated address or field.
68    Malformed(Error),
69}
70
71impl fmt::Display for NpduDecodeError {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        match self {
74            Self::AddressTooLong { field, length, .. } => write!(
75                f,
76                "NPDU {}={length} exceeds the {}-octet address limit",
77                field.length_octet(),
78                NpduAddress::MAX_MAC_LEN
79            ),
80            Self::Malformed(error) => error.fmt(f),
81        }
82    }
83}
84
85impl core::error::Error for NpduDecodeError {
86    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
87        match self {
88            Self::AddressTooLong { .. } => None,
89            Self::Malformed(error) => Some(error),
90        }
91    }
92}
93
94impl From<Error> for NpduDecodeError {
95    fn from(error: Error) -> Self {
96        Self::Malformed(error)
97    }
98}
99
100impl From<NpduDecodeError> for Error {
101    /// An over-long address becomes [`Error::OutOfRange`]: the length octet
102    /// is well formed, but its value is past the limit.
103    fn from(error: NpduDecodeError) -> Self {
104        match error {
105            NpduDecodeError::AddressTooLong { .. } => Error::OutOfRange(error.to_string()),
106            NpduDecodeError::Malformed(error) => error,
107        }
108    }
109}