bacnet_encoding/npdu/decode_error.rs
1//! Why [`decode_npdu`](super::decode_npdu) refused an NPDU.
2
3use core::fmt;
4
5use bacnet_npdu::{AddressField, MAX_MAC_LEN, Malformed};
6use bacnet_types::error::{DecodeError, DecodingKind, Error, RangeError};
7
8use super::NpduAddress;
9
10/// Why [`decode_npdu`](super::decode_npdu) refused an NPDU: `bacnet-npdu`'s
11/// [`DecodeError`](bacnet_npdu::DecodeError), with the source behind an
12/// over-long DADR owned.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum NpduDecodeError {
15 /// The DLEN or SLEN octet is larger than [`MAX_MAC_LEN`] (#1141), so the
16 /// address names no node on a standard data link or on one this stack
17 /// serves.
18 ///
19 /// Clause 6.4.4 gives routers Reject-Message-To-Network reason 6
20 /// (`ADDRESSING_ERROR`) for an NPDU whose DADR or SADR length is invalid.
21 /// [`dnet`](Self::AddressTooLong::dnet) is the network the reject names,
22 /// and [`source`](Self::AddressTooLong::source) is where it goes when a
23 /// router relayed the refused NPDU (#1158).
24 AddressTooLong {
25 /// Which address the length octet introduces.
26 field: AddressField,
27 /// The DLEN or SLEN octet as received.
28 length: u8,
29 /// The NPDU's DNET, when its control octet announces one. It precedes
30 /// both length octets on the wire, so it is always known here.
31 dnet: Option<u16>,
32 /// The NPDU's SNET/SADR, when the over-long field is the DADR and a
33 /// complete, valid source follows the DLEN octets the frame announces.
34 /// It is `None` when the SADR itself is the over-long field, since
35 /// that source names no node.
36 source: Option<NpduAddress>,
37 },
38 /// Any other malformation: a short buffer, an unknown protocol version, a
39 /// reserved network number, SLEN 0, or a truncated address or field.
40 Malformed(Malformed),
41}
42
43impl fmt::Display for NpduDecodeError {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 match self {
46 Self::AddressTooLong { field, length, .. } => write!(
47 f,
48 "NPDU {}={length} exceeds the {MAX_MAC_LEN}-octet address limit",
49 field.length_octet(),
50 ),
51 Self::Malformed(fault) => fault.fmt(f),
52 }
53 }
54}
55
56impl core::error::Error for NpduDecodeError {}
57
58impl From<NpduDecodeError> for Error {
59 /// An over-long address becomes [`Error::Range`]: the length octet is
60 /// well formed, but its value is past the limit. Its text is the
61 /// refusal's own. Any other fault becomes [`Error::Decoding`], with the
62 /// fault's text: [`DecodingKind::Missing`] for a frame that ends inside
63 /// a field, [`DecodingKind::InvalidEncoding`] for the rest. Neither
64 /// knows the offset, so it reads 0.
65 fn from(error: NpduDecodeError) -> Self {
66 match error {
67 NpduDecodeError::AddressTooLong { field, length, .. } => {
68 let label = match field {
69 AddressField::Destination => "NPDU DLEN={} exceeds the {}-octet address limit",
70 AddressField::Source => "NPDU SLEN={} exceeds the {}-octet address limit",
71 };
72 RangeError::new(label)
73 .with_values(length.into(), MAX_MAC_LEN as u64)
74 .into()
75 }
76 NpduDecodeError::Malformed(fault) => {
77 let (kind, label) = match fault {
78 Malformed::Truncated => (DecodingKind::Missing, "NPDU truncated"),
79 Malformed::Version => (
80 DecodingKind::InvalidEncoding,
81 "unsupported BACnet protocol version",
82 ),
83 Malformed::ReservedNetwork => (
84 DecodingKind::InvalidEncoding,
85 "NPDU names a reserved network number",
86 ),
87 Malformed::EmptySource => (
88 DecodingKind::InvalidEncoding,
89 "NPDU source SLEN=0 is invalid",
90 ),
91 // A fault a later bacnet-npdu adds.
92 _ => (DecodingKind::InvalidEncoding, "NPDU malformed"),
93 };
94 Error::Decoding(DecodeError::new(kind, 0, label))
95 }
96 }
97 }
98}