Skip to main content

pamoja_gateway/
network.rs

1//! The network side of a single site: what a server does with what a gateway forwarded.
2//!
3//! A gateway hands over packets without reading them, because it holds no keys. Deciding
4//! what a packet is, admitting the device that sent it, decrypting what it carries, and
5//! working out when and where to answer is the network server's work, and this module does
6//! that much of it for one site: a [`Network`] holds the devices it admits, the sessions it
7//! has granted, and the counters it has seen, and turns an [`Rxpk`] into an [`Event`].
8//!
9//! It runs no sockets and keeps no clock. An uplink goes in as the gateway reported it, and
10//! a downlink comes back as a [`Txpk`] ready for a `PULL_RESP`, timed in the concentrator's
11//! own microseconds, so the caller owns every decision about the wire.
12//!
13//! The windows come from the published parameters rather than from habit. RP002-1.0.5
14//! section 3.3 gives the delays that are recommended for every region, TS001-1.0.4 gives the
15//! layout of the two bytes a join accept carries, and the channel a first window answers on
16//! is regional: [`Rx1Channels`] carries the two shapes the specification defines.
17//!
18//! # Examples
19//!
20//! A device joins, sends a reading, and is answered in its first receive window.
21//!
22//! ```
23//! use pamoja_gateway::network::{Event, Network, Registration};
24//! use pamoja_gateway::udp::Rxpk;
25//! use pamoja_lora::region::Region;
26//! use pamoja_lora::LinkSettings;
27//! use pamoja_lorawan::Device;
28//!
29//! let mut network = Network::new(Region::Eu868.plan(), 0x00_00_2A);
30//! let device = Device::new([1; 8], [2; 8], [3; 16]);
31//! network.register(Registration::new([1; 8], [2; 8], [3; 16]));
32//!
33//! // The gateway forwards the join request it heard.
34//! let link = LinkSettings::new(7, 125_000);
35//! let request = device.join_request(0x1234);
36//! let heard = Rxpk::new(868_100_000, link, request.as_bytes().to_vec()).with_timestamp_us(1_000);
37//! let joined = network.uplink(&heard).expect("the request verifies");
38//! assert!(matches!(joined, Event::Joined { .. }));
39//! ```
40
41use pamoja_lora::region::{ChannelBlock, ChannelPlan, OwnedChannelPlan};
42use pamoja_lora::LinkSettings;
43use pamoja_lorawan::{
44    Downlink, FrameHeader, JoinGrant, JoinRequest, LorawanError, MessageType, Session,
45};
46
47use crate::udp::{Rxpk, Txpk};
48
49/// The delay between the end of an uplink and the opening of the first receive window, in
50/// microseconds, as RP002-1.0.5 section 3.3 recommends for every region.
51pub const RECEIVE_DELAY1_US: u32 = 1_000_000;
52
53/// The delay before the second receive window, which the same table fixes at one second
54/// after the first.
55pub const RECEIVE_DELAY2_US: u32 = RECEIVE_DELAY1_US + 1_000_000;
56
57/// The delay before the first window a join accept may be sent in, in microseconds.
58pub const JOIN_ACCEPT_DELAY1_US: u32 = 5_000_000;
59
60/// The delay before the second window a join accept may be sent in, in microseconds.
61pub const JOIN_ACCEPT_DELAY2_US: u32 = 6_000_000;
62
63/// How far ahead of the counter it has seen a network will follow a device.
64///
65/// A frame further ahead than this is refused rather than accepted, which is what stops a
66/// captured frame from being replayed at a counter the device will never reach. The value
67/// is the one RP002-1.0.5 section 3.3 lists, noted there as deprecated and removed in
68/// LoRaWAN 1.0.4 and later; it is the ceiling this module applies to 1.0.x sessions.
69pub const MAX_FCNT_GAP: u32 = 16_384;
70
71/// The channel the first receive window answers on, which the region decides.
72///
73/// RP002-1.0.5 defines two shapes for the bands this carries. Most regions answer on the
74/// frequency the uplink arrived on (section 3.4.7 for EU863-870, and the same wording for
75/// EU433, AS923, KR920-923, IN865 and RU864-870). The 900 MHz plans instead answer on a run
76/// of downlink channels, choosing one by the uplink channel number: "RX1 Channel Number =
77/// Transmit Channel Number modulo NbChannel" (sections 3.5.7 and 3.8.7).
78///
79/// CN470-510 is a third shape, mapping an uplink channel number onto a published table of
80/// downlink frequencies that differs per plan type, and it is not carried here; a deployment
81/// on that band supplies its own downstream block.
82#[derive(Clone, Copy, Debug, PartialEq, Eq)]
83pub enum Rx1Channels {
84    /// The window answers on the frequency the uplink arrived on.
85    SameAsUplink,
86    /// The window answers on a run of downlink channels, indexed by the uplink channel
87    /// number modulo how many the run holds.
88    Downstream(ChannelBlock),
89}
90
91impl Rx1Channels {
92    /// Returns the downstream channels US902-928 answers on.
93    ///
94    /// Eight channels of 500 kHz starting at 923.3 MHz and stepping 600 kHz to 927.5 MHz,
95    /// carrying downlink data rates DR8 to DR13, from RP002-1.0.5 section 3.5.2.
96    ///
97    /// # Returns
98    ///
99    /// The channels.
100    pub const fn us915() -> Rx1Channels {
101        Rx1Channels::Downstream(ChannelBlock::new(923_300_000, 600_000, 8, 8, 13))
102    }
103
104    /// Returns the downstream channels AU915-928 answers on, which are the same run.
105    ///
106    /// # Returns
107    ///
108    /// The channels.
109    pub const fn au915() -> Rx1Channels {
110        Rx1Channels::Downstream(ChannelBlock::new(923_300_000, 600_000, 8, 8, 13))
111    }
112}
113
114/// When and where a network answers, and at what rate.
115///
116/// The defaults are the values recommended for every region in RP002-1.0.5 section 3.3: one
117/// second to the first receive window, five to the first join window, and no offset between
118/// the uplink data rate and the downlink one.
119#[derive(Clone, Copy, Debug, PartialEq, Eq)]
120pub struct Windows {
121    receive_delay_us: u32,
122    join_delay_us: u32,
123    rx1_data_rate_offset: u8,
124    rx1_channels: Rx1Channels,
125}
126
127impl Windows {
128    /// Returns the recommended windows: one second, five seconds, no offset, answering on
129    /// the frequency the uplink arrived on.
130    ///
131    /// # Returns
132    ///
133    /// The windows.
134    pub const fn new() -> Windows {
135        Windows {
136            receive_delay_us: RECEIVE_DELAY1_US,
137            join_delay_us: JOIN_ACCEPT_DELAY1_US,
138            rx1_data_rate_offset: 0,
139            rx1_channels: Rx1Channels::SameAsUplink,
140        }
141    }
142
143    /// Sets the delay before the first receive window, in microseconds.
144    ///
145    /// # Arguments
146    ///
147    /// * `micros` - the delay.
148    ///
149    /// # Returns
150    ///
151    /// The updated windows, for chaining.
152    pub const fn with_receive_delay_us(mut self, micros: u32) -> Windows {
153        self.receive_delay_us = micros;
154        self
155    }
156
157    /// Sets the delay before the window a join accept is sent in, in microseconds.
158    ///
159    /// # Arguments
160    ///
161    /// * `micros` - the delay.
162    ///
163    /// # Returns
164    ///
165    /// The updated windows, for chaining.
166    pub const fn with_join_delay_us(mut self, micros: u32) -> Windows {
167        self.join_delay_us = micros;
168        self
169    }
170
171    /// Sets the offset between the uplink data rate and the one the first window answers at.
172    ///
173    /// # Arguments
174    ///
175    /// * `offset` - the RX1DROffset the plan allows.
176    ///
177    /// # Returns
178    ///
179    /// The updated windows, for chaining.
180    pub const fn with_rx1_data_rate_offset(mut self, offset: u8) -> Windows {
181        self.rx1_data_rate_offset = offset;
182        self
183    }
184
185    /// Sets the channels the first window answers on.
186    ///
187    /// # Arguments
188    ///
189    /// * `channels` - the regional rule.
190    ///
191    /// # Returns
192    ///
193    /// The updated windows, for chaining.
194    pub const fn with_rx1_channels(mut self, channels: Rx1Channels) -> Windows {
195        self.rx1_channels = channels;
196        self
197    }
198
199    /// Returns the delay before the first receive window, in microseconds.
200    ///
201    /// # Returns
202    ///
203    /// The delay.
204    pub const fn receive_delay_us(&self) -> u32 {
205        self.receive_delay_us
206    }
207
208    /// Returns the delay before the join accept window, in microseconds.
209    ///
210    /// # Returns
211    ///
212    /// The delay.
213    pub const fn join_delay_us(&self) -> u32 {
214        self.join_delay_us
215    }
216
217    /// Returns the offset the first window answers at.
218    ///
219    /// # Returns
220    ///
221    /// The offset.
222    pub const fn rx1_data_rate_offset(&self) -> u8 {
223        self.rx1_data_rate_offset
224    }
225
226    /// Returns the channels the first window answers on.
227    ///
228    /// # Returns
229    ///
230    /// The regional rule.
231    pub const fn rx1_channels(&self) -> Rx1Channels {
232        self.rx1_channels
233    }
234
235    /// Returns the `RXDelay` byte a join accept carries.
236    ///
237    /// TS001-1.0.4 table 44 puts the delay in the low four bits, in seconds, and states that
238    /// a zero there means one second, so a sub-second delay cannot be expressed and rounds
239    /// down to the same one second the device already assumes.
240    ///
241    /// # Returns
242    ///
243    /// The byte.
244    pub const fn rx_delay_byte(&self) -> u8 {
245        let seconds = self.receive_delay_us / 1_000_000;
246        if seconds > 15 {
247            return 15;
248        }
249        seconds as u8
250    }
251
252    /// Returns the `DLSettings` byte a join accept carries.
253    ///
254    /// TS001-1.0.4 table 55 lays it out as a reserved top bit, the RX1DROffset in bits 6 to
255    /// 4, and the second window's data rate in the low four bits.
256    ///
257    /// # Arguments
258    ///
259    /// * `rx2_data_rate` - the data rate the second window listens at, from the plan.
260    ///
261    /// # Returns
262    ///
263    /// The byte.
264    pub const fn dl_settings_byte(&self, rx2_data_rate: u8) -> u8 {
265        ((self.rx1_data_rate_offset & 0x07) << 4) | (rx2_data_rate & 0x0F)
266    }
267}
268
269impl Default for Windows {
270    fn default() -> Windows {
271        Windows::new()
272    }
273}
274
275/// A device the network admits, and the key it was provisioned with.
276#[derive(Clone, Copy)]
277pub struct Registration {
278    dev_eui: [u8; 8],
279    app_eui: [u8; 8],
280    app_key: [u8; 16],
281}
282
283impl Registration {
284    /// Registers a device by its identifiers and its root key.
285    ///
286    /// # Arguments
287    ///
288    /// * `dev_eui` - the device's identifier.
289    /// * `app_eui` - the application identifier it joins under.
290    /// * `app_key` - the root key it was provisioned with.
291    ///
292    /// # Returns
293    ///
294    /// The registration.
295    pub const fn new(dev_eui: [u8; 8], app_eui: [u8; 8], app_key: [u8; 16]) -> Registration {
296        Registration {
297            dev_eui,
298            app_eui,
299            app_key,
300        }
301    }
302
303    /// Returns the device's identifier.
304    ///
305    /// # Returns
306    ///
307    /// The DevEUI.
308    pub const fn dev_eui(&self) -> [u8; 8] {
309        self.dev_eui
310    }
311
312    /// Returns the application identifier the device joins under.
313    ///
314    /// # Returns
315    ///
316    /// The AppEUI.
317    pub const fn app_eui(&self) -> [u8; 8] {
318        self.app_eui
319    }
320}
321
322// The root key never reaches a log, a panic message, or a test failure through this type.
323impl core::fmt::Debug for Registration {
324    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
325        f.debug_struct("Registration")
326            .field("dev_eui", &self.dev_eui)
327            .field("app_eui", &self.app_eui)
328            .finish_non_exhaustive()
329    }
330}
331
332/// Where and when a downlink answers an uplink, in the concentrator's own terms.
333#[derive(Clone, Copy, Debug, PartialEq)]
334pub struct Slot {
335    /// The concentrator timestamp to transmit at, in microseconds.
336    pub timestamp_us: u32,
337    /// The frequency to transmit on, in hertz.
338    pub frequency_hz: u32,
339    /// The settings to transmit with.
340    pub link: LinkSettings,
341}
342
343/// What a forwarded packet turned out to be.
344#[derive(Clone, Debug, PartialEq)]
345pub enum Event {
346    /// A device joined, and the accept is ready to transmit.
347    Joined {
348        /// The device that joined.
349        dev_eui: [u8; 8],
350        /// The address it was granted.
351        dev_addr: u32,
352        /// The accept, timed for the join window.
353        accept: Txpk,
354    },
355    /// A session frame arrived, decrypted.
356    Data {
357        /// The address it came from.
358        dev_addr: u32,
359        /// The counter it carried, reconstructed to its full width.
360        fcnt: u32,
361        /// The port it was sent on, absent for a frame carrying only MAC options.
362        fport: Option<u8>,
363        /// What the device sent.
364        payload: Vec<u8>,
365        /// Whether the device asked to be acknowledged.
366        confirmed: bool,
367        /// Where an answer would go.
368        slot: Slot,
369    },
370    /// A data frame for an address this network has not granted, which is another
371    /// network's traffic and is not an error.
372    Foreign {
373        /// The address the frame carried.
374        dev_addr: u32,
375    },
376}
377
378/// What can go wrong admitting or reading a forwarded packet.
379#[derive(Clone, Debug, PartialEq, Eq)]
380pub enum NetworkError {
381    /// The packet was not LoRa, so it carries no LoRaWAN frame here.
382    NotLora,
383    /// The frame did not parse, verify, or decrypt.
384    Frame(LorawanError),
385    /// A join request that no registered key verifies.
386    UnknownDevice,
387    /// A frame at a counter already seen, which is a replay.
388    Replayed {
389        /// The address it claimed.
390        dev_addr: u32,
391        /// The counter it carried.
392        fcnt: u32,
393    },
394    /// A frame further ahead of the counter last seen than [`MAX_FCNT_GAP`] allows.
395    CounterGap {
396        /// The address it claimed.
397        dev_addr: u32,
398        /// The counter last accepted.
399        seen: u32,
400        /// The counter it carried.
401        carried: u32,
402    },
403    /// The plan names no data rate for the settings the packet arrived at, so the rate the
404    /// first window answers at cannot be worked out.
405    UnknownDataRate,
406    /// No first receive window exists for the packet: its frequency is not a channel the
407    /// plan defines, or the plan names no downlink rate at that offset.
408    NoWindow,
409    /// A downlink for an address this network holds no session for.
410    NoSession {
411        /// The address asked for.
412        dev_addr: u32,
413    },
414}
415
416impl core::fmt::Display for NetworkError {
417    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
418        match self {
419            NetworkError::NotLora => f.write_str("the packet was not LoRa"),
420            NetworkError::Frame(error) => write!(f, "the frame was refused: {error}"),
421            NetworkError::UnknownDevice => {
422                f.write_str("no registered key verifies the join request")
423            }
424            NetworkError::Replayed { dev_addr, fcnt } => {
425                write!(f, "frame {fcnt} from {dev_addr:#010x} was already seen")
426            }
427            NetworkError::CounterGap {
428                dev_addr,
429                seen,
430                carried,
431            } => write!(
432                f,
433                "frame {carried} from {dev_addr:#010x} runs too far ahead of {seen}"
434            ),
435            NetworkError::UnknownDataRate => {
436                f.write_str("the plan names no data rate for the settings heard")
437            }
438            NetworkError::NoWindow => f.write_str("the plan defines no first receive window"),
439            NetworkError::NoSession { dev_addr } => {
440                write!(f, "no session for {dev_addr:#010x}")
441            }
442        }
443    }
444}
445
446impl core::error::Error for NetworkError {}
447
448// A device that has joined: the session that was granted, and the counters seen since.
449struct Admitted {
450    dev_eui: [u8; 8],
451    dev_addr: u32,
452    session: Session,
453    fcnt_up: Option<u32>,
454    fcnt_down: u32,
455}
456
457/// The network side of one site.
458///
459/// It admits the devices it is told about, grants sessions, follows frame counters, and
460/// decides where an answer goes. Everything it needs about the band comes from the
461/// [`ChannelPlan`] it is built with, so the same type serves any region.
462pub struct Network {
463    plan: OwnedChannelPlan,
464    windows: Windows,
465    net_id: u32,
466    registrations: Vec<Registration>,
467    admitted: Vec<Admitted>,
468    next_dev_addr: u32,
469    next_app_nonce: u32,
470}
471
472impl Network {
473    /// Builds a network on a channel plan.
474    ///
475    /// The plan is copied into the network, so one holds its band for as long as it runs
476    /// rather than borrowing a table that lives somewhere else.
477    ///
478    /// # Arguments
479    ///
480    /// * `plan` - the band this site operates in.
481    /// * `net_id` - the network identifier granted addresses carry; only its low 24 bits
482    ///   travel.
483    ///
484    /// # Returns
485    ///
486    /// The network, with the recommended windows and no devices registered.
487    pub fn new(plan: &ChannelPlan<'_>, net_id: u32) -> Network {
488        Network {
489            plan: OwnedChannelPlan::from_plan(plan),
490            windows: Windows::new(),
491            net_id,
492            registrations: Vec::new(),
493            admitted: Vec::new(),
494            next_dev_addr: 1,
495            next_app_nonce: 1,
496        }
497    }
498
499    /// Sets the windows this network answers in.
500    ///
501    /// # Arguments
502    ///
503    /// * `windows` - the delays, offset, and channels.
504    ///
505    /// # Returns
506    ///
507    /// The updated network, for chaining.
508    pub fn with_windows(mut self, windows: Windows) -> Network {
509        self.windows = windows;
510        self
511    }
512
513    /// Sets the first address this network grants; later joins take the ones after it.
514    ///
515    /// # Arguments
516    ///
517    /// * `dev_addr` - the address to grant next.
518    ///
519    /// # Returns
520    ///
521    /// The updated network, for chaining.
522    pub fn with_first_dev_addr(mut self, dev_addr: u32) -> Network {
523        self.next_dev_addr = dev_addr;
524        self
525    }
526
527    /// Admits a device, so a join request signed with its key is accepted.
528    ///
529    /// # Arguments
530    ///
531    /// * `registration` - the device and its root key.
532    pub fn register(&mut self, registration: Registration) {
533        self.registrations.push(registration);
534    }
535
536    /// Returns the windows this network answers in.
537    ///
538    /// # Returns
539    ///
540    /// The windows.
541    pub const fn windows(&self) -> Windows {
542        self.windows
543    }
544
545    /// Returns the session granted to an address, once a device has joined.
546    ///
547    /// # Arguments
548    ///
549    /// * `dev_addr` - the address.
550    ///
551    /// # Returns
552    ///
553    /// The session, or `None` if no device holds that address here.
554    pub fn session(&self, dev_addr: u32) -> Option<Session> {
555        self.admitted
556            .iter()
557            .find(|held| held.dev_addr == dev_addr)
558            .map(|held| held.session)
559    }
560
561    /// Reads a packet the gateway forwarded.
562    ///
563    /// A join request is verified against every registered key, granted an address and a
564    /// session, and answered with an accept timed for the join window. A data frame is
565    /// routed by its address, checked against the counter last seen, and decrypted. A frame
566    /// for an address this network has not granted is reported rather than refused, because
567    /// a gateway hears every network in range.
568    ///
569    /// # Arguments
570    ///
571    /// * `heard` - the packet as the gateway reported it.
572    ///
573    /// # Returns
574    ///
575    /// What the packet turned out to be.
576    ///
577    /// # Errors
578    ///
579    /// Returns [`NetworkError::NotLora`] for an FSK packet, [`NetworkError::Frame`] if the
580    /// frame does not parse or its MIC does not verify, [`NetworkError::UnknownDevice`] if
581    /// no registered key verifies a join request, [`NetworkError::Replayed`] or
582    /// [`NetworkError::CounterGap`] if the counter is not one this network will follow, and
583    /// [`NetworkError::UnknownDataRate`] or [`NetworkError::NoWindow`] if the plan does not
584    /// describe where to answer.
585    pub fn uplink(&mut self, heard: &Rxpk) -> Result<Event, NetworkError> {
586        let link = heard.modulation.link().ok_or(NetworkError::NotLora)?;
587        let header = FrameHeader::parse(&heard.payload).map_err(NetworkError::Frame)?;
588
589        match header.message_type() {
590            MessageType::JoinRequest => self.admit(heard, link),
591            MessageType::UnconfirmedUp | MessageType::ConfirmedUp => {
592                self.receive(heard, link, &header)
593            }
594            other => Err(NetworkError::Frame(LorawanError::UnsupportedMType(
595                downlink_mtype(other),
596            ))),
597        }
598    }
599
600    /// Builds a downlink for a device, encrypted with its session.
601    ///
602    /// # Arguments
603    ///
604    /// * `dev_addr` - the device to answer.
605    /// * `slot` - where and when to transmit, from the event that reported the uplink.
606    /// * `fport` - the port to answer on.
607    /// * `payload` - what to send.
608    ///
609    /// # Returns
610    ///
611    /// The packet to put in a `PULL_RESP`, with the inverted polarity a device listens for.
612    ///
613    /// # Errors
614    ///
615    /// Returns [`NetworkError::NoSession`] if no device holds that address here, or
616    /// [`NetworkError::Frame`] if the payload does not fit a single frame.
617    pub fn answer(
618        &mut self,
619        dev_addr: u32,
620        slot: Slot,
621        fport: u8,
622        payload: &[u8],
623    ) -> Result<Txpk, NetworkError> {
624        let held = self
625            .admitted
626            .iter_mut()
627            .find(|held| held.dev_addr == dev_addr)
628            .ok_or(NetworkError::NoSession { dev_addr })?;
629
630        let frame = held
631            .session
632            .encode_downlink(&Downlink::new(held.fcnt_down, fport, payload))
633            .map_err(NetworkError::Frame)?;
634        held.fcnt_down = held.fcnt_down.wrapping_add(1);
635
636        Ok(transmit(slot, frame.as_bytes().to_vec()))
637    }
638
639    // Verifies a join request against every registered key, grants a session, and answers.
640    fn admit(&mut self, heard: &Rxpk, link: LinkSettings) -> Result<Event, NetworkError> {
641        let (registration, request) = self
642            .registrations
643            .iter()
644            .find_map(|registration| {
645                let request = JoinRequest::parse(&heard.payload, &registration.app_key).ok()?;
646                (request.dev_eui() == registration.dev_eui).then_some((*registration, request))
647            })
648            .ok_or(NetworkError::UnknownDevice)?;
649
650        let dev_addr = self.next_dev_addr;
651        let app_nonce = self.next_app_nonce;
652        let grant = JoinGrant::new(app_nonce, self.net_id, dev_addr)
653            .with_dl_settings(
654                self.windows
655                    .dl_settings_byte(self.plan.with_plan(|plan| plan.rx2_data_rate)),
656            )
657            .with_rx_delay(self.windows.rx_delay_byte());
658        let accept = grant.accept(&registration.app_key, request.dev_nonce());
659        let session = grant.session(&registration.app_key, request.dev_nonce());
660
661        self.next_dev_addr = self.next_dev_addr.wrapping_add(1);
662        self.next_app_nonce = self.next_app_nonce.wrapping_add(1);
663        self.admitted
664            .retain(|held| held.dev_eui != registration.dev_eui);
665        self.admitted.push(Admitted {
666            dev_eui: registration.dev_eui,
667            dev_addr,
668            session,
669            fcnt_up: None,
670            fcnt_down: 0,
671        });
672
673        let slot = self.slot(heard, link, self.windows.join_delay_us)?;
674        Ok(Event::Joined {
675            dev_eui: registration.dev_eui,
676            dev_addr,
677            accept: transmit(slot, accept.as_bytes().to_vec()),
678        })
679    }
680
681    // Routes a data frame to its session, follows its counter, and decrypts it.
682    fn receive(
683        &mut self,
684        heard: &Rxpk,
685        link: LinkSettings,
686        header: &FrameHeader,
687    ) -> Result<Event, NetworkError> {
688        let dev_addr = header
689            .dev_addr()
690            .ok_or(NetworkError::Frame(LorawanError::MalformedFrame))?;
691        let carried = header
692            .fcnt()
693            .ok_or(NetworkError::Frame(LorawanError::MalformedFrame))?;
694        let slot = self.slot(heard, link, self.windows.receive_delay_us)?;
695
696        let Some(held) = self
697            .admitted
698            .iter_mut()
699            .find(|held| held.dev_addr == dev_addr)
700        else {
701            return Ok(Event::Foreign { dev_addr });
702        };
703
704        let fcnt = match held.fcnt_up {
705            None => u32::from(carried),
706            Some(seen) => {
707                let mut candidate = (seen & 0xFFFF_0000) | u32::from(carried);
708                // The counter already accepted, sent again.
709                if candidate == seen {
710                    return Err(NetworkError::Replayed {
711                        dev_addr,
712                        fcnt: candidate,
713                    });
714                }
715                // Only the low sixteen bits travel, so a counter below the one last seen is
716                // the device having wrapped rather than having gone backwards.
717                if candidate < seen {
718                    candidate = candidate.wrapping_add(0x0001_0000);
719                }
720                if candidate - seen > MAX_FCNT_GAP {
721                    return Err(NetworkError::CounterGap {
722                        dev_addr,
723                        seen,
724                        carried: candidate,
725                    });
726                }
727                candidate
728            }
729        };
730
731        let data = held
732            .session
733            .decode(&heard.payload, fcnt)
734            .map_err(NetworkError::Frame)?;
735        held.fcnt_up = Some(fcnt);
736
737        Ok(Event::Data {
738            dev_addr,
739            fcnt,
740            fport: data.fport(),
741            payload: data.payload().to_vec(),
742            confirmed: data.confirmed(),
743            slot,
744        })
745    }
746
747    // Works out where and when the first receive window opens for a packet.
748    fn slot(&self, heard: &Rxpk, link: LinkSettings, delay_us: u32) -> Result<Slot, NetworkError> {
749        let uplink_rate = self
750            .data_rate_of(link)
751            .ok_or(NetworkError::UnknownDataRate)?;
752        let settings = self
753            .plan
754            .with_plan(|plan| {
755                plan.rx1_data_rate(uplink_rate, self.windows.rx1_data_rate_offset)
756                    .and_then(|downlink_rate| plan.link_settings(downlink_rate))
757            })
758            .ok_or(NetworkError::NoWindow)?;
759
760        Ok(Slot {
761            timestamp_us: heard.timestamp_us.unwrap_or(0).wrapping_add(delay_us),
762            frequency_hz: self.rx1_frequency_hz(heard.frequency_hz)?,
763            link: settings,
764        })
765    }
766
767    // Applies the region's rule for which channel the first window answers on.
768    fn rx1_frequency_hz(&self, uplink_hz: u32) -> Result<u32, NetworkError> {
769        match self.windows.rx1_channels {
770            Rx1Channels::SameAsUplink => Ok(uplink_hz),
771            Rx1Channels::Downstream(block) => {
772                let channel = self.channel_of(uplink_hz).ok_or(NetworkError::NoWindow)?;
773                block
774                    .frequency_hz(channel % block.count)
775                    .ok_or(NetworkError::NoWindow)
776            }
777        }
778    }
779
780    // Finds which channel of the plan a frequency is, counting through the default blocks
781    // in the order the channel numbering follows.
782    fn channel_of(&self, frequency_hz: u32) -> Option<u16> {
783        self.plan.with_plan(|plan| {
784            let mut first = 0u16;
785            for block in plan.default_channels {
786                for index in 0..block.count {
787                    if block.frequency_hz(index) == Some(frequency_hz) {
788                        return Some(first + index);
789                    }
790                }
791                first += block.count;
792            }
793            None
794        })
795    }
796
797    // Finds the data rate number whose settings a packet arrived with. Only the spreading
798    // factor and the bandwidth name a rate; the coding rate and the frame options a radio
799    // reports alongside them do not.
800    fn data_rate_of(&self, link: LinkSettings) -> Option<u8> {
801        self.plan.with_plan(|plan| {
802            plan.uplink_data_rates
803                .iter()
804                .enumerate()
805                .find_map(|(number, rate)| {
806                    let settings = rate.as_ref()?.link_settings()?;
807                    (settings.spreading_factor() == link.spreading_factor()
808                        && settings.bandwidth_hz() == link.bandwidth_hz())
809                    .then_some(number as u8)
810                })
811        })
812    }
813}
814
815// The packet a downlink goes out as: at the window, with the polarity a device listens for.
816fn transmit(slot: Slot, payload: Vec<u8>) -> Txpk {
817    Txpk::at(slot.timestamp_us, slot.frequency_hz, slot.link, payload).with_inverted_polarity(true)
818}
819
820// The MHDR byte a message type carries, for reporting one that is not an uplink.
821const fn downlink_mtype(message_type: MessageType) -> u8 {
822    match message_type {
823        MessageType::JoinRequest => 0x00,
824        MessageType::JoinAccept => 0x20,
825        MessageType::UnconfirmedUp => 0x40,
826        MessageType::UnconfirmedDown => 0x60,
827        MessageType::ConfirmedUp => 0x80,
828        MessageType::ConfirmedDown => 0xA0,
829    }
830}
831
832#[cfg(test)]
833mod tests {
834    use super::*;
835
836    use pamoja_lora::region::Region;
837    use pamoja_lorawan::Device;
838
839    const DEV_EUI: [u8; 8] = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77];
840    const APP_EUI: [u8; 8] = [0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x00, 0x00, 0x01];
841    const APP_KEY: [u8; 16] = [
842        0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F,
843        0x3C,
844    ];
845
846    fn site() -> Network {
847        let mut network =
848            Network::new(Region::Eu868.plan(), 0x00_00_2A).with_first_dev_addr(0x2601_0001);
849        network.register(Registration::new(DEV_EUI, APP_EUI, APP_KEY));
850        network
851    }
852
853    fn heard(frame: Vec<u8>, timestamp_us: u32) -> Rxpk {
854        Rxpk::new(868_100_000, LinkSettings::new(7, 125_000), frame).with_timestamp_us(timestamp_us)
855    }
856
857    #[test]
858    fn the_recommended_delays_are_the_published_ones() {
859        // RP002-1.0.5 section 3.3: RECEIVE_DELAY1 1s, RECEIVE_DELAY2 2s, JOIN_ACCEPT_DELAY1
860        // 5s, JOIN_ACCEPT_DELAY2 6s.
861        assert_eq!(RECEIVE_DELAY1_US, 1_000_000);
862        assert_eq!(RECEIVE_DELAY2_US, 2_000_000);
863        assert_eq!(JOIN_ACCEPT_DELAY1_US, 5_000_000);
864        assert_eq!(JOIN_ACCEPT_DELAY2_US, 6_000_000);
865        assert_eq!(MAX_FCNT_GAP, 16_384);
866    }
867
868    #[test]
869    fn the_join_accept_bytes_follow_the_specification() {
870        // TS001-1.0.4 table 55: RFU, then RX1DROffset in bits 6:4, then RX2DataRate in 3:0.
871        let windows = Windows::new().with_rx1_data_rate_offset(5);
872        assert_eq!(windows.dl_settings_byte(0), 0x50);
873        assert_eq!(windows.dl_settings_byte(0x0F), 0x5F);
874        assert_eq!(Windows::new().dl_settings_byte(8), 0x08);
875
876        // TS001-1.0.4 table 44: the delay in seconds in the low four bits, and a zero there
877        // means one second.
878        assert_eq!(Windows::new().rx_delay_byte(), 1);
879        assert_eq!(
880            Windows::new()
881                .with_receive_delay_us(5_000_000)
882                .rx_delay_byte(),
883            5
884        );
885    }
886
887    #[test]
888    fn a_registration_never_prints_its_key() {
889        let printed = format!("{:?}", Registration::new(DEV_EUI, APP_EUI, APP_KEY));
890        assert!(printed.contains("dev_eui"));
891        assert!(!printed.contains("2b") && !printed.contains("43"));
892    }
893
894    #[test]
895    fn a_device_joins_and_is_answered_in_the_join_window() {
896        let mut network = site();
897        let device = Device::new(DEV_EUI, APP_EUI, APP_KEY);
898        let request = device.join_request(0x0102);
899
900        let event = network
901            .uplink(&heard(request.as_bytes().to_vec(), 1_000_000))
902            .expect("the request verifies");
903
904        let Event::Joined {
905            dev_eui,
906            dev_addr,
907            accept,
908        } = event
909        else {
910            panic!("a join request is admitted");
911        };
912        assert_eq!(dev_eui, DEV_EUI);
913        assert_eq!(dev_addr, 0x2601_0001);
914        // Five seconds after the uplink, on the uplink frequency, with inverted polarity.
915        assert_eq!(accept.timestamp_us, Some(6_000_000));
916        assert_eq!(accept.frequency_hz, 868_100_000);
917        assert!(accept.invert_polarity);
918
919        // The device reads the accept it was sent and derives the same session.
920        let granted = device
921            .accept_join(&accept.payload, 0x0102)
922            .expect("the accept verifies");
923        assert_eq!(granted.dev_addr(), 0x2601_0001);
924    }
925
926    #[test]
927    fn an_uplink_is_decrypted_and_answered_one_second_later() {
928        let mut network = site();
929        let device = Device::new(DEV_EUI, APP_EUI, APP_KEY);
930        let request = device.join_request(0x0102);
931        let Event::Joined { accept, .. } = network
932            .uplink(&heard(request.as_bytes().to_vec(), 1_000_000))
933            .expect("the request verifies")
934        else {
935            panic!("a join request is admitted");
936        };
937        let session = device
938            .accept_join(&accept.payload, 0x0102)
939            .expect("the accept verifies")
940            .session();
941
942        let frame = session
943            .encode_uplink(&pamoja_lorawan::Uplink::new(0, 2, b"21.5"))
944            .expect("it fits one frame");
945        let event = network
946            .uplink(&heard(frame.as_bytes().to_vec(), 9_000_000))
947            .expect("the frame verifies");
948
949        let Event::Data {
950            dev_addr,
951            fcnt,
952            fport,
953            payload,
954            confirmed,
955            slot,
956        } = event
957        else {
958            panic!("a data frame is read");
959        };
960        assert_eq!(dev_addr, 0x2601_0001);
961        assert_eq!(fcnt, 0);
962        assert_eq!(fport, Some(2));
963        assert_eq!(payload, b"21.5");
964        assert!(!confirmed);
965        assert_eq!(slot.timestamp_us, 10_000_000);
966        assert_eq!(slot.frequency_hz, 868_100_000);
967        assert_eq!(slot.link.spreading_factor(), 7);
968
969        // The answer goes out in that window, and the device reads it.
970        let downlink = network
971            .answer(dev_addr, slot, 2, b"ok")
972            .expect("the session is held");
973        assert_eq!(downlink.timestamp_us, Some(10_000_000));
974        assert!(downlink.invert_polarity);
975        let read = session.decode(&downlink.payload, 0).expect("it verifies");
976        assert_eq!(read.payload(), b"ok");
977    }
978
979    #[test]
980    fn a_replayed_frame_is_refused() {
981        let mut network = site();
982        let device = Device::new(DEV_EUI, APP_EUI, APP_KEY);
983        let request = device.join_request(0x0102);
984        let Event::Joined { accept, .. } = network
985            .uplink(&heard(request.as_bytes().to_vec(), 1_000_000))
986            .expect("the request verifies")
987        else {
988            panic!("a join request is admitted");
989        };
990        let session = device
991            .accept_join(&accept.payload, 0x0102)
992            .expect("the accept verifies")
993            .session();
994
995        let first = session
996            .encode_uplink(&pamoja_lorawan::Uplink::new(1, 2, b"one"))
997            .expect("it fits one frame");
998        network
999            .uplink(&heard(first.as_bytes().to_vec(), 2_000_000))
1000            .expect("the first frame is read");
1001
1002        let error = network
1003            .uplink(&heard(first.as_bytes().to_vec(), 3_000_000))
1004            .expect_err("the same counter twice is a replay");
1005        assert!(matches!(
1006            error,
1007            NetworkError::Replayed {
1008                dev_addr: 0x2601_0001,
1009                ..
1010            }
1011        ));
1012    }
1013
1014    #[test]
1015    fn a_counter_that_wraps_carries_on_where_it_left_off() {
1016        let mut network = site();
1017        let device = Device::new(DEV_EUI, APP_EUI, APP_KEY);
1018        let request = device.join_request(0x0102);
1019        let Event::Joined { accept, .. } = network
1020            .uplink(&heard(request.as_bytes().to_vec(), 1_000_000))
1021            .expect("the request verifies")
1022        else {
1023            panic!("a join request is admitted");
1024        };
1025        let session = device
1026            .accept_join(&accept.payload, 0x0102)
1027            .expect("the accept verifies")
1028            .session();
1029
1030        // The last counter the low sixteen bits can hold, then the one after it.
1031        let last = session
1032            .encode_uplink(&pamoja_lorawan::Uplink::new(0xFFFF, 2, b"last"))
1033            .expect("it fits one frame");
1034        network
1035            .uplink(&heard(last.as_bytes().to_vec(), 2_000_000))
1036            .expect("the frame is read");
1037
1038        let wrapped = session
1039            .encode_uplink(&pamoja_lorawan::Uplink::new(0x0001_0000, 2, b"next"))
1040            .expect("it fits one frame");
1041        let event = network
1042            .uplink(&heard(wrapped.as_bytes().to_vec(), 3_000_000))
1043            .expect("the wrapped frame is read");
1044
1045        let Event::Data { fcnt, payload, .. } = event else {
1046            panic!("a data frame is read");
1047        };
1048        assert_eq!(fcnt, 0x0001_0000);
1049        assert_eq!(payload, b"next");
1050    }
1051
1052    #[test]
1053    fn a_frame_for_another_network_is_reported_not_refused() {
1054        let mut network = site();
1055        let stranger = Session::new(0x1234_5678, [9; 16], [8; 16]);
1056        let frame = stranger
1057            .encode_uplink(&pamoja_lorawan::Uplink::new(0, 1, b"hello"))
1058            .expect("it fits one frame");
1059
1060        let event = network
1061            .uplink(&heard(frame.as_bytes().to_vec(), 1_000_000))
1062            .expect("a frame from elsewhere is not an error");
1063        assert_eq!(
1064            event,
1065            Event::Foreign {
1066                dev_addr: 0x1234_5678
1067            }
1068        );
1069    }
1070
1071    #[test]
1072    fn the_first_window_follows_the_region() {
1073        // RP002-1.0.5 section 3.5.7: RX1 Channel Number = Transmit Channel Number modulo
1074        // NbChannel, over the eight downlink channels of section 3.5.2.
1075        let block = match Rx1Channels::us915() {
1076            Rx1Channels::Downstream(block) => block,
1077            Rx1Channels::SameAsUplink => panic!("US902-928 answers on its own channels"),
1078        };
1079        assert_eq!(block.frequency_hz(0), Some(923_300_000));
1080        assert_eq!(block.frequency_hz(7), Some(927_500_000));
1081        assert_eq!(block.count, 8);
1082    }
1083
1084    #[test]
1085    fn an_fsk_packet_carries_no_frame() {
1086        let mut network = site();
1087        let mut packet = heard(vec![0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0);
1088        packet.modulation = crate::udp::Modulation::Fsk(50_000);
1089        assert_eq!(network.uplink(&packet), Err(NetworkError::NotLora));
1090    }
1091}