Skip to main content

bacnet_objects/network_port/
bip6_config.rs

1//! Declared configuration for an unbound application-level B/IPv6 port
2//! (Annex U). As for B/IP, the mode is not configuration: a registered
3//! owner publishes it, with its actual bind.
4
5use crate::common;
6use bacnet_types::error::Error;
7
8/// FF05::BAC0, the site-local BACnet group a B/IPv6 transport broadcasts to
9/// by default (Annex U.4).
10const SITE_LOCAL_GROUP: [u8; 16] = [0xFF, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xBA, 0xC0];
11
12/// Complete configured B/IPv6 snapshot. Fixed-size addresses prevent
13/// malformed IPv6 values. The unspecified address `::` for the address,
14/// gateway or one DNS server means unknown or unconfigured; none of them
15/// describes an observed interface or route.
16///
17/// The object serves this as a port whose addresses are configured by hand:
18/// it lists no IPv6_Auto_Addressing_Enable (Table 12-71 footnote 16) or
19/// IPv6_Zone_Index (footnote 17) row, nor the optional DHCPv6 rows, and
20/// every row is read-only over BACnet.
21///
22/// `vmac`, and the UDP port the multicast row carries, are placeholders
23/// until a registered owner publishes the VMAC it uses and the port it is
24/// bound to.
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct Bip6PortConfig {
27    /// Caller-configured number; zero means unknown, 65535 is invalid.
28    pub network_number: u16,
29    /// Port APDU_Length, independent of Device Max_APDU_Length_Accepted;
30    /// at least 50.
31    pub apdu_length: u32,
32    /// Configured IPv6 address, most significant octet first: IPv6_Address.
33    pub ip_address: [u8; 16],
34    /// The subnet prefix length of `ip_address`, 1 to 128:
35    /// IPv6_Prefix_Length.
36    pub prefix_length: u8,
37    /// BACnet_IPv6_UDP_Port. Zero is allowed in this unbound configuration.
38    pub udp_port: u16,
39    /// Configured gateway, with no assumed OS route: IPv6_Default_Gateway.
40    pub default_gateway: [u8; 16],
41    /// At least one address; `::` represents unavailable DNS:
42    /// IPv6_DNS_Server.
43    pub dns_servers: Vec<[u8; 16]>,
44    /// The multicast group the port broadcasts to. BACnet_IPv6_Multicast_Address
45    /// serves it followed by the port's UDP port, since the transport sends
46    /// its broadcasts to the group at its own port.
47    pub multicast_address: [u8; 16],
48    /// The port's 3-octet VMAC (Annex U.1.3): MAC_Address. A registered
49    /// owner publishes the VMAC it actually uses, which replaces this one.
50    pub vmac: [u8; 3],
51}
52
53impl Default for Bip6PortConfig {
54    fn default() -> Self {
55        Self {
56            network_number: 0,
57            // Declared B/IPv6 capacity of this library's transport profile.
58            apdu_length: 1476,
59            ip_address: [0; 16],
60            prefix_length: 64,
61            udp_port: 47808,
62            default_gateway: [0; 16],
63            dns_servers: vec![[0; 16]],
64            multicast_address: SITE_LOCAL_GROUP,
65            vmac: [0; 3],
66        }
67    }
68}
69
70impl Bip6PortConfig {
71    pub(super) fn validate(&self, instance: u32) -> Result<(), Error> {
72        // The flat application profile's local Port ID policy, as for B/IP;
73        // a prefix length is 1 to 128 (Clause 12.56.41); a broadcast group
74        // is an IPv6 multicast address (Annex U.4); an IPv4-mapped address
75        // is an IPv4 port, which `new_bip` describes.
76        if !(1..=255).contains(&instance)
77            || std::net::Ipv6Addr::from(self.ip_address)
78                .to_ipv4_mapped()
79                .is_some()
80            || self.network_number == u16::MAX
81            || self.apdu_length < 50
82            || self.dns_servers.is_empty()
83            || !(1..=128).contains(&self.prefix_length)
84            || self.multicast_address[0] != 0xFF
85        {
86            return Err(common::value_out_of_range_error());
87        }
88        Ok(())
89    }
90
91    /// BACnet_IPv6_Multicast_Address: the group, then the UDP port, each
92    /// most significant octet first (Clause 12.56.44).
93    pub(super) fn multicast_with_port(&self) -> Vec<u8> {
94        let mut value = self.multicast_address.to_vec();
95        value.extend_from_slice(&self.udp_port.to_be_bytes());
96        value
97    }
98}
99
100/// What a started B/IPv6 owner publishes for its registered Network Port:
101/// the address and UDP port it is bound to, the VMAC it uses and the group
102/// it broadcasts to.
103#[derive(Clone, Copy, Debug, PartialEq, Eq)]
104pub(crate) struct Bip6Bind {
105    /// The bound IPv6 address, most significant octet first.
106    pub ip: [u8; 16],
107    /// The bound UDP port, never zero.
108    pub udp: u16,
109    /// The VMAC the owner uses (Annex U.1.3).
110    pub vmac: [u8; 3],
111    /// The multicast group its broadcasts go to.
112    pub multicast: [u8; 16],
113}