Skip to main content

bacnet_encoding/constructed/
access_credential.rs

1//! Clause 21 codecs for the elements of two Access Credential arrays
2//! (Clause 12.35): Assigned_Access_Rights (`BACnetAssignedAccessRights`) and
3//! Authentication_Factors (`BACnetCredentialAuthenticationFactor`, which
4//! embeds a `BACnetAuthenticationFactor`). The Credential Data Input serves
5//! the bare factor as its Present_Value and an array of
6//! `BACnetAuthenticationFactorFormat` as Supported_Formats (Clause 12.36).
7//!
8//! Each element is a bare SEQUENCE; a whole array concatenates them with no
9//! wrapper, so each decoder reads one element at `offset` and returns the
10//! offset just past it. A caller holding exactly one element must check that
11//! offset reaches the end of its data.
12//!
13//! The decoders check structure only. Enumerated members up to 32 bits are
14//! kept as received, reserved and vendor values included, for the object to
15//! judge; a member wider than 32 bits is malformed.
16
17use bacnet_types::constructed::{
18    BACnetAssignedAccessRights, BACnetAuthenticationFactor, BACnetAuthenticationFactorFormat,
19    BACnetCredentialAuthenticationFactor,
20};
21use bacnet_types::enums::{AccessAuthenticationFactorDisable, AuthenticationFactorType};
22use bacnet_types::error::Error;
23use bytes::BytesMut;
24
25use super::tagged::{
26    decode_ctx_boolean, decode_ctx_octet_string, decode_ctx_unsigned, decode_optional_ctx,
27    expect_closing, expect_opening,
28};
29use super::{decode_device_object_reference, encode_device_object_reference};
30use crate::{primitives, tags};
31
32const RIGHTS: &str = "BACnetAssignedAccessRights";
33const FACTOR: &str = "BACnetAuthenticationFactor";
34const CREDENTIAL_FACTOR: &str = "BACnetCredentialAuthenticationFactor";
35const FACTOR_FORMAT: &str = "BACnetAuthenticationFactorFormat";
36
37/// Encode one `BACnetAssignedAccessRights` SEQUENCE: the reference inside
38/// opening and closing tag 0, then the enable flag as context `[1]`.
39pub fn encode_assigned_access_rights(buf: &mut BytesMut, value: &BACnetAssignedAccessRights) {
40    tags::encode_opening_tag(buf, 0);
41    encode_device_object_reference(buf, &value.assigned_access_rights);
42    tags::encode_closing_tag(buf, 0);
43    primitives::encode_ctx_boolean(buf, 1, value.enable);
44}
45
46/// Decode one `BACnetAssignedAccessRights` SEQUENCE at `offset`.
47///
48/// A missing frame or member, a frame holding anything but one
49/// device-object reference, or a BOOLEAN whose contents aren't 0 or 1 fails
50/// with [`Error::Decoding`] or [`Error::BufferTooShort`].
51pub fn decode_assigned_access_rights(
52    data: &[u8],
53    offset: usize,
54) -> Result<(BACnetAssignedAccessRights, usize), Error> {
55    let pos = expect_opening(data, offset, 0, RIGHTS)?;
56    let (assigned_access_rights, pos) = decode_device_object_reference(data, pos)?;
57    let pos = expect_closing(data, pos, 0, RIGHTS)?;
58    let (enable, end) = decode_ctx_boolean(data, pos, 1, RIGHTS)?;
59    Ok((
60        BACnetAssignedAccessRights {
61            assigned_access_rights,
62            enable,
63        },
64        end,
65    ))
66}
67
68/// Encode one `BACnetAuthenticationFactor` SEQUENCE: format type `[0]`,
69/// format class `[1]` and value `[2]`, all primitive context tags.
70pub fn encode_authentication_factor(buf: &mut BytesMut, value: &BACnetAuthenticationFactor) {
71    primitives::encode_ctx_enumerated(buf, 0, value.format_type.to_raw());
72    primitives::encode_ctx_unsigned(buf, 1, u64::from(value.format_class));
73    primitives::encode_ctx_octet_string(buf, 2, &value.value);
74}
75
76/// Decode one `BACnetAuthenticationFactor` SEQUENCE at `offset`.
77///
78/// The three members must appear in order. A missing or out-of-order member,
79/// a truncated one, or a format type or class wider than 32 bits fails with
80/// [`Error::Decoding`] or [`Error::BufferTooShort`]; an empty value is
81/// accepted.
82pub fn decode_authentication_factor(
83    data: &[u8],
84    offset: usize,
85) -> Result<(BACnetAuthenticationFactor, usize), Error> {
86    let (format_type, pos) = decode_ctx_unsigned::<u32>(data, offset, 0, FACTOR)?;
87    let (format_class, pos) = decode_ctx_unsigned::<u32>(data, pos, 1, FACTOR)?;
88    let (value, end) = decode_ctx_octet_string(data, pos, 2, FACTOR)?;
89    Ok((
90        BACnetAuthenticationFactor {
91            format_type: AuthenticationFactorType::from_raw(format_type),
92            format_class,
93            value,
94        },
95        end,
96    ))
97}
98
99/// Encode one `BACnetAuthenticationFactorFormat` SEQUENCE: the format type
100/// as context `[0]`, then each vendor member that is present, the vendor
101/// identifier as context `[1]` and the vendor's format as context `[2]`.
102pub fn encode_authentication_factor_format(
103    buf: &mut BytesMut,
104    value: &BACnetAuthenticationFactorFormat,
105) {
106    primitives::encode_ctx_enumerated(buf, 0, value.format_type.to_raw());
107    if let Some(vendor_id) = value.vendor_id {
108        primitives::encode_ctx_unsigned(buf, 1, u64::from(vendor_id));
109    }
110    if let Some(vendor_format) = value.vendor_format {
111        primitives::encode_ctx_unsigned(buf, 2, u64::from(vendor_format));
112    }
113}
114
115/// Decode one `BACnetAuthenticationFactorFormat` SEQUENCE at `offset`.
116///
117/// The format type is required and the two vendor members optional, each
118/// read only when its tag comes next, so the decoder stops in front of the
119/// next element of an array. A missing format type, one wider than 32 bits,
120/// a vendor member above 65535 or a truncated member fails with
121/// [`Error::Decoding`] or [`Error::BufferTooShort`]. The decoder doesn't
122/// check whether the vendor members suit the format type; the object does.
123pub fn decode_authentication_factor_format(
124    data: &[u8],
125    offset: usize,
126) -> Result<(BACnetAuthenticationFactorFormat, usize), Error> {
127    let (format_type, pos) = decode_ctx_unsigned::<u32>(data, offset, 0, FACTOR_FORMAT)?;
128    let (vendor_id, pos) =
129        decode_optional_ctx(data, pos, 1, FACTOR_FORMAT, decode_ctx_unsigned::<u16>)?;
130    let (vendor_format, end) =
131        decode_optional_ctx(data, pos, 2, FACTOR_FORMAT, decode_ctx_unsigned::<u16>)?;
132    Ok((
133        BACnetAuthenticationFactorFormat {
134            format_type: AuthenticationFactorType::from_raw(format_type),
135            vendor_id,
136            vendor_format,
137        },
138        end,
139    ))
140}
141
142/// Encode one `BACnetCredentialAuthenticationFactor` SEQUENCE: the disable
143/// value as context `[0]`, then the factor inside opening and closing tag 1.
144pub fn encode_credential_authentication_factor(
145    buf: &mut BytesMut,
146    value: &BACnetCredentialAuthenticationFactor,
147) {
148    primitives::encode_ctx_enumerated(buf, 0, value.disable.to_raw());
149    tags::encode_opening_tag(buf, 1);
150    encode_authentication_factor(buf, &value.authentication_factor);
151    tags::encode_closing_tag(buf, 1);
152}
153
154/// Decode one `BACnetCredentialAuthenticationFactor` SEQUENCE at `offset`.
155///
156/// Fails as [`decode_authentication_factor`] does, and also when the disable
157/// member is missing or wider than 32 bits or the factor's frame is missing
158/// or holds anything after the factor.
159pub fn decode_credential_authentication_factor(
160    data: &[u8],
161    offset: usize,
162) -> Result<(BACnetCredentialAuthenticationFactor, usize), Error> {
163    let (disable, pos) = decode_ctx_unsigned::<u32>(data, offset, 0, CREDENTIAL_FACTOR)?;
164    let pos = expect_opening(data, pos, 1, CREDENTIAL_FACTOR)?;
165    let (authentication_factor, pos) = decode_authentication_factor(data, pos)?;
166    let end = expect_closing(data, pos, 1, CREDENTIAL_FACTOR)?;
167    Ok((
168        BACnetCredentialAuthenticationFactor {
169            disable: AccessAuthenticationFactorDisable::from_raw(disable),
170            authentication_factor,
171        },
172        end,
173    ))
174}