1use super::*;
5use crate::network_port::{
6 Bip6Bind, Bip6PortConfig, BipPortConfig, NetworkPortObject, PortAddress, PortBind,
7};
8use alloc::sync::Weak;
9use bacnet_types::bip_port::BipPortMode;
10
11pub(super) struct NetworkPortRegistration {
12 oid: ObjectIdentifier,
13 lease: Weak<()>,
14 configured: PortAddress,
16 published: bool,
17}
18
19impl ObjectDatabase {
20 fn builtin_network_port_mut(
21 &mut self,
22 oid: &ObjectIdentifier,
23 ) -> Option<&mut NetworkPortObject> {
24 self.objects
26 .get_mut(oid)?
27 .as_mut()
28 .as_stored_any_mut(crate::traits::ObjectStorageAccess(()))
29 .downcast_mut::<NetworkPortObject>()
30 .filter(|port| port.object_identifier() == *oid)
31 }
32
33 #[doc(hidden)]
35 pub fn configured_bip_port_internal(
36 &mut self,
37 oid: &ObjectIdentifier,
38 ) -> Option<BipPortConfig> {
39 self.builtin_network_port_mut(oid)?
40 .configuration_internal()
41 .cloned()
42 }
43
44 #[doc(hidden)]
46 pub fn configured_bip6_port_internal(
47 &mut self,
48 oid: &ObjectIdentifier,
49 ) -> Option<Bip6PortConfig> {
50 self.builtin_network_port_mut(oid)?
51 .bip6_configuration_internal()
52 .cloned()
53 }
54
55 #[doc(hidden)]
59 pub fn reserve_bip_port_internal(
60 &mut self,
61 oid: ObjectIdentifier,
62 ip: [u8; 4],
63 udp: u16,
64 ) -> Result<(BipPortConfig, Arc<()>), Error> {
65 let lease = self.reserve_port(oid, PortAddress::V4(ip, udp))?;
66 let configured = self
67 .configured_bip_port_internal(&oid)
68 .expect("reserved B/IP port");
69 Ok((configured, lease))
70 }
71
72 #[doc(hidden)]
76 pub fn reserve_bip6_port_internal(
77 &mut self,
78 oid: ObjectIdentifier,
79 ip: [u8; 16],
80 udp: u16,
81 ) -> Result<(Bip6PortConfig, Arc<()>), Error> {
82 let lease = self.reserve_port(oid, PortAddress::V6(ip, udp))?;
83 let configured = self
84 .configured_bip6_port_internal(&oid)
85 .expect("reserved B/IPv6 port");
86 Ok((configured, lease))
87 }
88
89 fn reserve_port(
90 &mut self,
91 oid: ObjectIdentifier,
92 address: PortAddress,
93 ) -> Result<Arc<()>, Error> {
94 if oid.object_type() != ObjectType::NETWORK_PORT
95 || !(1..=255).contains(&oid.instance_number())
96 {
97 return Err(invalid("registered Network Port instance must be 1..255"));
98 }
99 if self
100 .network_port
101 .as_ref()
102 .is_some_and(|port| port.lease.strong_count() != 0)
103 {
104 return Err(invalid("database already has a live registered port owner"));
105 }
106 let authority = self
107 .builtin_network_port_mut(&oid)
108 .ok_or_else(|| invalid("registration requires the selected built-in Network Port"))?;
109 let configured = match authority.configured_address_internal() {
110 Some(configured) if configured == address => configured,
111 Some(configured) if configured.same_family(address) => {
112 return Err(invalid(
113 "Network Port configuration differs from transport interface/UDP",
114 ));
115 }
116 _ => {
117 return Err(invalid(match address {
118 PortAddress::V4(..) => "registration requires an IPV4 port",
119 PortAddress::V6(..) => "registration requires an IPV6 port",
120 }));
121 }
122 };
123 let lease = Arc::new(());
124 authority.reserve_internal(&lease)?;
125 self.network_port = Some(NetworkPortRegistration {
126 oid,
127 lease: Arc::downgrade(&lease),
128 configured,
129 published: false,
130 });
131 Ok(lease)
132 }
133
134 #[doc(hidden)]
138 pub fn publish_bip_port_internal(
139 &mut self,
140 oid: ObjectIdentifier,
141 ip: [u8; 4],
142 udp: u16,
143 capacity: u32,
144 mode: BipPortMode,
145 ) -> Result<(), Error> {
146 self.publish_port(oid, PortBind::V4(ip, udp), capacity, mode)
147 }
148
149 #[doc(hidden)]
154 #[allow(clippy::too_many_arguments)] pub fn publish_bip6_port_internal(
156 &mut self,
157 oid: ObjectIdentifier,
158 ip: [u8; 16],
159 udp: u16,
160 vmac: [u8; 3],
161 multicast: [u8; 16],
162 capacity: u32,
163 mode: BipPortMode,
164 ) -> Result<(), Error> {
165 let bind = Bip6Bind {
166 ip,
167 udp,
168 vmac,
169 multicast,
170 };
171 self.publish_port(oid, PortBind::V6(bind), capacity, mode)
172 }
173
174 fn publish_port(
175 &mut self,
176 oid: ObjectIdentifier,
177 bind: PortBind,
178 capacity: u32,
179 mode: BipPortMode,
180 ) -> Result<(), Error> {
181 let registration = self
182 .network_port
183 .as_ref()
184 .filter(|port| port.oid == oid)
185 .ok_or_else(|| invalid("missing Network Port reservation"))?;
186 let lease = registration
187 .lease
188 .upgrade()
189 .ok_or_else(|| invalid("Network Port owner expired"))?;
190 let actual = bind.address();
191 let configured = registration.configured;
192 if registration.published
193 || !configured.same_ip(actual)
194 || actual.udp() == 0
195 || (configured.udp() != 0 && configured.udp() != actual.udp())
196 {
197 return Err(invalid("post-bind Network Port identity mismatch"));
198 }
199 self.builtin_network_port_mut(&oid)
200 .ok_or_else(|| invalid("selected Network Port authority disappeared"))?
201 .reconcile_internal(&lease, bind, capacity, mode)?;
202 self.network_port
203 .as_mut()
204 .expect("validated registration")
205 .published = true;
206 Ok(())
207 }
208
209 #[doc(hidden)]
211 pub fn registered_port_internal(&self) -> Option<ObjectIdentifier> {
212 self.network_port
213 .as_ref()
214 .filter(|port| port.published && port.lease.strong_count() != 0)
215 .map(|port| port.oid)
216 }
217
218 #[doc(hidden)]
221 pub fn network_number_internal(
222 &mut self,
223 oid: ObjectIdentifier,
224 announcement: Option<(u16, u8)>,
225 ) -> Option<bacnet_types::network_number::NetworkNumber> {
226 if self.registered_port_internal() != Some(oid) {
227 return None;
228 }
229 Some(
230 self.builtin_network_port_mut(&oid)?
231 .network_number_internal(announcement),
232 )
233 }
234
235 #[doc(hidden)]
239 pub fn set_network_port_activation_internal(
240 &mut self,
241 oid: ObjectIdentifier,
242 activation: bool,
243 ) -> Result<(), Error> {
244 self.builtin_network_port_mut(&oid)
245 .ok_or_else(|| invalid("selected Network Port authority disappeared"))?
246 .set_activation_internal(activation);
247 Ok(())
248 }
249
250 #[doc(hidden)]
257 pub fn set_network_port_multicast_internal(
258 &mut self,
259 oid: ObjectIdentifier,
260 multicast: Option<alloc::sync::Arc<dyn bacnet_types::bip_port::IpMulticast>>,
261 ) -> Result<(), Error> {
262 self.builtin_network_port_mut(&oid)
263 .ok_or_else(|| invalid("selected Network Port authority disappeared"))?
264 .set_multicast_internal(multicast);
265 Ok(())
266 }
267
268 fn network_port_oids(&self) -> Vec<ObjectIdentifier> {
270 self.objects
271 .keys()
272 .filter(|oid| oid.object_type() == ObjectType::NETWORK_PORT)
273 .copied()
274 .collect()
275 }
276
277 pub fn check_network_port_changes(&mut self) -> Result<(), Error> {
281 for oid in self.network_port_oids() {
282 if let Some(port) = self.builtin_network_port_mut(&oid) {
283 port.check_pending_changes()?;
284 }
285 }
286 Ok(())
287 }
288
289 pub fn activate_network_port_changes(&mut self) -> Result<usize, Error> {
298 let ports = self.network_port_oids();
299 let mut activated = 0;
300 let mut first_error = None;
301 for oid in ports {
302 let Some(port) = self.builtin_network_port_mut(&oid) else {
303 continue;
304 };
305 match port.activate_changes() {
306 Ok(true) => activated += 1,
307 Ok(false) => {}
308 Err(error) => {
309 first_error.get_or_insert(error);
310 }
311 }
312 }
313 first_error.map_or(Ok(activated), Err)
314 }
315
316 pub(super) fn check_network_port_membership(
317 &self,
318 oid: &ObjectIdentifier,
319 ) -> Result<(), Error> {
320 if self
321 .network_port
322 .as_ref()
323 .is_some_and(|port| port.oid == *oid && port.lease.strong_count() != 0)
324 {
325 return Err(Error::protocol(
326 ErrorClass::OBJECT,
327 ErrorCode::OBJECT_DELETION_NOT_PERMITTED,
328 ));
329 }
330 Ok(())
331 }
332}
333fn invalid(message: &str) -> Error {
334 Error::Encoding(message.into())
335}