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