bacnet_parse/
bvlc.rs

1use super::npdu::*;
2use super::Error;
3use arrayref::array_ref;
4
5pub fn parse_bvlc(slice: &[u8]) -> Result<BVLC, Error> {
6    if slice.len() < 4 {
7        return Err(Error::Length("insufficient size for bvlc"));
8    }
9    if slice[0] != 0x81 {
10        return Err(Error::InvalidValue("invalid bvlc type"));
11    }
12
13    let len = u16::from_be_bytes(*array_ref!(slice, 2, 2));
14    let len = len as usize;
15    if len > slice.len() {
16        return Err(Error::Length("bvlc length too largu"));
17    }
18
19    let mut bvlc = BVLC::default();
20    bvlc.bfn = slice[1].into();
21    let npdu_start_idx: usize = if bvlc.has_ip_port() {
22        if slice.len() < 6 {
23            return Err(Error::Length("insufficient size for bvlc ip/port"));
24        }
25        bvlc.ip_port = Some(array_ref!(slice, 4, 6).into());
26        10
27    } else {
28        4
29    };
30    if bvlc.has_npdu() {
31        if slice.len() < npdu_start_idx || len < npdu_start_idx {
32            return Err(Error::Length("insufficient size for npdu"));
33        }
34        if let Ok(npdu) = parse_npdu(&slice[npdu_start_idx..len]) {
35            bvlc.npdu = Some(npdu);
36        }
37    }
38    Ok(bvlc)
39}
40
41#[derive(Default)]
42pub struct BVLC<'a> {
43    bfn: BVLCFunction,
44    ip_port: Option<IpPort>,
45    npdu: Option<NPDU<'a>>,
46}
47
48impl<'a> BVLC<'a> {
49    pub fn bvlc_function(&self) -> BVLCFunction {
50        self.bfn
51    }
52    pub fn ip_port(&self) -> &Option<IpPort> {
53        &self.ip_port
54    }
55    pub fn npdu(&self) -> &Option<NPDU<'a>> {
56        &self.npdu
57    }
58    pub fn has_npdu(&self) -> bool {
59        match &self.bfn {
60            BVLCFunction::ForwardedNPDU
61            | BVLCFunction::UnicastNPDU
62            | BVLCFunction::BroadcastNPDU => true,
63            _ => false,
64        }
65    }
66    pub fn has_ip_port(&self) -> bool {
67        match &self.bfn {
68            BVLCFunction::ForwardedNPDU => true,
69            _ => false,
70        }
71    }
72}
73
74#[derive(Clone, Copy, Debug, PartialEq)]
75pub enum BVLCFunction {
76    BVLCResult,
77    WBDT,
78    RBDT,
79    RBDTAck,
80    ForwardedNPDU,
81    RegisterForeignDevice,
82    UnicastNPDU,
83    BroadcastNPDU,
84    SecureBVLL,
85    Unknown,
86}
87
88impl Default for BVLCFunction {
89    fn default() -> BVLCFunction {
90        Self::Unknown
91    }
92}
93
94impl From<u8> for BVLCFunction {
95    fn from(b: u8) -> Self {
96        match b {
97            0x00 => Self::BVLCResult,
98            0x01 => Self::WBDT,
99            0x02 => Self::RBDT,
100            0x03 => Self::RBDTAck,
101            0x04 => Self::ForwardedNPDU,
102            0x05 => Self::RegisterForeignDevice,
103            0x0a => Self::UnicastNPDU,
104            0x0b => Self::BroadcastNPDU,
105            0x0c => Self::SecureBVLL,
106            _ => Self::Unknown,
107        }
108    }
109}
110
111pub struct IpPort {
112    pub ip: u32,
113    pub port: u16,
114}
115
116impl From<&[u8; 6]> for IpPort {
117    fn from(b: &[u8; 6]) -> IpPort {
118        IpPort {
119            ip: u32::from_be_bytes(*array_ref!(b, 0, 4)),
120            port: u16::from_be_bytes(*array_ref!(b, 4, 2)),
121        }
122    }
123}