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
//! [`CovTarget`]: the device a managed COV subscription goes to (#1790).
use super::*;
/// The device a managed COV subscription goes to: on this network at a MAC,
/// or on another network behind a router.
///
/// A device keeps a subscription under the address the request came from
/// (Clause 13.14.2), and its notifications carry that subscription's process
/// identifier back from the device's own address (Clauses 13.6.1 and
/// 13.7.1). So a notification belongs to this target when it comes from the
/// same address: the MAC with no source network for a local device, or the
/// source network and station address for a routed one. The router a
/// routed notification came through is not part of the device's address and
/// isn't compared.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum CovTarget {
/// A device on this network.
Local {
/// Its MAC address.
mac: MacAddr,
},
/// A device on another network, reached through a router on this one.
Routed {
/// The MAC of the router the requests go to.
router_mac: MacAddr,
/// The device's network number, 1 to 65534.
network: u16,
/// The device's MAC address on that network.
address: MacAddr,
},
}
impl CovTarget {
/// A device on this network at `mac`.
pub fn local(mac: &[u8]) -> Self {
Self::Local {
mac: MacAddr::from_slice(mac),
}
}
/// A device at `address` on `network`, reached through the router at
/// `router_mac`.
pub fn routed(router_mac: &[u8], network: u16, address: &[u8]) -> Self {
Self::Routed {
router_mac: MacAddr::from_slice(router_mac),
network,
address: MacAddr::from_slice(address),
}
}
/// Where a discovered device is: routed when its I-Am came with a source
/// network and address (through the router it came from), local
/// otherwise.
pub fn of_device(device: &DiscoveredDevice) -> Self {
match (device.source_network, &device.source_address) {
(Some(network), Some(address)) => Self::Routed {
router_mac: device.mac_address.clone(),
network,
address: address.clone(),
},
_ => Self::Local {
mac: device.mac_address.clone(),
},
}
}
pub(super) fn confirmed(&self) -> ConfirmedTarget<'_> {
match self {
Self::Local { mac } => ConfirmedTarget::Local { mac },
Self::Routed {
router_mac,
network,
address,
} => ConfirmedTarget::Routed {
router_mac,
dest_network: *network,
dest_mac: address,
},
}
}
/// True when `received` came from this device's address. A routed
/// target on the client's own network (`local_network`, once learned)
/// is sent to as a local device (#1358), so its notifications may come
/// with no source network, from its address as the MAC.
pub(super) fn sent(
&self,
received: &ReceivedCOVNotification,
local_network: Option<u16>,
) -> bool {
let local_from = |mac: &MacAddr| {
received.source_network.is_none()
&& received.source_address.is_none()
&& received.source_mac == *mac
};
match self {
Self::Local { mac } => local_from(mac),
Self::Routed {
network, address, ..
} => {
(received.source_network == Some(*network)
&& received.source_address.as_ref() == Some(address))
|| (local_network == Some(*network) && local_from(address))
}
}
}
}