Skip to main content

bacnet_bip_core/
subnet.rs

1//! The IP subnet a node is on.
2
3use core::net::{Ipv4Addr, SocketAddrV4};
4
5/// A node's own IP subnet as its B/IP network uses it: the broadcast
6/// address that reaches the network's devices there and, when the caller
7/// knows it, the subnet mask.
8///
9/// A BBMD passes it to the decisions that can send to its subnet,
10/// [`Tables::forwarded_npdu`](crate::bbmd::Tables::forwarded_npdu) and
11/// [`Tables::distribute_broadcast`](crate::bbmd::Tables::distribute_broadcast).
12///
13/// It is `#[non_exhaustive]`, so a new detail of the subnet isn't a
14/// breaking change: outside this crate, build it with
15/// [`LocalSubnet::new`] and set [`mask`](Self::mask) when it is known.
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17#[non_exhaustive]
18pub struct LocalSubnet {
19    /// Where a broadcast to the network's devices goes: the subnet's
20    /// directed broadcast address (or 255.255.255.255) at the B/IP
21    /// network's UDP port (Annex J.1.2). For a B/IP-M node it is the
22    /// multicast group and its port instead (Annex J.8.1): the group acts
23    /// as the node's subnet, and broadcasts go to it and come from it
24    /// alone ([`Addressed::classify`](crate::node::Addressed::classify)).
25    pub broadcast: SocketAddrV4,
26    /// The mask of the subnet the node's own B/IP address is on, when the
27    /// caller knows it. With it, a BBMD doesn't broadcast a peer's
28    /// Forwarded-NPDU again when the peer sent it from this subnet at the
29    /// BBMD's own port: the network's devices there heard it first hand.
30    /// Leave it `None` when it isn't known, or when the own address isn't
31    /// on the subnet, as behind NAT; such a forward is then broadcast. A
32    /// BBMD that serves a multicast group doesn't use it: a peer's own
33    /// broadcasts reach its IP subnet, not the group.
34    pub mask: Option<Ipv4Addr>,
35    /// Whether the node is the only device of its B/IP network on the
36    /// subnet, as a BBMD behind a NAT router often is (Annex J.7.5). A BBMD
37    /// then skips the local broadcast of a peer's Forwarded-NPDU, as Annex
38    /// J.4.5 permits (leaving how the BBMD knows to the installation), and,
39    /// extending that permission, of a foreign device's
40    /// Distribute-Broadcast-To-Network: nothing there would receive either,
41    /// and the BBMD's own application still gets the message. `false` unless the caller sets it; set it only when
42    /// no other device of the network shares the subnet, or they stop
43    /// receiving remote broadcasts.
44    pub alone: bool,
45    /// For a B/IP-M node, whose [`broadcast`](Self::broadcast) is its
46    /// multicast group, the IP subnet's directed broadcast address, when
47    /// the caller knows it. The node neither sends there nor takes
48    /// broadcasts from there, but the address still reaches more than one
49    /// node, so a datagram from it, or a Forwarded-NPDU naming it as the
50    /// origin, is dropped ([`Groups`](crate::node::Groups)). `None` for a
51    /// plain node, whose broadcast address already is it.
52    pub directed: Option<Ipv4Addr>,
53}
54
55impl LocalSubnet {
56    /// The subnet whose broadcasts go to `broadcast`, its mask not known,
57    /// shared with other devices.
58    #[must_use]
59    pub const fn new(broadcast: SocketAddrV4) -> Self {
60        Self {
61            broadcast,
62            mask: None,
63            alone: false,
64            directed: None,
65        }
66    }
67
68    /// A B/IP-M node's subnet (Annex J.8.1): broadcasts go to `group`, a
69    /// multicast address at the network's port, and `directed`, the IP
70    /// subnet's own broadcast address when known, stays a group address.
71    /// A BBMD that serves the group (Annex J.8.3) has the same subnet.
72    #[must_use]
73    pub const fn member(group: SocketAddrV4, directed: Option<Ipv4Addr>) -> Self {
74        Self {
75            broadcast: group,
76            mask: None,
77            alone: false,
78            directed,
79        }
80    }
81
82    /// Whether the broadcast address is a multicast group: the subnet of a
83    /// B/IP-M node, or of the BBMD that serves its group (Annex J.8).
84    #[must_use]
85    pub const fn is_group(&self) -> bool {
86        self.broadcast.ip().is_multicast()
87    }
88}