pamoja_lorawan/relay/trusted.rs
1//! The end devices a relay verifies wake-on-radio frames for, TS011-1.0.1 sections 10.4
2//! and 10.5.
3
4use super::keys::WorKeys;
5use super::limits::TokenBucket;
6use super::wor::{Carrier, SealedWor};
7use super::TRUSTED_ED_NUMBER;
8use crate::LorawanError;
9
10/// An end device a relay trusts: its keys, the WOR frame counter it expects next, and how
11/// much of it the relay forwards.
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub struct TrustedDevice {
14 dev_addr: u32,
15 keys: WorKeys,
16 next_wfcnt: u64,
17 bucket: TokenBucket,
18}
19
20impl TrustedDevice {
21 /// Trusts an end device, as `UpdateUplinkListReq` asks.
22 ///
23 /// # Arguments
24 ///
25 /// * `dev_addr` - its address.
26 /// * `root_wor_s_key` - the root relay session key the network sent for it, which its
27 /// integrity and encryption keys derive from.
28 /// * `next_wfcnt` - the WOR frame counter the network expects from it next.
29 /// * `bucket` - how many of its uplinks the relay forwards.
30 ///
31 /// # Returns
32 ///
33 /// The trusted device.
34 #[must_use]
35 pub fn new(
36 dev_addr: u32,
37 root_wor_s_key: &[u8; 16],
38 next_wfcnt: u32,
39 bucket: TokenBucket,
40 ) -> TrustedDevice {
41 TrustedDevice::with_keys(
42 dev_addr,
43 WorKeys::derive(root_wor_s_key, dev_addr),
44 next_wfcnt,
45 bucket,
46 )
47 }
48
49 /// Trusts an end device whose keys are already derived.
50 ///
51 /// # Arguments
52 ///
53 /// * `dev_addr` - its address.
54 /// * `keys` - its integrity and encryption keys.
55 /// * `next_wfcnt` - the WOR frame counter expected from it next.
56 /// * `bucket` - how many of its uplinks the relay forwards.
57 ///
58 /// # Returns
59 ///
60 /// The trusted device.
61 #[must_use]
62 pub const fn with_keys(
63 dev_addr: u32,
64 keys: WorKeys,
65 next_wfcnt: u32,
66 bucket: TokenBucket,
67 ) -> TrustedDevice {
68 TrustedDevice {
69 dev_addr,
70 keys,
71 next_wfcnt: next_wfcnt as u64,
72 bucket,
73 }
74 }
75
76 /// Returns the device's address.
77 ///
78 /// # Returns
79 ///
80 /// The address.
81 #[must_use]
82 pub const fn dev_addr(&self) -> u32 {
83 self.dev_addr
84 }
85
86 /// Returns the device's keys.
87 ///
88 /// # Returns
89 ///
90 /// The integrity and encryption keys.
91 #[must_use]
92 pub const fn keys(&self) -> &WorKeys {
93 &self.keys
94 }
95
96 /// Returns the WOR frame counter the relay accepts next, at the least.
97 ///
98 /// # Returns
99 ///
100 /// The counter, or `None` once a frame with the last counter there is has been
101 /// accepted.
102 #[must_use]
103 pub const fn next_wfcnt(&self) -> Option<u32> {
104 if self.next_wfcnt > u32::MAX as u64 {
105 None
106 } else {
107 Some(self.next_wfcnt as u32)
108 }
109 }
110
111 /// Returns the last WOR frame counter the relay accepted, which `CtrlUplinkListAns`
112 /// reports.
113 ///
114 /// # Returns
115 ///
116 /// The counter. Before any frame arrives, it is one less than the counter the network
117 /// said to expect, wrapping, so the network reads back what it set.
118 #[must_use]
119 pub const fn last_wfcnt(&self) -> u32 {
120 (self.next_wfcnt as u32).wrapping_sub(1)
121 }
122
123 /// Returns how many of the device's uplinks the relay forwards.
124 ///
125 /// # Returns
126 ///
127 /// The bucket.
128 #[must_use]
129 pub const fn bucket(&self) -> &TokenBucket {
130 &self.bucket
131 }
132
133 /// Returns the device's bucket to spend from or reconfigure.
134 ///
135 /// # Returns
136 ///
137 /// The bucket.
138 pub fn bucket_mut(&mut self) -> &mut TokenBucket {
139 &mut self.bucket
140 }
141
142 /// Checks and opens a wake-on-radio frame from the device, then moves the counter past
143 /// it.
144 ///
145 /// The frame carries the counter's low sixteen bits. The relay takes the first full
146 /// counter at or after the one it expects with those bits, so a frame it has seen, or
147 /// an older one, does not verify.
148 ///
149 /// # Arguments
150 ///
151 /// * `wor` - the frame.
152 /// * `carrier` - the carrier it arrived on.
153 ///
154 /// # Returns
155 ///
156 /// The full counter the frame carried and where its uplink follows.
157 ///
158 /// # Errors
159 ///
160 /// Returns [`LorawanError::FcntMismatch`] for a frame addressed elsewhere or past the
161 /// last counter, and [`LorawanError::MicMismatch`] when it does not verify, leaving the
162 /// counter where it was.
163 pub fn open(
164 &mut self,
165 wor: &SealedWor,
166 carrier: Carrier,
167 ) -> Result<(u32, Carrier), LorawanError> {
168 if wor.dev_addr() != self.dev_addr {
169 return Err(LorawanError::FcntMismatch);
170 }
171 let mut candidate = (self.next_wfcnt & !0xFFFF) | u64::from(wor.wfcnt());
172 if candidate < self.next_wfcnt {
173 candidate += 0x1_0000;
174 }
175 let wfcnt = u32::try_from(candidate).map_err(|_| LorawanError::FcntMismatch)?;
176 let uplink = wor.open(&self.keys, wfcnt, carrier)?;
177 self.next_wfcnt = candidate + 1;
178 Ok((wfcnt, uplink))
179 }
180}
181
182/// The end devices a relay trusts, [`TRUSTED_ED_NUMBER`] of them, each at the index the
183/// network gave it.
184#[derive(Clone, Copy, Debug, PartialEq, Eq)]
185pub struct TrustedDevices {
186 entries: [Option<TrustedDevice>; TRUSTED_ED_NUMBER],
187}
188
189impl TrustedDevices {
190 /// An empty list.
191 ///
192 /// # Returns
193 ///
194 /// The list.
195 #[must_use]
196 pub const fn new() -> TrustedDevices {
197 TrustedDevices {
198 entries: [None; TRUSTED_ED_NUMBER],
199 }
200 }
201
202 /// Returns the device at an index.
203 ///
204 /// # Arguments
205 ///
206 /// * `index` - the entry, 0 to 15.
207 ///
208 /// # Returns
209 ///
210 /// The device, or `None` for an empty entry or one out of range.
211 #[must_use]
212 pub fn get(&self, index: u8) -> Option<&TrustedDevice> {
213 self.entries.get(usize::from(index))?.as_ref()
214 }
215
216 /// Returns the device at an index to change.
217 ///
218 /// # Arguments
219 ///
220 /// * `index` - the entry, 0 to 15.
221 ///
222 /// # Returns
223 ///
224 /// The device, or `None` for an empty entry or one out of range.
225 pub fn get_mut(&mut self, index: u8) -> Option<&mut TrustedDevice> {
226 self.entries.get_mut(usize::from(index))?.as_mut()
227 }
228
229 /// Puts a device at an index, replacing whatever was there.
230 ///
231 /// # Arguments
232 ///
233 /// * `index` - the entry, 0 to 15.
234 /// * `device` - the device.
235 ///
236 /// # Returns
237 ///
238 /// `false` for an index out of range.
239 pub fn set(&mut self, index: u8, device: TrustedDevice) -> bool {
240 match self.entries.get_mut(usize::from(index)) {
241 Some(entry) => {
242 *entry = Some(device);
243 true
244 }
245 None => false,
246 }
247 }
248
249 /// Stops trusting the device at an index.
250 ///
251 /// # Arguments
252 ///
253 /// * `index` - the entry, 0 to 15.
254 ///
255 /// # Returns
256 ///
257 /// The device that was there.
258 pub fn remove(&mut self, index: u8) -> Option<TrustedDevice> {
259 self.entries.get_mut(usize::from(index))?.take()
260 }
261
262 /// Lists the devices.
263 ///
264 /// # Returns
265 ///
266 /// Each device with its index, in index order.
267 pub fn iter(&self) -> impl Iterator<Item = (u8, &TrustedDevice)> + '_ {
268 (0u8..)
269 .zip(self.entries.iter())
270 .filter_map(|(index, entry)| entry.as_ref().map(|device| (index, device)))
271 }
272
273 /// Reports whether any device has an address.
274 ///
275 /// # Arguments
276 ///
277 /// * `dev_addr` - the address.
278 ///
279 /// # Returns
280 ///
281 /// `true` when a trusted device has it.
282 #[must_use]
283 pub fn knows(&self, dev_addr: u32) -> bool {
284 self.iter().any(|(_, device)| device.dev_addr() == dev_addr)
285 }
286
287 /// Checks and opens a wake-on-radio frame with the keys of whichever device it verifies
288 /// for.
289 ///
290 /// # Arguments
291 ///
292 /// * `wor` - the frame.
293 /// * `carrier` - the carrier it arrived on.
294 ///
295 /// # Returns
296 ///
297 /// The index of the device it came from, the full counter it carried, and where its
298 /// uplink follows; or `None` when no trusted device has the address it names.
299 ///
300 /// # Errors
301 ///
302 /// When devices have the address but the frame verifies for none of them, the last of
303 /// their errors, as [`TrustedDevice::open`] gives them.
304 pub fn open(
305 &mut self,
306 wor: &SealedWor,
307 carrier: Carrier,
308 ) -> Option<Result<(u8, u32, Carrier), LorawanError>> {
309 let mut outcome = None;
310 for (index, entry) in (0u8..).zip(self.entries.iter_mut()) {
311 let Some(device) = entry
312 .as_mut()
313 .filter(|device| device.dev_addr == wor.dev_addr())
314 else {
315 continue;
316 };
317 match device.open(wor, carrier) {
318 Ok((wfcnt, uplink)) => return Some(Ok((index, wfcnt, uplink))),
319 Err(error) => outcome = Some(Err(error)),
320 }
321 }
322 outcome
323 }
324
325 /// Adds what every device's bucket earns over some hours.
326 ///
327 /// # Arguments
328 ///
329 /// * `hours` - the whole hours since the last reload.
330 pub fn reload(&mut self, hours: u64) {
331 for device in self.entries.iter_mut().flatten() {
332 device.bucket.reload(hours);
333 }
334 }
335}
336
337impl Default for TrustedDevices {
338 fn default() -> TrustedDevices {
339 TrustedDevices::new()
340 }
341}