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