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::{DecodeError, DecodingKind, 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, Fixed,
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(DecodeError::new(
85 DecodingKind::InvalidEncoding,
86 offset,
87 "none [0]: NULL has {} contents octets",
88 )
89 .within(what)
90 .with_value(tag.length.into())
91 .into());
92 }
93 return Ok((BACnetHostAddress::None, start));
94 }
95 if tag.is_context(1) {
96 let (octets, end) = contents(data, start, tag.length)?;
97 let ip = match *octets {
98 [a, b, c, d] => IpAddr::V4(Ipv4Addr::new(a, b, c, d)),
99 _ => match <[u8; 16]>::try_from(octets) {
100 Ok(v6) => IpAddr::V6(Ipv6Addr::from(v6)),
101 Err(_) => {
102 return Err(DecodeError::new(
103 DecodingKind::InvalidEncoding,
104 offset,
105 "ip-address [1]: {} octets, expected 4 or 16",
106 )
107 .within(what)
108 .with_value(octets.len() as u64)
109 .into())
110 }
111 },
112 };
113 return Ok((BACnetHostAddress::Ip(ip), end));
114 }
115 if tag.is_context(2) {
116 let (name, end) = decode_ctx_character_string(data, offset, 2, what)?;
117 return Ok((BACnetHostAddress::Name(name), end));
118 }
119 Err(misplaced(
120 data,
121 &tag,
122 None,
123 offset,
124 "expected none [0], ip-address [1] or name [2]",
125 )
126 .within(what)
127 .into())
128}
129
130pub fn encode_host_n_port(buf: &mut BytesMut, value: &BACnetHostNPort) -> Result<(), Error> {
135 let mut encoded = BytesMut::new();
136 tags::encode_opening_tag(&mut encoded, 0);
137 encode_host_address(&mut encoded, &value.host)?;
138 tags::encode_closing_tag(&mut encoded, 0);
139 primitives::encode_ctx_unsigned(&mut encoded, 1, value.port.into());
140 buf.extend_from_slice(&encoded);
141 Ok(())
142}
143
144pub fn decode_host_n_port(data: &[u8], offset: usize) -> Result<(BACnetHostNPort, usize), Error> {
147 let what = "BACnetHostNPort";
148 let pos = expect_opening(data, offset, 0, what)?;
149 let (host, pos) = decode_host_address(data, pos)?;
150 let pos = expect_closing(data, pos, 0, what)?;
151 let (port, pos) = decode_ctx_unsigned::<u16>(data, pos, 1, what)?;
152 Ok((BACnetHostNPort { host, port }, pos))
153}
154
155pub fn encode_bdt_entry(buf: &mut BytesMut, entry: &BACnetBDTEntry) -> Result<(), Error> {
160 let mut encoded = BytesMut::new();
161 tags::encode_opening_tag(&mut encoded, 0);
162 encode_host_n_port(&mut encoded, &entry.bbmd_address)?;
163 tags::encode_closing_tag(&mut encoded, 0);
164 if let Some(mask) = &entry.broadcast_mask {
165 primitives::encode_ctx_octet_string(&mut encoded, 1, mask);
166 }
167 buf.extend_from_slice(&encoded);
168 Ok(())
169}
170
171pub fn decode_bdt_entry(data: &[u8], offset: usize) -> Result<(BACnetBDTEntry, usize), Error> {
174 let what = "BACnetBDTEntry";
175 let pos = expect_opening(data, offset, 0, what)?;
176 let (bbmd_address, pos) = decode_host_n_port(data, pos)?;
177 let pos = expect_closing(data, pos, 0, what)?;
178 const MASK: Fixed = Fixed {
179 octets: 4,
180 misplaced: "expected context tag [{}] broadcast mask",
181 wrong_length: "[{}] broadcast mask has {} contents octets, expected 4",
182 };
183 let (mask, pos) = decode_optional_ctx(data, pos, 1, what, |data, at, tag, what| {
184 decode_ctx_fixed(data, at, tag, MASK, what)
185 })?;
186 let broadcast_mask = mask.map(|octets| [octets[0], octets[1], octets[2], octets[3]]);
187 Ok((
188 BACnetBDTEntry {
189 bbmd_address,
190 broadcast_mask,
191 },
192 pos,
193 ))
194}
195
196pub fn encode_fdt_entry(buf: &mut BytesMut, entry: &BACnetFDTEntry) {
198 let mut address = [0u8; 18];
199 let len = match entry.address {
200 SocketAddr::V4(v4) => {
201 address[..4].copy_from_slice(&v4.ip().octets());
202 address[4..6].copy_from_slice(&v4.port().to_be_bytes());
203 6
204 }
205 SocketAddr::V6(v6) => {
206 address[..16].copy_from_slice(&v6.ip().octets());
207 address[16..].copy_from_slice(&v6.port().to_be_bytes());
208 18
209 }
210 };
211 primitives::encode_ctx_octet_string(buf, 0, &address[..len]);
212 primitives::encode_ctx_unsigned(buf, 1, entry.time_to_live.into());
213 primitives::encode_ctx_unsigned(buf, 2, entry.remaining_time_to_live.into());
214}
215
216pub fn decode_fdt_entry(data: &[u8], offset: usize) -> Result<(BACnetFDTEntry, usize), Error> {
219 let what = "BACnetFDTEntry";
220 let (tag, start) = tags::decode_tag(data, offset)?;
221 if !tag.is_context(0) {
222 return Err(
223 misplaced(data, &tag, Some(0), offset, "expected bacnetip-address [0]")
224 .within(what)
225 .into(),
226 );
227 }
228 let (octets, pos) = contents(data, start, tag.length)?;
229 let address = match octets.len() {
230 6 => SocketAddr::V4(SocketAddrV4::new(
231 Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]),
232 u16::from_be_bytes([octets[4], octets[5]]),
233 )),
234 18 => {
235 let mut ip = [0u8; 16];
236 ip.copy_from_slice(&octets[..16]);
237 SocketAddr::V6(SocketAddrV6::new(
238 Ipv6Addr::from(ip),
239 u16::from_be_bytes([octets[16], octets[17]]),
240 0,
241 0,
242 ))
243 }
244 other => {
245 return Err(DecodeError::new(
246 DecodingKind::InvalidEncoding,
247 offset,
248 "bacnetip-address [0]: {} octets, expected 6 or 18",
249 )
250 .within(what)
251 .with_value(other as u64)
252 .into())
253 }
254 };
255 let (time_to_live, pos) = decode_ctx_unsigned::<u16>(data, pos, 1, what)?;
256 let (remaining_time_to_live, pos) = decode_ctx_unsigned::<u16>(data, pos, 2, what)?;
257 Ok((
258 BACnetFDTEntry {
259 address,
260 time_to_live,
261 remaining_time_to_live,
262 },
263 pos,
264 ))
265}
266
267pub fn encode_bdt_entry_list(buf: &mut BytesMut, entries: &[BACnetBDTEntry]) -> Result<(), Error> {
271 let mut encoded = BytesMut::new();
272 for entry in entries {
273 encode_bdt_entry(&mut encoded, entry)?;
274 }
275 buf.extend_from_slice(&encoded);
276 Ok(())
277}
278
279pub fn encode_fdt_entry_list(buf: &mut BytesMut, entries: &[BACnetFDTEntry]) {
281 for entry in entries {
282 encode_fdt_entry(buf, entry);
283 }
284}
285
286pub fn decode_bdt_entry_list(data: &[u8]) -> Result<Vec<BACnetBDTEntry>, Error> {
289 decode_list(data, "BACnetBDTEntry list", decode_bdt_entry)
290}
291
292pub fn decode_fdt_entry_list(data: &[u8]) -> Result<Vec<BACnetFDTEntry>, Error> {
295 decode_list(data, "BACnetFDTEntry list", decode_fdt_entry)
296}
297
298fn decode_list<T>(
299 data: &[u8],
300 what: &'static str,
301 decode: impl Fn(&[u8], usize) -> Result<(T, usize), Error>,
302) -> Result<Vec<T>, Error> {
303 let mut values = Vec::new();
304 let mut offset = 0;
305 while offset < data.len() {
306 if values.len() == MAX_FRAMED_ITEMS {
307 return Err(DecodeError::new(
308 DecodingKind::InvalidEncoding,
309 offset,
310 "more than {} entries",
311 )
312 .within(what)
313 .with_value(MAX_FRAMED_ITEMS as u64)
314 .into());
315 }
316 let (value, end) = decode(data, offset)?;
317 values.push(value);
318 offset = end;
319 }
320 Ok(values)
321}