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}