1use crate::{region, AppSKey, Downlink, NewSKey};
2use heapless::Vec;
3use lorawan::keys::CryptoFactory;
4use lorawan::maccommands::{DownlinkMacCommand, MacCommandIterator};
5use lorawan::{
6 creator::DataPayloadCreator,
7 maccommands::SerializableMacCommand,
8 parser::{parse_with_factory as lorawan_parse, *},
9 parser::{DecryptedJoinAcceptPayload, DevAddr},
10};
11
12use generic_array::{typenum::U256, GenericArray};
13
14use crate::radio::RadioBuffer;
15
16use super::{
17 otaa::{DevNonce, NetworkCredentials},
18 uplink, FcntUp, Response, SendData,
19};
20
21#[derive(Clone, Debug)]
22#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24pub struct Session {
25 pub uplink: uplink::Uplink,
26 pub confirmed: bool,
27 pub newskey: NewSKey,
28 pub appskey: AppSKey,
29 pub devaddr: DevAddr<[u8; 4]>,
30 pub fcnt_up: u32,
31 pub fcnt_down: u32,
32}
33
34#[derive(Clone, Debug)]
35#[cfg_attr(feature = "defmt", derive(defmt::Format))]
36pub struct SessionKeys {
37 pub newskey: NewSKey,
38 pub appskey: AppSKey,
39 pub devaddr: DevAddr<[u8; 4]>,
40}
41
42impl From<Session> for SessionKeys {
43 fn from(session: Session) -> Self {
44 Self { newskey: session.newskey, appskey: session.appskey, devaddr: session.devaddr }
45 }
46}
47
48impl Session {
49 pub fn derive_new<T: AsRef<[u8]>, F: CryptoFactory>(
50 decrypt: &DecryptedJoinAcceptPayload<T, F>,
51 devnonce: DevNonce,
52 credentials: &NetworkCredentials,
53 ) -> Self {
54 Self::new(
55 decrypt.derive_newskey(&devnonce, credentials.appkey()),
56 decrypt.derive_appskey(&devnonce, credentials.appkey()),
57 DevAddr::new([
58 decrypt.dev_addr().as_ref()[0],
59 decrypt.dev_addr().as_ref()[1],
60 decrypt.dev_addr().as_ref()[2],
61 decrypt.dev_addr().as_ref()[3],
62 ])
63 .unwrap(),
64 )
65 }
66
67 pub fn new(newskey: NewSKey, appskey: AppSKey, devaddr: DevAddr<[u8; 4]>) -> Self {
68 Self {
69 newskey,
70 appskey,
71 devaddr,
72 confirmed: false,
73 fcnt_down: 0,
74 fcnt_up: 0,
75 uplink: uplink::Uplink::default(),
76 }
77 }
78
79 pub fn devaddr(&self) -> &DevAddr<[u8; 4]> {
80 &self.devaddr
81 }
82 pub fn appskey(&self) -> &AppSKey {
83 &self.appskey
84 }
85 pub fn newskey(&self) -> &NewSKey {
86 &self.newskey
87 }
88
89 pub fn get_session_keys(&self) -> Option<SessionKeys> {
90 Some(SessionKeys { newskey: self.newskey, appskey: self.appskey, devaddr: self.devaddr })
91 }
92}
93
94impl Session {
95 pub(crate) fn handle_rx<C: CryptoFactory + Default, const N: usize, const D: usize>(
96 &mut self,
97 region: &mut region::Configuration,
98 configuration: &mut super::Configuration,
99 rx: &mut RadioBuffer<N>,
100 dl: &mut Vec<Downlink, D>,
101 ignore_mac: bool,
102 ) -> Response {
103 if let Ok(PhyPayload::Data(DataPayload::Encrypted(encrypted_data))) =
104 lorawan_parse(rx.as_mut_for_read(), C::default())
105 {
106 if self.devaddr() == &encrypted_data.fhdr().dev_addr() {
107 let fcnt = encrypted_data.fhdr().fcnt() as u32;
108 let confirmed = encrypted_data.is_confirmed();
109 if encrypted_data.validate_mic(self.newskey().inner(), fcnt)
110 && (fcnt > self.fcnt_down || fcnt == 0)
111 {
112 self.fcnt_down = fcnt;
113 let decrypted = encrypted_data
115 .decrypt(
116 Some(self.newskey().inner()),
117 Some(self.appskey().inner()),
118 self.fcnt_down,
119 )
120 .unwrap();
121
122 if !ignore_mac {
123 configuration.handle_downlink_macs(
125 region,
126 &mut self.uplink,
127 MacCommandIterator::<DownlinkMacCommand>::new(decrypted.fhdr().data()),
128 );
129 if let FRMPayload::MACCommands(mac_cmds) = decrypted.frm_payload() {
130 configuration.handle_downlink_macs(
131 region,
132 &mut self.uplink,
133 MacCommandIterator::<DownlinkMacCommand>::new(mac_cmds.data()),
134 );
135 }
136 }
137
138 if confirmed {
139 self.uplink.set_downlink_confirmation();
140 }
141
142 return if self.fcnt_up == 0xFFFF_FFFF {
143 Response::SessionExpired
145 } else {
146 self.fcnt_up += 1;
148 if let (Some(fport), FRMPayload::Data(data)) =
149 (decrypted.f_port(), decrypted.frm_payload())
150 {
151 let data = Vec::from_slice(data).unwrap();
154 let _ = dl.push(Downlink { data, fport });
156 }
157 Response::DownlinkReceived(fcnt)
158 };
159 }
160 }
161 }
162 Response::NoUpdate
163 }
164
165 pub(crate) fn rx2_complete(&mut self) -> Response {
166 if self.fcnt_up == 0xFFFF_FFFF {
168 return Response::SessionExpired;
170 } else {
171 self.fcnt_up += 1;
172 }
173 if self.confirmed {
174 Response::NoAck
175 } else {
176 Response::RxComplete
177 }
178 }
179
180 pub(crate) fn prepare_buffer<C: CryptoFactory + Default, const N: usize>(
181 &mut self,
182 data: &SendData,
183 tx_buffer: &mut RadioBuffer<N>,
184 ) -> FcntUp {
185 tx_buffer.clear();
186 let fcnt = self.fcnt_up;
187 let mut phy: DataPayloadCreator<GenericArray<u8, U256>, C> = DataPayloadCreator::default();
188
189 let mut fctrl = FCtrl(0x0, true);
190 if self.uplink.confirms_downlink() {
191 fctrl.set_ack();
192 self.uplink.clear_downlink_confirmation();
193 }
194
195 self.confirmed = data.confirmed;
196
197 phy.set_confirmed(data.confirmed)
198 .set_fctrl(&fctrl)
199 .set_f_port(data.fport)
200 .set_dev_addr(self.devaddr)
201 .set_fcnt(fcnt);
202
203 let mut cmds = Vec::new();
204 self.uplink.get_cmds(&mut cmds);
205 let mut dyn_cmds: Vec<&dyn SerializableMacCommand, 8> = Vec::new();
206
207 for cmd in &cmds {
208 if let Err(_e) = dyn_cmds.push(cmd) {
209 panic!("dyn_cmds too small compared to cmds")
210 }
211 }
212
213 match phy.build(data.data, dyn_cmds.as_slice(), &self.newskey, &self.appskey) {
214 Ok(packet) => {
215 tx_buffer.clear();
216 tx_buffer.extend_from_slice(packet).unwrap();
217 }
218 Err(e) => panic!("Error assembling packet! {:?} ", e),
219 }
220 fcnt
221 }
222}