1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
//! The B/IP port driver: a node on one socket, with everything its
//! [`Node`](crate::node::Node) asks of a host carried out.
//!
//! [`node`](crate::node) decides and [`bbmd`](crate::bbmd) keeps the
//! tables; a port joins them to a socket, one type per mode, since a link
//! is never both a BBMD and a foreign device:
//!
//! - [`NodePort`]: a node in normal or foreign-device mode. It sends the
//! NAKs a node owes, a foreign device's registrations, and the
//! broadcasts it holds until the first registration attempt resolves
//! (Annex J.7.4; decision D17), in [`HeldBroadcast`] slots the caller
//! lends.
//! - [`BbmdPort`]: a BBMD's link over [`Tables`](crate::bbmd::Tables) the
//! caller lends. It forwards each broadcast where the tables say (Annex
//! J.4.5), and answers the management requests from them
//! ([`Tables::serve`](crate::bbmd::Tables::serve)), so the caller never
//! sees one. A BBMD registers nowhere and holds nothing, so it needs no
//! node.
//!
//! Every datagram leaves through the caller's [`Datagrams`], which encodes
//! the message straight into its socket's buffer, so a port keeps no
//! datagram buffer of its own. What a received datagram brought comes
//! back as an [`Ingress`]: an NPDU for the network layer, or what the port
//! did instead.
//!
//! Wiring a port to a device or a router:
//!
//! - **Start:** call [`NodePort::start`] once, before anything else: a
//! foreign device's first registration is due at once, and its response
//! timeout is the port's first deadline. A [`BbmdPort`] registers
//! nowhere, and needs no start.
//! - **Receive:** hand each datagram to the port's `receive`, and each
//! [`Ingress::Npdu`] to the network layer. Its source is the B/IP address
//! the node delivered from, which for a Forwarded-NPDU is the origin
//! (Annex J.2.5).
//! - **Send:** `unicast` an NPDU to one node, which refuses a group
//! address (#1677), or `broadcast` it: held while a foreign device's
//! first registration is outstanding, and also forwarded by a BBMD.
//! - **Timers:** sleep until the earliest of a [`NodePort`]'s
//! `next_deadline` and anything else the device runs, and call its
//! `on_deadline`. A [`BbmdPort`] has no timers of its own: lapsed
//! registrations are left out of every decision, and purged at the next
//! registration or through `tables_mut`.
//!
//! ```
//! use core::net::{Ipv4Addr, SocketAddrV4};
//! use bacnet_bip_core::codec::Bvll;
//! use bacnet_bip_core::node::{Addressed, Datagram, Link, Mode, Node, Permissive, SendRefusal};
//! use bacnet_bip_core::port::{Datagrams, Ingress, NodePort};
//! use bacnet_bip_core::{Instant, LocalSubnet};
//!
//! /// A socket that keeps the last datagram it sent.
//! struct Socket([u8; 64], usize);
//!
//! impl Datagrams for Socket {
//! fn send(&mut self, _to: SocketAddrV4, message: &Bvll<'_>) -> Result<(), SendRefusal> {
//! self.1 = message.encode_into(&mut self.0).map_err(|_| SendRefusal::SocketError)?;
//! Ok(())
//! }
//! }
//!
//! let own = SocketAddrV4::new(Ipv4Addr::new(192, 0, 2, 10), 47808);
//! let subnet = LocalSubnet::new(SocketAddrV4::new(Ipv4Addr::new(192, 0, 2, 255), 47808));
//! let node: Node = Node::new(Link::new(own, subnet, Mode::Normal)?, Instant::ZERO)?;
//! // A normal node holds no broadcasts, so it needs no slots.
//! let mut port: NodePort<'_> = NodePort::new(node, &mut [])?;
//! let mut socket = Socket([0; 64], 0);
//!
//! // A peer's Read-Broadcast-Distribution-Table draws its NAK.
//! let mut wire = [0u8; 4];
//! Bvll::ReadBroadcastDistributionTable.encode_into(&mut wire)?;
//! let peer = SocketAddrV4::new(Ipv4Addr::new(192, 0, 2, 20), 47808);
//! let to = Addressed { node: true, broadcast: false };
//! let ingress = port.receive(&Datagram::new(&wire, peer, Some(to)), Instant::ZERO, &mut Permissive, &mut socket);
//! assert_eq!(ingress, Ingress::Handled);
//! assert_eq!(&socket.0[..socket.1], [0x81, 0x00, 0x00, 0x06, 0x00, 0x20]);
//!
//! // A broadcast goes to the subnet's broadcast address.
//! port.broadcast(&[0x01, 0x00, 0x10, 0x08], Instant::ZERO, &mut socket)?;
//! assert_eq!(&socket.0[..2], [0x81, 0x0B]);
//! # Ok::<(), Box<dyn core::error::Error>>(())
//! ```
//!
//! # Local rules
//!
//! A datagram the node drops, a malformed one included, goes no further.
//! On a foreign device's port, a refused first registration drops the held
//! broadcasts, a registration the socket refuses ends its attempt, and a
//! full hold refuses the next broadcast as [`SendRefusal::HoldFull`]. Each
//! datagram of a port's own that its socket refuses (a NAK, a released
//! broadcast, a BBMD's forwarded copy or management answer) is counted
//! once in its [`PortCounters`]; a refused registration is the node's
//! [`local_errors`](crate::node::ExchangeCounters::local_errors). A BBMD
//! serves no management request from a source a reply can't reach
//! ([`Link::is_answerable`](crate::node::Link::is_answerable)). Tests:
//! `tests/port_node.rs` and `tests/port_bbmd.rs`.
use fmt;
use SocketAddrV4;
use Bvll;
use crate;
use MAX_NPDU;
use crate;
pub use BbmdPort;
pub use NodePort;
/// Where a port's datagrams go: the host's UDP socket.
/// What a received datagram brought.
///
/// It is exhaustive, as the node's [`Inbound`](crate::node::Inbound) is:
/// the caller serves each case.
/// Why a port refused its node and storage.
///
/// It is `#[non_exhaustive]`, so a new refusal isn't a breaking change: a
/// `match` needs a wildcard arm.
/// What a port counted since its counters were last taken. Its node keeps
/// counts of its own ([`Node::take_counters`](crate::node::Node::take_counters)).
///
/// It is `#[non_exhaustive]`, so a new count isn't a breaking change.
/// Outside this crate, build one from `PortCounters::default()` and set its
/// fields.
/// Room for one broadcast that a foreign device's port holds until its
/// first registration attempt resolves (Annex J.7.4; decision D17). It is
/// all zero bits, so firmware lends the port a static's.
///
/// A slot holds `N` octets, at most 65,535: by default [`MAX_NPDU`], B/IP's
/// largest NPDU. A link with a smaller send budget sends shorter
/// broadcasts, and its port can hold them in shorter slots;
/// [`NodePort::new`] checks that the link's broadcast limit fits `N`.
///
/// A default doesn't drive inference, so `HeldBroadcast::EMPTY` alone, in
/// an expression, leaves `N` open. Name the type instead: `<HeldBroadcast>`
/// is a type, so it takes the default.
///
/// ```
/// use bacnet_bip_core::port::HeldBroadcast;
///
/// // Two slots of MAX_NPDU octets, the default.
/// let full = [<HeldBroadcast>::EMPTY; 2];
/// // Two slots of 501 octets, for a link whose broadcasts are no longer.
/// let short = [HeldBroadcast::<501>::EMPTY; 2];
/// # let _ = (full, short);
/// ```
/// The length held, not the slot.
/// Send each `(to, message)`, returning how many the socket refused.
/// Add `n` refused sends to the counts, saturating.
/// Count a refused send.