Skip to main content

bacnet_encoding/npdu/
decode_error.rs

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