bacnet_network/
response_route.rs1use crate::layer::ReceivedApdu;
3use bacnet_encoding::npdu::{encode_npdu, Npdu, NpduAddress};
4use bacnet_transport::port::{DirectResponse, TransportProvenance};
5use bacnet_types::{enums::NetworkPriority, error::Error};
6use bytes::{Bytes, BytesMut};
7
8#[derive(Clone, Debug)]
14pub struct ResponseRoute {
15 provenance: TransportProvenance,
16 direct: Option<DirectResponse>,
17}
18
19impl ResponseRoute {
20 pub fn new(provenance: TransportProvenance, direct: Option<DirectResponse>) -> Self {
23 Self { provenance, direct }
24 }
25
26 pub fn unverified() -> Self {
28 Self::new(TransportProvenance::unverified(), None)
29 }
30
31 pub fn provenance(&self) -> TransportProvenance {
33 self.provenance
34 }
35
36 pub fn max_apdu_length(
41 &self,
42 apdu_limit: u16,
43 destination: Option<&NpduAddress>,
44 ) -> Result<u16, Error> {
45 let Some(direct) = self.direct()? else {
46 return Ok(apdu_limit);
47 };
48 let header = encode_response_npdu(&[], destination, false, NetworkPriority::NORMAL)?;
49 let available = direct.max_npdu_length().saturating_sub(header.len());
50 Ok(usize::from(apdu_limit).min(available) as u16)
51 }
52
53 pub(crate) fn direct(&self) -> Result<Option<&DirectResponse>, bacnet_types::error::Error> {
54 match (self.provenance.direct_sc_identity(), self.direct.as_ref()) {
55 (Some(identity), Some(route)) if identity == route.identity() => Ok(Some(route)),
56 (None, None) => Ok(None),
57 _ => Err(bacnet_types::error::Error::Transport(std::io::Error::new(
58 std::io::ErrorKind::PermissionDenied,
59 "missing or mismatched original direct response capability",
60 ))),
61 }
62 }
63}
64
65impl ReceivedApdu {
66 pub fn response_route(&self) -> ResponseRoute {
68 ResponseRoute::new(self.provenance, self.direct_response.clone())
69 }
70}
71
72pub(crate) fn encode_response_npdu(
74 apdu: &[u8],
75 destination: Option<&NpduAddress>,
76 expecting_reply: bool,
77 priority: NetworkPriority,
78) -> Result<BytesMut, Error> {
79 check_response_destination(destination)?;
80 encode_checked_response_npdu(apdu, destination, expecting_reply, priority)
81}
82
83pub(crate) fn check_response_destination(destination: Option<&NpduAddress>) -> Result<(), Error> {
85 match destination {
86 Some(destination) => crate::layer::check_destination(
87 destination.network,
88 "pass no destination (no DNET) for a local peer",
89 ),
90 None => Ok(()),
91 }
92}
93
94pub(crate) fn encode_checked_response_npdu(
96 apdu: &[u8],
97 destination: Option<&NpduAddress>,
98 expecting_reply: bool,
99 priority: NetworkPriority,
100) -> Result<BytesMut, Error> {
101 let npdu = Npdu {
102 destination: destination.cloned(),
103 expecting_reply,
104 priority,
105 payload: Bytes::copy_from_slice(apdu),
106 ..Npdu::default()
107 };
108 let mut encoded = BytesMut::new();
109 encode_npdu(&mut encoded, &npdu)?;
110 Ok(encoded)
111}