Skip to main content

bacnet_encoding/constructed/
authentication_policy.rs

1//! Clause 21 codec for `BACnetAuthenticationPolicy`, the element of an Access
2//! Point's Authentication_Policy_List array (Clause 12.31.12).
3//!
4//! A policy is a bare SEQUENCE and a whole array concatenates them with no
5//! wrapper, so the decoder reads one policy at `offset` and returns the
6//! offset just past it, the way the Access Credential element codecs do.
7//!
8//! The decoder checks structure only. An empty entry list, entries naming
9//! another object type and indexes out of sequence all decode; the Access
10//! Point judges whether a policy is usable. An index or timeout wider than
11//! 32 bits is malformed.
12
13#[cfg(not(feature = "std"))]
14use alloc::vec::Vec;
15
16use bacnet_types::constructed::{BACnetAuthenticationPolicy, BACnetAuthenticationPolicyEntry};
17use bacnet_types::error::Error;
18use bytes::BytesMut;
19
20use super::tagged::{
21    decode_ctx_boolean, decode_ctx_unsigned, expect_closing, expect_opening, next_is_closing,
22};
23use super::{decode_device_object_reference, encode_device_object_reference};
24use crate::{primitives, tags};
25
26const POLICY: &str = "BACnetAuthenticationPolicy";
27
28/// Encode one `BACnetAuthenticationPolicy` SEQUENCE: the entries inside
29/// opening and closing tag 0, each its Credential Data Input reference inside
30/// opening and closing tag 0 followed by its index as context `[1]`; then
31/// the order flag as context `[1]` and the timeout as context `[2]`.
32pub fn encode_authentication_policy(buf: &mut BytesMut, value: &BACnetAuthenticationPolicy) {
33    tags::encode_opening_tag(buf, 0);
34    for entry in &value.policy {
35        tags::encode_opening_tag(buf, 0);
36        encode_device_object_reference(buf, &entry.credential_data_input);
37        tags::encode_closing_tag(buf, 0);
38        primitives::encode_ctx_unsigned(buf, 1, u64::from(entry.index));
39    }
40    tags::encode_closing_tag(buf, 0);
41    primitives::encode_ctx_boolean(buf, 1, value.order_enforced);
42    primitives::encode_ctx_unsigned(buf, 2, u64::from(value.timeout));
43}
44
45/// Decode one `BACnetAuthenticationPolicy` SEQUENCE at `offset`.
46///
47/// A missing entry frame, order flag or timeout, an entry whose reference
48/// frame holds anything but one device-object reference or that lacks its
49/// index, an index or timeout above 32 bits, a BOOLEAN whose contents aren't
50/// 0 or 1, or a truncated member fails with [`Error::Decoding`] or
51/// [`Error::BufferTooShort`].
52pub fn decode_authentication_policy(
53    data: &[u8],
54    offset: usize,
55) -> Result<(BACnetAuthenticationPolicy, usize), Error> {
56    let mut pos = expect_opening(data, offset, 0, POLICY)?;
57    let mut policy = Vec::new();
58    while !next_is_closing(data, pos, 0)? {
59        let content = expect_opening(data, pos, 0, POLICY)?;
60        let (credential_data_input, end) = decode_device_object_reference(data, content)?;
61        let end = expect_closing(data, end, 0, POLICY)?;
62        let (index, end) = decode_ctx_unsigned::<u32>(data, end, 1, POLICY)?;
63        policy.push(BACnetAuthenticationPolicyEntry {
64            credential_data_input,
65            index,
66        });
67        pos = end;
68    }
69    let pos = expect_closing(data, pos, 0, POLICY)?;
70    let (order_enforced, pos) = decode_ctx_boolean(data, pos, 1, POLICY)?;
71    let (timeout, end) = decode_ctx_unsigned::<u32>(data, pos, 2, POLICY)?;
72    Ok((
73        BACnetAuthenticationPolicy {
74            policy,
75            order_enforced,
76            timeout,
77        },
78        end,
79    ))
80}