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}