+745
crates/ergot/src/interface_manager/profiles/bridge_router/mod.rs
+745
crates/ergot/src/interface_manager/profiles/bridge_router/mod.rs
···
···
1
+
//! The Direct Router profile
2
+
//!
3
+
//! This is an early and simple router profile that can manage multiple directly connected
4
+
//! edge devices. It can route messages from one directly connected edge device to another,
5
+
//! as well as messages to/from itself and an edge device. It does not currently handle
6
+
//! multi-hop routing.
7
+
8
+
use core::time::Duration;
9
+
use std::{
10
+
collections::{BTreeMap, HashMap},
11
+
time::Instant,
12
+
};
13
+
14
+
use log::{debug, info, trace, warn};
15
+
use rand::Rng;
16
+
17
+
use crate::{
18
+
Header, ProtocolError,
19
+
interface_manager::{
20
+
DeregisterError, Interface, InterfaceSendError, InterfaceState, Profile,
21
+
SeedAssignmentError, SeedNetAssignment, SeedRefreshError, SetStateError,
22
+
profiles::direct_edge::CENTRAL_NODE_ID,
23
+
},
24
+
net_stack::NetStackHandle,
25
+
wire_frames::de_frame,
26
+
};
27
+
28
+
use super::direct_edge::EDGE_NODE_ID;
29
+
30
+
// pub mod tokio_tcp;
31
+
32
+
// #[cfg(feature = "nusb-v0_1")]
33
+
// pub mod nusb_0_1;
34
+
35
+
// #[cfg(feature = "tokio-serial-v5")]
36
+
// pub mod tokio_serial_5;
37
+
38
+
struct Node<I: Interface> {
39
+
// TODO: can we JUST use an interface here, NOT a profile?
40
+
edge: edge_interface_plus::EdgeInterfacePlus<I>,
41
+
net_id: u16,
42
+
ident: u64,
43
+
}
44
+
45
+
/// The "kind" of route, currently only "directly connected and assigned by us",
46
+
/// coming soon: remotely assigned net ids
47
+
#[derive(Clone)]
48
+
enum RouteKind {
49
+
/// This route is associated with a node we are DIRECTLY connected to
50
+
DirectAssigned,
51
+
/// This route was assigned by us as a seed router
52
+
SeedAssigned {
53
+
source_net_id: u16,
54
+
expiration_time: Instant,
55
+
refresh_token: u64,
56
+
},
57
+
/// This route is inactive
58
+
Tombstone { clear_time: Instant },
59
+
}
60
+
61
+
/// Route information
62
+
#[derive(Clone)]
63
+
struct Route {
64
+
/// The interface identifier for this route
65
+
ident: u64,
66
+
/// The kind of this route
67
+
kind: RouteKind,
68
+
}
69
+
70
+
pub struct DirectRouter<I: Interface> {
71
+
/// Monotonic interface counter
72
+
interface_ctr: u64,
73
+
/// Map of (Network ID => Route), where Route contains the interface ident
74
+
routes: BTreeMap<u16, Route>,
75
+
/// Map of (Interface Ident => Ident)
76
+
direct_links: HashMap<u64, Node<I>>,
77
+
}
78
+
79
+
/// The timeout duration in seconds for an initial net_id assignment as a seed router
80
+
const INITIAL_SEED_ASSIGN_TIMEOUT: u16 = 30;
81
+
/// The max timeout duration in seconds for a net_id assignment
82
+
const MAX_SEED_ASSIGN_TIMEOUT: u16 = 120;
83
+
/// There must be LESS than this many seconds left until expiration to allow for a refresh
84
+
const MIN_SEED_REFRESH: u16 = 62;
85
+
86
+
impl<I: Interface> Profile for DirectRouter<I> {
87
+
type InterfaceIdent = u64;
88
+
89
+
fn send<T: serde::Serialize>(
90
+
&mut self,
91
+
hdr: &crate::Header,
92
+
data: &T,
93
+
) -> Result<(), InterfaceSendError> {
94
+
let mut hdr = hdr.clone();
95
+
// Make sure we still have ttl juice
96
+
if hdr.decrement_ttl().is_err() {
97
+
return Err(InterfaceSendError::NoRouteToDest);
98
+
}
99
+
100
+
if hdr.dst.port_id == 255 {
101
+
if hdr.any_all.is_none() {
102
+
return Err(InterfaceSendError::AnyPortMissingKey);
103
+
}
104
+
105
+
let mut any_good = false;
106
+
for (_ident, p) in self.direct_links.iter_mut() {
107
+
// Don't send back to the origin
108
+
if hdr.dst.network_id == p.net_id {
109
+
continue;
110
+
}
111
+
let mut hdr = hdr.clone();
112
+
hdr.dst.network_id = p.net_id;
113
+
hdr.dst.node_id = EDGE_NODE_ID;
114
+
any_good |= p.edge.send(&hdr, data).is_ok();
115
+
}
116
+
if any_good {
117
+
Ok(())
118
+
} else {
119
+
Err(InterfaceSendError::NoRouteToDest)
120
+
}
121
+
} else {
122
+
let intfc = self.find(&hdr, None)?;
123
+
intfc.send(&hdr, data)
124
+
}
125
+
}
126
+
127
+
fn send_err(
128
+
&mut self,
129
+
hdr: &crate::Header,
130
+
err: ProtocolError,
131
+
source: Option<Self::InterfaceIdent>,
132
+
) -> Result<(), InterfaceSendError> {
133
+
let mut hdr = hdr.clone();
134
+
// Make sure we still have ttl juice
135
+
if hdr.decrement_ttl().is_err() {
136
+
return Err(InterfaceSendError::NoRouteToDest);
137
+
}
138
+
139
+
let intfc = self.find(&hdr, source)?;
140
+
intfc.send_err(&hdr, err)
141
+
}
142
+
143
+
fn send_raw(
144
+
&mut self,
145
+
hdr: &crate::HeaderSeq,
146
+
data: &[u8],
147
+
source: Self::InterfaceIdent,
148
+
) -> Result<(), InterfaceSendError> {
149
+
let mut hdr = hdr.clone();
150
+
// Make sure we still have ttl juice
151
+
if hdr.decrement_ttl().is_err() {
152
+
return Err(InterfaceSendError::NoRouteToDest);
153
+
}
154
+
155
+
if hdr.dst.port_id == 255 {
156
+
if hdr.any_all.is_none() {
157
+
return Err(InterfaceSendError::AnyPortMissingKey);
158
+
}
159
+
let mut any_good = false;
160
+
for (_ident, p) in self.direct_links.iter_mut() {
161
+
// Don't send back to the origin
162
+
if source == p.ident {
163
+
continue;
164
+
}
165
+
166
+
// For broadcast messages, rewrite the destination address
167
+
// to the address of the next hop.
168
+
hdr.dst.network_id = p.net_id;
169
+
hdr.dst.node_id = EDGE_NODE_ID;
170
+
any_good |= p.edge.send_raw(&hdr, data).is_ok();
171
+
}
172
+
if any_good {
173
+
Ok(())
174
+
} else {
175
+
Err(InterfaceSendError::NoRouteToDest)
176
+
}
177
+
} else {
178
+
let nshdr = hdr.clone().into();
179
+
let intfc = self.find(&nshdr, Some(source))?;
180
+
intfc.send_raw(&hdr, data)
181
+
}
182
+
}
183
+
184
+
fn interface_state(&mut self, ident: Self::InterfaceIdent) -> Option<InterfaceState> {
185
+
let node = self.direct_links.get_mut(&ident)?;
186
+
node.edge.interface_state(())
187
+
}
188
+
189
+
fn set_interface_state(
190
+
&mut self,
191
+
ident: Self::InterfaceIdent,
192
+
state: InterfaceState,
193
+
) -> Result<(), SetStateError> {
194
+
let Some(node) = self.direct_links.get_mut(&ident) else {
195
+
return Err(SetStateError::InterfaceNotFound);
196
+
};
197
+
node.edge.set_interface_state((), state)
198
+
}
199
+
200
+
fn request_seed_net_assign(
201
+
&mut self,
202
+
source_net: u16,
203
+
) -> Result<SeedNetAssignment, SeedAssignmentError> {
204
+
// Get the route for the source net
205
+
let Some(rte) = self.routes.get(&source_net) else {
206
+
return Err(SeedAssignmentError::UnknownSource);
207
+
};
208
+
let rte = rte.clone();
209
+
// Get a new net id
210
+
let Some(new_net_id) = self.find_free_net_id() else {
211
+
return Err(SeedAssignmentError::NetIdsExhausted);
212
+
};
213
+
// Pick a random refresh token
214
+
let refresh_token = rand::rng().random();
215
+
216
+
// Insert this route, initially with a low refresh time, allowing the
217
+
// remote device to immediately refresh, acting as an "acknowledgement"
218
+
// of the assignment
219
+
self.routes.insert(
220
+
new_net_id,
221
+
Route {
222
+
ident: rte.ident,
223
+
kind: RouteKind::SeedAssigned {
224
+
source_net_id: source_net,
225
+
expiration_time: Instant::now()
226
+
+ Duration::from_secs(INITIAL_SEED_ASSIGN_TIMEOUT.into()),
227
+
refresh_token,
228
+
},
229
+
},
230
+
);
231
+
232
+
Ok(SeedNetAssignment {
233
+
net_id: new_net_id,
234
+
expires_seconds: INITIAL_SEED_ASSIGN_TIMEOUT,
235
+
max_refresh_seconds: MAX_SEED_ASSIGN_TIMEOUT,
236
+
min_refresh_seconds: MIN_SEED_REFRESH,
237
+
refresh_token: refresh_token.to_le_bytes(),
238
+
})
239
+
}
240
+
241
+
fn refresh_seed_net_assignment(
242
+
&mut self,
243
+
req_source_net: u16,
244
+
req_refresh_net: u16,
245
+
req_refresh_token: [u8; 8],
246
+
) -> Result<SeedNetAssignment, SeedRefreshError> {
247
+
let Some(rte) = self.routes.get_mut(&req_refresh_net) else {
248
+
return Err(SeedRefreshError::UnknownNetId);
249
+
};
250
+
let req_refresh_token_u64 = u64::from_le_bytes(req_refresh_token);
251
+
match &mut rte.kind {
252
+
RouteKind::DirectAssigned => Err(SeedRefreshError::NotAssigned),
253
+
RouteKind::Tombstone { clear_time: _ } => Err(SeedRefreshError::AlreadyExpired),
254
+
RouteKind::SeedAssigned {
255
+
source_net_id,
256
+
expiration_time,
257
+
refresh_token,
258
+
} => {
259
+
let bad_net = *source_net_id != req_source_net;
260
+
let bad_tok = *refresh_token != req_refresh_token_u64;
261
+
if bad_net || bad_tok {
262
+
return Err(SeedRefreshError::BadRequest);
263
+
}
264
+
let now = Instant::now();
265
+
// Are we ALREADY expired?
266
+
if *expiration_time <= now {
267
+
warn!("Tombstoning net_id: {req_refresh_net}");
268
+
rte.kind = RouteKind::Tombstone {
269
+
clear_time: now + Duration::from_secs(30),
270
+
};
271
+
return Err(SeedRefreshError::AlreadyExpired);
272
+
}
273
+
// Are we TOO SOON for a refresh?
274
+
// Note: we already checked if the expiration time is in the past
275
+
let until_expired = *expiration_time - now;
276
+
if until_expired > Duration::from_secs(MIN_SEED_REFRESH.into()) {
277
+
return Err(SeedRefreshError::TooSoon);
278
+
}
279
+
280
+
// Looks good: update the expiration time
281
+
*expiration_time = now + Duration::from_secs(MAX_SEED_ASSIGN_TIMEOUT.into());
282
+
Ok(SeedNetAssignment {
283
+
net_id: req_refresh_net,
284
+
expires_seconds: MAX_SEED_ASSIGN_TIMEOUT,
285
+
max_refresh_seconds: MAX_SEED_ASSIGN_TIMEOUT,
286
+
min_refresh_seconds: MIN_SEED_REFRESH,
287
+
refresh_token: req_refresh_token,
288
+
})
289
+
}
290
+
}
291
+
}
292
+
}
293
+
294
+
impl<I: Interface> DirectRouter<I> {
295
+
pub fn new() -> Self {
296
+
Self {
297
+
interface_ctr: 0,
298
+
direct_links: HashMap::new(),
299
+
routes: BTreeMap::new(),
300
+
}
301
+
}
302
+
303
+
pub fn get_nets(&mut self) -> Vec<u16> {
304
+
self.direct_links
305
+
.iter_mut()
306
+
.filter_map(|(_ident, n)| match n.edge.interface_state(())? {
307
+
InterfaceState::Down => None,
308
+
InterfaceState::Inactive => None,
309
+
InterfaceState::ActiveLocal { .. } => None,
310
+
InterfaceState::Active { net_id, node_id: _ } => Some(net_id),
311
+
})
312
+
.collect()
313
+
}
314
+
315
+
fn find<'b>(
316
+
&'b mut self,
317
+
hdr: &Header,
318
+
source: Option<<Self as Profile>::InterfaceIdent>,
319
+
) -> Result<&'b mut edge_interface_plus::EdgeInterfacePlus<I>, InterfaceSendError> {
320
+
// todo: make this state impossible? enum of dst w/ or w/o key?
321
+
if hdr.dst.port_id == 0 && hdr.any_all.is_none() {
322
+
return Err(InterfaceSendError::AnyPortMissingKey);
323
+
}
324
+
325
+
// Find destination by net_id
326
+
let Some(rte) = self.routes.get_mut(&hdr.dst.network_id) else {
327
+
return Err(InterfaceSendError::NoRouteToDest);
328
+
};
329
+
330
+
// Do an expiration check for the given route
331
+
match rte.kind {
332
+
RouteKind::DirectAssigned => {}
333
+
RouteKind::SeedAssigned {
334
+
expiration_time, ..
335
+
} => {
336
+
let now = Instant::now();
337
+
if expiration_time <= now {
338
+
warn!("Tombstoning net_id: {}", hdr.dst.network_id);
339
+
rte.kind = RouteKind::Tombstone {
340
+
clear_time: now + Duration::from_secs(30),
341
+
};
342
+
return Err(InterfaceSendError::NoRouteToDest);
343
+
}
344
+
}
345
+
RouteKind::Tombstone { clear_time } => {
346
+
let now = Instant::now();
347
+
if clear_time <= now {
348
+
// times up, get gone.
349
+
self.routes.remove(&hdr.dst.network_id);
350
+
}
351
+
return Err(InterfaceSendError::NoRouteToDest);
352
+
}
353
+
}
354
+
355
+
// Cool, get the interface based on that ident
356
+
let Some(intfc) = self.direct_links.get_mut(&rte.ident) else {
357
+
// This is not cool. We have a route with no live direct link
358
+
// associated with it. Remove the route, return no route.
359
+
warn!(
360
+
"Stale route with net_id: {}, ident: {}, removing",
361
+
hdr.dst.network_id, rte.ident
362
+
);
363
+
self.routes.remove(&hdr.dst.network_id);
364
+
return Err(InterfaceSendError::NoRouteToDest);
365
+
};
366
+
367
+
// Is this actually for us?
368
+
if (hdr.dst.network_id == intfc.net_id) && (hdr.dst.node_id == CENTRAL_NODE_ID) {
369
+
return Err(InterfaceSendError::DestinationLocal);
370
+
}
371
+
372
+
// Is this NOT for us but the source and destination are the same?
373
+
//
374
+
// If the dest IS one of our interfaces, but NOT for us, and we received it,
375
+
// then the only thing to do would be to send it back on the same interface
376
+
// it came in on. That's a routing loop: don't do that!
377
+
if let Some(src) = source
378
+
&& intfc.ident == src
379
+
{
380
+
return Err(InterfaceSendError::RoutingLoop);
381
+
}
382
+
383
+
Ok(&mut intfc.edge)
384
+
}
385
+
386
+
fn find_free_net_id(&mut self) -> Option<u16> {
387
+
if self.routes.is_empty() {
388
+
assert!(self.direct_links.is_empty());
389
+
Some(1)
390
+
} else if self.routes.len() == 65534 {
391
+
warn!("Out of netids!");
392
+
None
393
+
} else {
394
+
let mut new_net_id = 1;
395
+
396
+
let mut to_evict = None;
397
+
let now = Instant::now();
398
+
for (net_id, rte) in self.routes.iter_mut() {
399
+
match rte.kind {
400
+
RouteKind::DirectAssigned => {
401
+
// We don't need to care about timeouts for directly assigned routes
402
+
}
403
+
RouteKind::SeedAssigned {
404
+
expiration_time, ..
405
+
} => {
406
+
// If a route has expired, mark it tombstoned to avoid re-using it for a bit
407
+
if expiration_time <= now {
408
+
warn!("Tombstoning net_id: {net_id}");
409
+
rte.kind = RouteKind::Tombstone {
410
+
clear_time: now + Duration::from_secs(30),
411
+
};
412
+
}
413
+
}
414
+
RouteKind::Tombstone { clear_time } => {
415
+
// If we've cleared the tombstone time, then re-use this net id
416
+
if clear_time <= now {
417
+
info!("Reclaiming tombstoned net_id: {net_id}");
418
+
to_evict = Some(*net_id);
419
+
break;
420
+
}
421
+
}
422
+
}
423
+
if *net_id > new_net_id {
424
+
trace!("Found gap: {net_id}");
425
+
break;
426
+
}
427
+
debug_assert!(*net_id == new_net_id);
428
+
new_net_id += 1;
429
+
}
430
+
if let Some(evicted) = to_evict {
431
+
self.routes.remove(&evicted);
432
+
Some(evicted)
433
+
} else {
434
+
// EITHER: We've found a gap that we can use, OR we've iterated all
435
+
// interfaces, which means that we had contiguous allocations but we
436
+
// have not exhausted the range.
437
+
debug_assert!(new_net_id > 0 && new_net_id != u16::MAX);
438
+
Some(new_net_id)
439
+
}
440
+
}
441
+
}
442
+
443
+
pub fn register_interface(&mut self, sink: I::Sink) -> Option<u64> {
444
+
let net_id = self.find_free_net_id()?;
445
+
446
+
let intfc_id = self.interface_ctr;
447
+
self.interface_ctr += 1;
448
+
449
+
self.direct_links.insert(
450
+
intfc_id,
451
+
Node {
452
+
edge: edge_interface_plus::EdgeInterfacePlus::new_controller(
453
+
sink,
454
+
InterfaceState::Active {
455
+
net_id,
456
+
node_id: CENTRAL_NODE_ID,
457
+
},
458
+
),
459
+
net_id,
460
+
ident: intfc_id,
461
+
},
462
+
);
463
+
self.routes.insert(
464
+
net_id,
465
+
Route {
466
+
ident: intfc_id,
467
+
kind: RouteKind::DirectAssigned,
468
+
},
469
+
);
470
+
Some(intfc_id)
471
+
}
472
+
473
+
pub fn deregister_interface(&mut self, ident: u64) -> Result<(), DeregisterError> {
474
+
let Some(node) = self.direct_links.remove(&ident) else {
475
+
return Err(DeregisterError::NoSuchInterface);
476
+
};
477
+
if let Some(rte) = self.routes.remove(&node.net_id) {
478
+
debug!(
479
+
"removing interface with net_id: {}, ident: {ident:?}",
480
+
node.net_id
481
+
);
482
+
assert!(matches!(rte.kind, RouteKind::DirectAssigned));
483
+
} else {
484
+
unreachable!("Why doesn't this interface have a direct route?")
485
+
}
486
+
// Also remove any routes that rely on this interface
487
+
self.routes.retain(|net_id, rte| {
488
+
let keep = rte.ident != ident;
489
+
if !keep {
490
+
debug!("removing indirect route with net_id: {net_id}, ident: {ident:?}")
491
+
}
492
+
keep
493
+
});
494
+
495
+
// re-insert route as a tombstone
496
+
self.routes.insert(
497
+
node.net_id,
498
+
Route {
499
+
ident,
500
+
kind: RouteKind::Tombstone {
501
+
clear_time: Instant::now() + Duration::from_secs(30),
502
+
},
503
+
},
504
+
);
505
+
506
+
Ok(())
507
+
}
508
+
}
509
+
510
+
impl<I: Interface> Default for DirectRouter<I> {
511
+
fn default() -> Self {
512
+
Self::new()
513
+
}
514
+
}
515
+
516
+
pub fn process_frame<N>(
517
+
net_id: u16,
518
+
data: &[u8],
519
+
nsh: &N,
520
+
ident: <<N as NetStackHandle>::Profile as Profile>::InterfaceIdent,
521
+
) where
522
+
N: NetStackHandle,
523
+
{
524
+
// Successfully received a packet, now we need to
525
+
// do something with it.
526
+
if let Some(mut frame) = de_frame(data) {
527
+
trace!("{} got frame from {ident:?}", frame.hdr);
528
+
// If the message comes in and has a src net_id of zero,
529
+
// we should rewrite it so it isn't later understood as a
530
+
// local packet.
531
+
if frame.hdr.src.network_id == 0 {
532
+
match frame.hdr.src.node_id {
533
+
0 => {
534
+
log::warn!("{}: device is sending us frames without a node id, ignoring", frame.hdr);
535
+
return;
536
+
}
537
+
CENTRAL_NODE_ID => {
538
+
log::warn!("{}: device is sending us frames as us, ignoring", frame.hdr);
539
+
return;
540
+
}
541
+
EDGE_NODE_ID => {}
542
+
_ => {
543
+
log::warn!("{}: device is sending us frames with a bad node id, ignoring", frame.hdr);
544
+
return;
545
+
}
546
+
}
547
+
548
+
frame.hdr.src.network_id = net_id;
549
+
}
550
+
// TODO: if the destination IS self.net_id, we could rewrite the
551
+
// dest net_id as zero to avoid a pass through the interface manager.
552
+
//
553
+
// If the dest is 0, should we rewrite the dest as self.net_id? This
554
+
// is the opposite as above, but I dunno how that will work with responses
555
+
let hdr = frame.hdr.clone();
556
+
let nshdr: Header = hdr.clone().into();
557
+
558
+
let res = match frame.body {
559
+
Ok(body) => nsh.stack().send_raw(&hdr, body, ident),
560
+
Err(e) => nsh.stack().send_err(&nshdr, e, Some(ident)),
561
+
};
562
+
match res {
563
+
Ok(()) => {}
564
+
Err(e) => {
565
+
// TODO: match on error, potentially try to send NAK?
566
+
warn!("{} recv->send error: {e:?}", frame.hdr);
567
+
}
568
+
}
569
+
} else {
570
+
warn!("Decode error! Ignoring frame on net_id {}", net_id);
571
+
}
572
+
}
573
+
574
+
mod edge_interface_plus {
575
+
use log::trace;
576
+
use serde::Serialize;
577
+
578
+
use crate::{
579
+
Header, HeaderSeq, ProtocolError,
580
+
interface_manager::{
581
+
Interface, InterfaceSendError, InterfaceSink, InterfaceState, SetStateError,
582
+
profiles::direct_edge::{CENTRAL_NODE_ID, EDGE_NODE_ID},
583
+
},
584
+
};
585
+
586
+
// TODO: call this something like "point to point edge"
587
+
pub struct EdgeInterfacePlus<I: Interface> {
588
+
sink: I::Sink,
589
+
seq_no: u16,
590
+
state: InterfaceState,
591
+
own_node_id: u8,
592
+
other_node_id: u8,
593
+
}
594
+
595
+
impl<I: Interface> EdgeInterfacePlus<I> {
596
+
pub const fn new_controller(sink: I::Sink, state: InterfaceState) -> Self {
597
+
Self {
598
+
sink,
599
+
seq_no: 0,
600
+
state,
601
+
own_node_id: CENTRAL_NODE_ID,
602
+
other_node_id: EDGE_NODE_ID,
603
+
}
604
+
}
605
+
}
606
+
607
+
impl<I: Interface> EdgeInterfacePlus<I> {
608
+
fn common_send<'b>(
609
+
&'b mut self,
610
+
hdr: &Header,
611
+
) -> Result<(&'b mut I::Sink, HeaderSeq), InterfaceSendError> {
612
+
let net_id = match &self.state {
613
+
InterfaceState::Down | InterfaceState::Inactive => {
614
+
return Err(InterfaceSendError::NoRouteToDest);
615
+
}
616
+
InterfaceState::ActiveLocal { .. } => {
617
+
// TODO: maybe also handle this?
618
+
return Err(InterfaceSendError::NoRouteToDest);
619
+
}
620
+
InterfaceState::Active { net_id, node_id: _ } => *net_id,
621
+
};
622
+
623
+
trace!("{hdr} common_send");
624
+
625
+
// TODO: when this WAS a real Profile, we did a lot of these things, but
626
+
// now they should be done by the router. For now, we just have asserts,
627
+
// eventually we should relax this to debug_asserts?
628
+
assert!(net_id != 0);
629
+
let for_us = hdr.dst.network_id == net_id && hdr.dst.node_id == self.own_node_id;
630
+
assert!(!for_us);
631
+
632
+
let mut hdr = hdr.clone();
633
+
634
+
// If the source is local, rewrite the source using this interface's
635
+
// information so responses can find their way back here
636
+
if hdr.src.net_node_any() {
637
+
// todo: if we know the destination is EXACTLY this network,
638
+
// we could leave the network_id local to allow for shorter
639
+
// addresses
640
+
hdr.src.network_id = net_id;
641
+
hdr.src.node_id = self.own_node_id;
642
+
}
643
+
644
+
// If this is a broadcast message, update the destination, ignoring
645
+
// whatever was there before
646
+
if hdr.dst.port_id == 255 {
647
+
hdr.dst.network_id = net_id;
648
+
hdr.dst.node_id = self.other_node_id;
649
+
}
650
+
651
+
// If this message has no seq_no, assign it one
652
+
let header = hdr.to_headerseq_or_with_seq(|| {
653
+
let seq_no = self.seq_no;
654
+
self.seq_no = self.seq_no.wrapping_add(1);
655
+
seq_no
656
+
});
657
+
if [0, 255].contains(&hdr.dst.port_id) && hdr.any_all.is_none() {
658
+
return Err(InterfaceSendError::AnyPortMissingKey);
659
+
}
660
+
661
+
Ok((&mut self.sink, header))
662
+
}
663
+
}
664
+
665
+
/// NOTE: this LOOKS like a profile impl, because it was, but it's actually not, because
666
+
/// this version of DirectEdge only serves DirectRouter
667
+
impl<I: Interface> EdgeInterfacePlus<I> {
668
+
pub(super) fn send<T: Serialize>(
669
+
&mut self,
670
+
hdr: &Header,
671
+
data: &T,
672
+
) -> Result<(), InterfaceSendError> {
673
+
let (intfc, header) = self.common_send(hdr)?;
674
+
675
+
let res = intfc.send_ty(&header, data);
676
+
677
+
match res {
678
+
Ok(()) => Ok(()),
679
+
Err(()) => Err(InterfaceSendError::InterfaceFull),
680
+
}
681
+
}
682
+
683
+
pub(super) fn send_err(
684
+
&mut self,
685
+
hdr: &Header,
686
+
err: ProtocolError,
687
+
) -> Result<(), InterfaceSendError> {
688
+
let (intfc, header) = self.common_send(hdr)?;
689
+
690
+
let res = intfc.send_err(&header, err);
691
+
692
+
match res {
693
+
Ok(()) => Ok(()),
694
+
Err(()) => Err(InterfaceSendError::InterfaceFull),
695
+
}
696
+
}
697
+
698
+
pub(super) fn send_raw(
699
+
&mut self,
700
+
hdr: &HeaderSeq,
701
+
data: &[u8],
702
+
) -> Result<(), InterfaceSendError> {
703
+
let nshdr: Header = hdr.clone().into();
704
+
let (intfc, header) = self.common_send(&nshdr)?;
705
+
let res = intfc.send_raw(&header, data);
706
+
707
+
match res {
708
+
Ok(()) => Ok(()),
709
+
Err(()) => Err(InterfaceSendError::InterfaceFull),
710
+
}
711
+
}
712
+
713
+
pub(super) fn interface_state(&mut self, _ident: ()) -> Option<InterfaceState> {
714
+
Some(self.state)
715
+
}
716
+
717
+
pub(super) fn set_interface_state(
718
+
&mut self,
719
+
_ident: (),
720
+
state: InterfaceState,
721
+
) -> Result<(), SetStateError> {
722
+
match state {
723
+
InterfaceState::Down => {
724
+
self.state = InterfaceState::Down;
725
+
}
726
+
InterfaceState::Inactive => {
727
+
self.state = InterfaceState::Inactive;
728
+
}
729
+
InterfaceState::ActiveLocal { node_id } => {
730
+
if node_id != self.own_node_id {
731
+
return Err(SetStateError::InvalidNodeId);
732
+
}
733
+
self.state = InterfaceState::ActiveLocal { node_id };
734
+
}
735
+
InterfaceState::Active { net_id, node_id } => {
736
+
if node_id != self.own_node_id {
737
+
return Err(SetStateError::InvalidNodeId);
738
+
}
739
+
self.state = InterfaceState::Active { net_id, node_id };
740
+
}
741
+
}
742
+
Ok(())
743
+
}
744
+
}
745
+
}