embedded_bacnet/network_protocol/
network_pdu.rs

1use crate::{
2    application_protocol::application_pdu::ApplicationPdu,
3    common::{
4        error::Error,
5        io::{Reader, Writer},
6    },
7};
8
9// Network Layer Protocol Data Unit
10#[derive(Debug, Clone)]
11#[cfg_attr(feature = "defmt", derive(defmt::Format))]
12pub struct NetworkPdu<'a> {
13    pub src: Option<SourceAddress>,
14    pub dst: Option<DestinationAddress>,
15    pub expect_reply: bool,
16    pub message_priority: MessagePriority,
17    pub network_message: NetworkMessage<'a>,
18}
19
20// NOTE: this is actually a control flag
21#[derive(Debug, Clone)]
22#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23#[repr(u8)]
24pub enum MessagePriority {
25    Normal = 0,
26    Urgent = 1,
27    CriticalEquipment = 2,
28    LifeSafety = 3,
29}
30
31impl From<u8> for MessagePriority {
32    fn from(value: u8) -> Self {
33        const MASK: u8 = 0b0000_0011;
34        let value = value & MASK;
35
36        match value {
37            0 => MessagePriority::Normal,
38            1 => MessagePriority::Urgent,
39            2 => MessagePriority::CriticalEquipment,
40            3 => MessagePriority::LifeSafety,
41            _ => unreachable!(), // because of mask
42        }
43    }
44}
45
46#[derive(Debug, Clone)]
47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48#[repr(u8)]
49enum ControlFlags {
50    NetworkLayerMessage = 1 << 7,
51    HasDestination = 1 << 5,
52    HasSource = 1 << 3,
53    ExpectingReply = 1 << 2,
54}
55
56#[derive(Debug, Clone)]
57#[cfg_attr(feature = "defmt", derive(defmt::Format))]
58pub enum NetworkMessage<'a> {
59    Apdu(ApplicationPdu<'a>),
60    MessageType(MessageType),
61    CustomMessageType(u8),
62}
63
64// Network Layer Message Type
65#[derive(Debug, Clone)]
66#[cfg_attr(feature = "defmt", derive(defmt::Format))]
67#[repr(u8)]
68pub enum MessageType {
69    WhoIsRouterToNetwork = 0,
70    IAmRouterToNetwork = 1,
71    ICouldBeRouterToNetwork = 2,
72    RejectMessageToNetwork = 3,
73    RouterBusyToNetwork = 4,
74    RouterAvailableToNetwork = 5,
75    InitRtTable = 6,
76    InitRtTableAck = 7,
77    EstablishConnectionToNetwork = 8,
78    DisconnectConnectionToNetwork = 9,
79    ChallengeRequest = 10,
80    SecurityPayload = 11,
81    SecurityResponse = 12,
82    RequestKeyUpdate = 13,
83    UpdateKeySet = 14,
84    UpdateDistributionKey = 15,
85    RequestMasterKey = 16,
86    SetMasterKey = 17,
87    WhatIsNetworkNumber = 18,
88    NetworkNumberIs = 19,
89    // X'14' to X'7F': Reserved for use by ASHRAE
90    // X'80' to X'FF': Available for vendor proprietary messages
91}
92
93impl TryFrom<u8> for MessageType {
94    type Error = u8;
95
96    fn try_from(value: u8) -> Result<Self, Self::Error> {
97        match value {
98            0 => Ok(Self::WhoIsRouterToNetwork),
99            1 => Ok(Self::IAmRouterToNetwork),
100            2 => Ok(Self::ICouldBeRouterToNetwork),
101            3 => Ok(Self::RejectMessageToNetwork),
102            4 => Ok(Self::RouterBusyToNetwork),
103            5 => Ok(Self::RouterAvailableToNetwork),
104            6 => Ok(Self::InitRtTable),
105            7 => Ok(Self::InitRtTableAck),
106            8 => Ok(Self::EstablishConnectionToNetwork),
107            9 => Ok(Self::DisconnectConnectionToNetwork),
108            10 => Ok(Self::ChallengeRequest),
109            11 => Ok(Self::SecurityPayload),
110            12 => Ok(Self::SecurityResponse),
111            13 => Ok(Self::RequestKeyUpdate),
112            14 => Ok(Self::UpdateKeySet),
113            15 => Ok(Self::UpdateDistributionKey),
114            16 => Ok(Self::RequestMasterKey),
115            17 => Ok(Self::SetMasterKey),
116            18 => Ok(Self::WhatIsNetworkNumber),
117            19 => Ok(Self::NetworkNumberIs),
118            _ => Err(value),
119        }
120    }
121}
122
123impl<'a> NetworkPdu<'a> {
124    const VERSION: u8 = 0x01; // ASHRAE 135-1995
125    pub fn new(
126        src: Option<SourceAddress>,
127        dst: Option<DestinationAddress>,
128        expect_reply: bool,
129        message_priority: MessagePriority,
130        message: NetworkMessage<'a>,
131    ) -> Self {
132        Self {
133            src,
134            dst,
135            expect_reply,
136            message_priority,
137            network_message: message,
138        }
139    }
140
141    pub fn encode(&self, writer: &mut Writer) {
142        writer.push(Self::VERSION);
143        writer.push(self.calculate_control());
144
145        if let Some(dst) = self.dst.as_ref() {
146            dst.network_address.encode(writer);
147        }
148
149        if let Some(src) = self.src.as_ref() {
150            src.encode(writer);
151        }
152
153        // hop count comes after src
154        if let Some(dst) = self.dst.as_ref() {
155            writer.push(dst.hop_count);
156        }
157
158        match &self.network_message {
159            NetworkMessage::Apdu(adpu) => adpu.encode(writer),
160            NetworkMessage::MessageType(message_type) => {
161                writer.push(message_type.clone() as u8);
162            }
163            NetworkMessage::CustomMessageType(message_type) => {
164                writer.push(*message_type);
165            }
166        };
167    }
168
169    fn calculate_control(&self) -> u8 {
170        let is_network_layer_message = match &self.network_message {
171            NetworkMessage::Apdu(_) => 0,
172            NetworkMessage::MessageType(_) => ControlFlags::NetworkLayerMessage as u8,
173            NetworkMessage::CustomMessageType(_) => ControlFlags::NetworkLayerMessage as u8,
174        };
175
176        let has_destination = match self.dst.as_ref() {
177            Some(dst) => {
178                if dst.network_address.net > 0 {
179                    ControlFlags::HasDestination as u8
180                } else {
181                    0
182                }
183            }
184            None => 0,
185        };
186
187        let has_source = match self.src.as_ref() {
188            Some(src) => {
189                if src.net > 0 && src.net != 0xFFFF {
190                    ControlFlags::HasSource as u8
191                } else {
192                    0
193                }
194            }
195            None => 0,
196        };
197        let expecting_reply = if self.expect_reply {
198            ControlFlags::ExpectingReply as u8
199        } else {
200            0
201        };
202        let message_priority = self.message_priority.clone() as u8;
203
204        is_network_layer_message | has_destination | has_source | expecting_reply | message_priority
205    }
206
207    pub fn decode(reader: &mut Reader, buf: &'a [u8]) -> Result<Self, Error> {
208        // ignore version
209        let _version = reader.read_byte(buf)?;
210
211        // read and decode control byte
212        let control = reader.read_byte(buf)?;
213        let has_dst = (control & ControlFlags::HasDestination as u8) > 0;
214        let has_src = (control & ControlFlags::HasSource as u8) > 0;
215        let is_network_message = (control & ControlFlags::NetworkLayerMessage as u8) > 0;
216        let expect_reply = (control & ControlFlags::ExpectingReply as u8) > 0;
217        let message_priority: MessagePriority = control.into();
218
219        let dst = if has_dst {
220            Some(NetworkAddress::decode(reader, buf)?)
221        } else {
222            None
223        };
224
225        let src = if has_src {
226            Some(NetworkAddress::decode(reader, buf)?)
227        } else {
228            None
229        };
230
231        // if dst exists then read the hop_count (it comes after src for some reason)
232        let dst = if let Some(dst) = dst {
233            let hop_count = reader.read_byte(buf)?;
234            Some(DestinationAddress {
235                network_address: dst,
236                hop_count,
237            })
238        } else {
239            None
240        };
241
242        let network_message = if is_network_message {
243            let message_type = reader.read_byte(buf)?;
244            match message_type.try_into() {
245                Ok(message_type) => NetworkMessage::MessageType(message_type),
246                Err(custom_message_type) => NetworkMessage::CustomMessageType(custom_message_type),
247            }
248        } else {
249            let apdu = ApplicationPdu::decode(reader, buf)?;
250            NetworkMessage::Apdu(apdu)
251        };
252
253        Ok(Self {
254            dst,
255            src,
256            expect_reply,
257            message_priority,
258            network_message,
259        })
260    }
261}
262
263#[derive(Debug, Clone)]
264#[cfg_attr(feature = "defmt", derive(defmt::Format))]
265pub struct Addr {
266    pub ipv4: [u8; 4],
267    pub port: u16,
268}
269
270const IPV4_ADDR_LEN: u8 = 6;
271
272pub type SourceAddress = NetworkAddress;
273
274#[derive(Debug, Clone)]
275#[cfg_attr(feature = "defmt", derive(defmt::Format))]
276pub struct NetworkAddress {
277    pub net: u16,
278    pub addr: Option<Addr>,
279}
280
281#[derive(Debug, Clone)]
282#[cfg_attr(feature = "defmt", derive(defmt::Format))]
283pub struct DestinationAddress {
284    pub network_address: NetworkAddress,
285    pub hop_count: u8,
286}
287
288impl DestinationAddress {
289    pub fn new(net: u16, addr: Option<Addr>) -> Self {
290        Self {
291            network_address: NetworkAddress { net, addr },
292            hop_count: 255,
293        }
294    }
295}
296
297impl NetworkAddress {
298    pub fn encode(&self, writer: &mut Writer) {
299        writer.extend_from_slice(&self.net.to_be_bytes());
300        match self.addr.as_ref() {
301            Some(addr) => {
302                writer.push(IPV4_ADDR_LEN);
303                writer.extend_from_slice(&addr.ipv4);
304                writer.extend_from_slice(&addr.port.to_be_bytes());
305            }
306            None => writer.push(0),
307        }
308    }
309
310    pub fn decode(reader: &mut Reader, buf: &[u8]) -> Result<Self, Error> {
311        let net = u16::from_be_bytes(reader.read_bytes(buf)?);
312        let len = reader.read_byte(buf)?;
313        match len {
314            IPV4_ADDR_LEN => {
315                let ipv4: [u8; 4] = reader.read_bytes(buf)?;
316                let port = u16::from_be_bytes(reader.read_bytes(buf)?);
317
318                Ok(Self {
319                    net,
320                    addr: Some(Addr { ipv4, port }),
321                })
322            }
323            0 => Ok(Self { net, addr: None }),
324            x => Err(Error::Length((
325                "NetworkAddress decode ip len can only be 6 or 0",
326                x as u32,
327            ))),
328        }
329    }
330}