1#[cfg(not(feature = "std"))]
30use alloc::vec::Vec;
31
32use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
33
34use bacnet_types::constructed::{
35 BACnetBDTEntry, BACnetFDTEntry, BACnetHostAddress, BACnetHostNPort,
36};
37use bacnet_types::error::Error;
38use bytes::BytesMut;
39
40use super::tagged::{
41 contents, decode_ctx_character_string, decode_ctx_fixed, decode_ctx_unsigned,
42 decode_optional_ctx, expect_closing, expect_opening, misplaced_tag,
43};
44use super::MAX_FRAMED_ITEMS;
45use crate::primitives;
46use crate::tags::{self, TagClass};
47
48pub fn encode_host_address(buf: &mut BytesMut, host: &BACnetHostAddress) -> Result<(), Error> {
53 match host {
54 BACnetHostAddress::None => tags::encode_tag(buf, 0, TagClass::Context, 0),
55 BACnetHostAddress::Ip(IpAddr::V4(ip)) => {
56 primitives::encode_ctx_octet_string(buf, 1, &ip.octets())
57 }
58 BACnetHostAddress::Ip(IpAddr::V6(ip)) => {
59 primitives::encode_ctx_octet_string(buf, 1, &ip.octets())
60 }
61 BACnetHostAddress::Name(name) => {
62 let mut encoded = BytesMut::new();
63 primitives::encode_ctx_character_string(&mut encoded, 2, name)?;
64 buf.extend_from_slice(&encoded);
65 }
66 }
67 Ok(())
68}
69
70pub fn decode_host_address(
77 data: &[u8],
78 offset: usize,
79) -> Result<(BACnetHostAddress, usize), Error> {
80 let what = "BACnetHostAddress";
81 let (tag, start) = tags::decode_tag(data, offset)?;
82 if tag.is_context(0) {
83 if tag.length != 0 {
84 return Err(Error::decoding(
85 offset,
86 format!("{what} none [0]: NULL has {} contents octets", tag.length),
87 ));
88 }
89 return Ok((BACnetHostAddress::None, start));
90 }
91 if tag.is_context(1) {
92 let (octets, end) = contents(data, start, tag.length)?;
93 let ip = match *octets {
94 [a, b, c, d] => IpAddr::V4(Ipv4Addr::new(a, b, c, d)),
95 _ => match <[u8; 16]>::try_from(octets) {
96 Ok(v6) => IpAddr::V6(Ipv6Addr::from(v6)),
97 Err(_) => {
98 return Err(Error::decoding(
99 offset,
100 format!(
101 "{what} ip-address [1]: {} octets, expected 4 or 16",
102 octets.len()
103 ),
104 ))
105 }
106 },
107 };
108 return Ok((BACnetHostAddress::Ip(ip), end));
109 }
110 if tag.is_context(2) {
111 let (name, end) = decode_ctx_character_string(data, offset, 2, what)?;
112 return Ok((BACnetHostAddress::Name(name), end));
113 }
114 Err(misplaced_tag(
115 data,
116 &tag,
117 None,
118 offset,
119 format!("{what}: expected none [0], ip-address [1] or name [2]"),
120 ))
121}
122
123pub fn encode_host_n_port(buf: &mut BytesMut, value: &BACnetHostNPort) -> Result<(), Error> {
128 let mut encoded = BytesMut::new();
129 tags::encode_opening_tag(&mut encoded, 0);
130 encode_host_address(&mut encoded, &value.host)?;
131 tags::encode_closing_tag(&mut encoded, 0);
132 primitives::encode_ctx_unsigned(&mut encoded, 1, value.port.into());
133 buf.extend_from_slice(&encoded);
134 Ok(())
135}
136
137pub fn decode_host_n_port(data: &[u8], offset: usize) -> Result<(BACnetHostNPort, usize), Error> {
140 let what = "BACnetHostNPort";
141 let pos = expect_opening(data, offset, 0, what)?;
142 let (host, pos) = decode_host_address(data, pos)?;
143 let pos = expect_closing(data, pos, 0, what)?;
144 let (port, pos) = decode_ctx_unsigned::<u16>(data, pos, 1, what)?;
145 Ok((BACnetHostNPort { host, port }, pos))
146}
147
148pub fn encode_bdt_entry(buf: &mut BytesMut, entry: &BACnetBDTEntry) -> Result<(), Error> {
153 let mut encoded = BytesMut::new();
154 tags::encode_opening_tag(&mut encoded, 0);
155 encode_host_n_port(&mut encoded, &entry.bbmd_address)?;
156 tags::encode_closing_tag(&mut encoded, 0);
157 if let Some(mask) = &entry.broadcast_mask {
158 primitives::encode_ctx_octet_string(&mut encoded, 1, mask);
159 }
160 buf.extend_from_slice(&encoded);
161 Ok(())
162}
163
164pub fn decode_bdt_entry(data: &[u8], offset: usize) -> Result<(BACnetBDTEntry, usize), Error> {
167 let what = "BACnetBDTEntry";
168 let pos = expect_opening(data, offset, 0, what)?;
169 let (bbmd_address, pos) = decode_host_n_port(data, pos)?;
170 let pos = expect_closing(data, pos, 0, what)?;
171 let (mask, pos) = decode_optional_ctx(data, pos, 1, what, |data, at, tag, what| {
172 decode_ctx_fixed(data, at, tag, 4, "broadcast mask", what)
173 })?;
174 let broadcast_mask = mask.map(|octets| [octets[0], octets[1], octets[2], octets[3]]);
175 Ok((
176 BACnetBDTEntry {
177 bbmd_address,
178 broadcast_mask,
179 },
180 pos,
181 ))
182}
183
184pub fn encode_fdt_entry(buf: &mut BytesMut, entry: &BACnetFDTEntry) {
186 let mut address = [0u8; 18];
187 let len = match entry.address {
188 SocketAddr::V4(v4) => {
189 address[..4].copy_from_slice(&v4.ip().octets());
190 address[4..6].copy_from_slice(&v4.port().to_be_bytes());
191 6
192 }
193 SocketAddr::V6(v6) => {
194 address[..16].copy_from_slice(&v6.ip().octets());
195 address[16..].copy_from_slice(&v6.port().to_be_bytes());
196 18
197 }
198 };
199 primitives::encode_ctx_octet_string(buf, 0, &address[..len]);
200 primitives::encode_ctx_unsigned(buf, 1, entry.time_to_live.into());
201 primitives::encode_ctx_unsigned(buf, 2, entry.remaining_time_to_live.into());
202}
203
204pub fn decode_fdt_entry(data: &[u8], offset: usize) -> Result<(BACnetFDTEntry, usize), Error> {
207 let what = "BACnetFDTEntry";
208 let (tag, start) = tags::decode_tag(data, offset)?;
209 if !tag.is_context(0) {
210 return Err(misplaced_tag(
211 data,
212 &tag,
213 Some(0),
214 offset,
215 format!("{what}: expected bacnetip-address [0]"),
216 ));
217 }
218 let (octets, pos) = contents(data, start, tag.length)?;
219 let address = match octets.len() {
220 6 => SocketAddr::V4(SocketAddrV4::new(
221 Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]),
222 u16::from_be_bytes([octets[4], octets[5]]),
223 )),
224 18 => {
225 let mut ip = [0u8; 16];
226 ip.copy_from_slice(&octets[..16]);
227 SocketAddr::V6(SocketAddrV6::new(
228 Ipv6Addr::from(ip),
229 u16::from_be_bytes([octets[16], octets[17]]),
230 0,
231 0,
232 ))
233 }
234 other => {
235 return Err(Error::decoding(
236 offset,
237 format!("{what} bacnetip-address [0]: {other} octets, expected 6 or 18"),
238 ))
239 }
240 };
241 let (time_to_live, pos) = decode_ctx_unsigned::<u16>(data, pos, 1, what)?;
242 let (remaining_time_to_live, pos) = decode_ctx_unsigned::<u16>(data, pos, 2, what)?;
243 Ok((
244 BACnetFDTEntry {
245 address,
246 time_to_live,
247 remaining_time_to_live,
248 },
249 pos,
250 ))
251}
252
253pub fn encode_bdt_entry_list(buf: &mut BytesMut, entries: &[BACnetBDTEntry]) -> Result<(), Error> {
257 let mut encoded = BytesMut::new();
258 for entry in entries {
259 encode_bdt_entry(&mut encoded, entry)?;
260 }
261 buf.extend_from_slice(&encoded);
262 Ok(())
263}
264
265pub fn encode_fdt_entry_list(buf: &mut BytesMut, entries: &[BACnetFDTEntry]) {
267 for entry in entries {
268 encode_fdt_entry(buf, entry);
269 }
270}
271
272pub fn decode_bdt_entry_list(data: &[u8]) -> Result<Vec<BACnetBDTEntry>, Error> {
275 decode_list(data, "BACnetBDTEntry list", decode_bdt_entry)
276}
277
278pub fn decode_fdt_entry_list(data: &[u8]) -> Result<Vec<BACnetFDTEntry>, Error> {
281 decode_list(data, "BACnetFDTEntry list", decode_fdt_entry)
282}
283
284fn decode_list<T>(
285 data: &[u8],
286 what: &str,
287 decode: impl Fn(&[u8], usize) -> Result<(T, usize), Error>,
288) -> Result<Vec<T>, Error> {
289 let mut values = Vec::new();
290 let mut offset = 0;
291 while offset < data.len() {
292 if values.len() == MAX_FRAMED_ITEMS {
293 return Err(Error::decoding(
294 offset,
295 format!("{what}: more than {MAX_FRAMED_ITEMS} entries"),
296 ));
297 }
298 let (value, end) = decode(data, offset)?;
299 values.push(value);
300 offset = end;
301 }
302 Ok(values)
303}