Skip to main content

bacnet_bip_codec/ipv6/
function.rs

1//! The B/IPv6 BVLC function and result codes, and the payload layout each
2//! function has.
3
4use super::{BIP6_ADDRESS_LENGTH, VMAC_LENGTH};
5use crate::function::named_codes;
6use crate::PayloadShape;
7
8named_codes! {
9    /// A B/IPv6 BVLC function code: the second octet of every B/IPv6 BVLL
10    /// message, which says what the message is (Annex U.2, Table U-1).
11    ///
12    /// The set is open, so a decoder can report a code it doesn't know. The
13    /// constants are the twelve functions of Annex U.2. Code 0x0B is not
14    /// among them: the clause that defined it (U.2.12) was deleted, so this
15    /// edition treats it like any other unknown code.
16    pub struct Bvlc6Function(u8);
17
18    /// Acknowledges a request that needs an answer (U.2.1).
19    const BVLC_RESULT = 0x00;
20    /// A directed NPDU, naming its recipient's VMAC (U.2.2).
21    const ORIGINAL_UNICAST_NPDU = 0x01;
22    /// A broadcast NPDU from a node that isn't a foreign device (U.2.3).
23    const ORIGINAL_BROADCAST_NPDU = 0x02;
24    /// Asks, by multicast, which B/IPv6 address a VMAC is at (U.2.4).
25    const ADDRESS_RESOLUTION = 0x03;
26    /// An Address-Resolution a BBMD sends on into other multicast domains
27    /// (U.2.5).
28    const FORWARDED_ADDRESS_RESOLUTION = 0x04;
29    /// Answers either kind of Address-Resolution (U.2.6).
30    const ADDRESS_RESOLUTION_ACK = 0x05;
31    /// Asks a node at a known B/IPv6 address for its VMAC (U.2.7).
32    const VIRTUAL_ADDRESS_RESOLUTION = 0x06;
33    /// Answers a Virtual-Address-Resolution (U.2.8).
34    const VIRTUAL_ADDRESS_RESOLUTION_ACK = 0x07;
35    /// An NPDU a BBMD passes on, with its originator's VMAC and address
36    /// (U.2.9).
37    const FORWARDED_NPDU = 0x08;
38    /// Asks a BBMD to take the sender as a foreign device (U.2.10).
39    const REGISTER_FOREIGN_DEVICE = 0x09;
40    /// Removes one entry from a BBMD's foreign device table (U.2.11).
41    const DELETE_FOREIGN_DEVICE_TABLE_ENTRY = 0x0A;
42    /// A foreign device's broadcast, for its BBMD to distribute (U.2.13).
43    const DISTRIBUTE_BROADCAST_TO_NETWORK = 0x0C;
44}
45
46named_codes! {
47    /// The result code a B/IPv6 BVLC-Result carries (Annex U.2.1.1):
48    /// success, or a NAK naming the request that failed.
49    pub struct Bvlc6ResultCode(u16);
50
51    /// The request succeeded.
52    const SUCCESSFUL_COMPLETION = 0x0000;
53    /// A BBMD refused an Address-Resolution sent to it: the sender is not
54    /// one of its registered foreign devices, or the BBMD could not pass the
55    /// request on (U.4.4).
56    const ADDRESS_RESOLUTION_NAK = 0x0030;
57    /// A Virtual-Address-Resolution failed.
58    const VIRTUAL_ADDRESS_RESOLUTION_NAK = 0x0060;
59    /// Register-Foreign-Device failed or is not supported.
60    const REGISTER_FOREIGN_DEVICE_NAK = 0x0090;
61    /// Delete-Foreign-Device-Table-Entry failed or is not supported.
62    const DELETE_FOREIGN_DEVICE_TABLE_ENTRY_NAK = 0x00A0;
63    /// Distribute-Broadcast-To-Network failed or is not supported.
64    const DISTRIBUTE_BROADCAST_TO_NETWORK_NAK = 0x00C0;
65}
66
67impl Bvlc6Function {
68    /// The payload layout of this function, from its format clause in
69    /// Annex U.2, or `None` for a code Annex U doesn't define. The payload
70    /// is everything after the 4-octet header, so it starts with a VMAC in
71    /// every message (Table U-1 gives the whole lengths).
72    ///
73    /// - Virtual-Address-Resolution: the source VMAC, 3 octets (U.2.7.1).
74    /// - BVLC-Result and Register-Foreign-Device: the source VMAC and a
75    ///   result code or time-to-live, 5 octets (U.2.1.1, U.2.10.1).
76    /// - Address-Resolution and the two ACKs: two VMACs, 6 octets (U.2.4.1,
77    ///   U.2.6.1, U.2.8.1).
78    /// - Delete-Foreign-Device-Table-Entry: the source VMAC and the entry's
79    ///   B/IPv6 address, 21 octets (U.2.11.1).
80    /// - Forwarded-Address-Resolution: two VMACs and the originator's
81    ///   address, 24 octets (U.2.5.1).
82    /// - Original-Broadcast-NPDU and Distribute-Broadcast-To-Network: a VMAC,
83    ///   then the NPDU (U.2.3.1, U.2.13.1).
84    /// - Original-Unicast-NPDU: two VMACs, then the NPDU (U.2.2.1).
85    /// - Forwarded-NPDU: the originator's VMAC and address, then the NPDU
86    ///   (U.2.9.1).
87    ///
88    /// ```
89    /// use bacnet_bip_codec::ipv6::Bvlc6Function;
90    /// use bacnet_bip_codec::PayloadShape;
91    ///
92    /// assert_eq!(
93    ///     Bvlc6Function::FORWARDED_NPDU.payload_shape(),
94    ///     Some(PayloadShape::Npdu { prefix: 21 }),
95    /// );
96    /// assert_eq!(Bvlc6Function::from_raw(0x0B).payload_shape(), None);
97    /// ```
98    #[must_use]
99    pub const fn payload_shape(self) -> Option<PayloadShape> {
100        Some(match self {
101            Self::VIRTUAL_ADDRESS_RESOLUTION => PayloadShape::Fixed(VMAC_LENGTH),
102            Self::BVLC_RESULT | Self::REGISTER_FOREIGN_DEVICE => {
103                PayloadShape::Fixed(VMAC_LENGTH + 2)
104            }
105            Self::ADDRESS_RESOLUTION
106            | Self::ADDRESS_RESOLUTION_ACK
107            | Self::VIRTUAL_ADDRESS_RESOLUTION_ACK => PayloadShape::Fixed(2 * VMAC_LENGTH),
108            Self::DELETE_FOREIGN_DEVICE_TABLE_ENTRY => {
109                PayloadShape::Fixed(VMAC_LENGTH + BIP6_ADDRESS_LENGTH)
110            }
111            Self::FORWARDED_ADDRESS_RESOLUTION => {
112                PayloadShape::Fixed(2 * VMAC_LENGTH + BIP6_ADDRESS_LENGTH)
113            }
114            Self::ORIGINAL_BROADCAST_NPDU | Self::DISTRIBUTE_BROADCAST_TO_NETWORK => {
115                PayloadShape::Npdu {
116                    prefix: VMAC_LENGTH,
117                }
118            }
119            Self::ORIGINAL_UNICAST_NPDU => PayloadShape::Npdu {
120                prefix: 2 * VMAC_LENGTH,
121            },
122            Self::FORWARDED_NPDU => PayloadShape::Npdu {
123                prefix: VMAC_LENGTH + BIP6_ADDRESS_LENGTH,
124            },
125            _ => return None,
126        })
127    }
128
129    /// The NAK named after this function in Annex U.2.1.1, for the five
130    /// requests that have one: both address resolutions, foreign-device
131    /// registration, FDT entry deletion and broadcast distribution. `None`
132    /// for every other code.
133    ///
134    /// Annex U says when to send four of them. A device that is not a BBMD
135    /// answers the last three with their NAKs (U.4.4, U.4.5.3, U.4.5.4), and
136    /// so does a BBMD that can't carry them out. A BBMD answers an
137    /// Address-Resolution sent to it with its NAK when the sender is not a
138    /// registered foreign device, or when the BBMD can't pass the request on
139    /// (U.4.4); a broadcast distribution from a node that isn't a registered
140    /// foreign device gets its NAK the same way. A
141    /// Forwarded-Address-Resolution is never answered with a BVLC-Result.
142    #[must_use]
143    pub const fn nak(self) -> Option<Bvlc6ResultCode> {
144        Some(match self {
145            Self::ADDRESS_RESOLUTION => Bvlc6ResultCode::ADDRESS_RESOLUTION_NAK,
146            Self::VIRTUAL_ADDRESS_RESOLUTION => Bvlc6ResultCode::VIRTUAL_ADDRESS_RESOLUTION_NAK,
147            Self::REGISTER_FOREIGN_DEVICE => Bvlc6ResultCode::REGISTER_FOREIGN_DEVICE_NAK,
148            Self::DELETE_FOREIGN_DEVICE_TABLE_ENTRY => {
149                Bvlc6ResultCode::DELETE_FOREIGN_DEVICE_TABLE_ENTRY_NAK
150            }
151            Self::DISTRIBUTE_BROADCAST_TO_NETWORK => {
152                Bvlc6ResultCode::DISTRIBUTE_BROADCAST_TO_NETWORK_NAK
153            }
154            _ => return None,
155        })
156    }
157}