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}