Use Device.device_session field for DS (WIP).

This is work-in-progress, still need to refactor all the tests.
This commit is contained in:
Orne Brocaar 2024-02-21 13:30:08 +00:00
parent fae182aa3d
commit da6b7e1b37
35 changed files with 946 additions and 857 deletions

1
Cargo.lock generated
View File

@ -876,6 +876,7 @@ dependencies = [
name = "chirpstack_api"
version = "4.7.0-test.3"
dependencies = [
"diesel",
"hex",
"pbjson",
"pbjson-build",

View File

@ -7,15 +7,9 @@ import "gw/gw.proto";
import "google/protobuf/timestamp.proto";
message DeviceSession {
// Device EUI.
bytes dev_eui = 1;
// Device address.
bytes dev_addr = 2;
// Join EUI.
bytes join_eui = 3;
// LoRaWAN mac-version.
common.MacVersion mac_version = 4;

2
api/rust/Cargo.toml vendored
View File

@ -12,6 +12,7 @@ edition = "2021"
default = ["api", "json"]
api = ["tonic/transport", "tonic-build/transport", "tokio"]
json = ["pbjson", "pbjson-types", "serde"]
diesel = ["dep:diesel"]
internal = []
[dependencies]
@ -25,6 +26,7 @@ tokio = { version = "1.32", features = ["macros"], optional = true }
pbjson = { version = "0.6", optional = true }
pbjson-types = { version = "0.6", optional = true }
serde = { version = "1.0", optional = true }
diesel = { version = "2.1", features = ["postgres_backend"], optional = true }
[build-dependencies]
tonic-build = { version = "0.10", features = ["prost"], default-features = false }

22
api/rust/build.rs vendored
View File

@ -73,13 +73,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
// internal
tonic_build::configure()
.out_dir(out_dir.join("internal"))
.file_descriptor_set_path(out_dir.join("internal").join("proto_descriptor.bin"))
.compile_well_known_types(true)
.extern_path(".google.protobuf", well_known_types_path)
.extern_path(".common", "crate::common")
.compile(
{
let mut builder = tonic_build::configure()
.out_dir(out_dir.join("internal"))
.file_descriptor_set_path(out_dir.join("internal").join("proto_descriptor.bin"))
.compile_well_known_types(true)
.extern_path(".google.protobuf", well_known_types_path)
.extern_path(".common", "crate::common");
#[cfg(feature = "diesel")]
{
builder = builder.message_attribute("internal.DeviceSession", "#[derive(diesel::expression::AsExpression, diesel::deserialize::FromSqlRow)] #[diesel(sql_type = diesel::sql_types::Binary)]");
}
builder.compile(
&[cs_dir
.join("internal")
.join("internal.proto")
@ -90,6 +97,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
proto_dir.join("google").to_str().unwrap(),
],
)?;
}
#[cfg(feature = "json")]
{

View File

@ -7,15 +7,9 @@ import "gw/gw.proto";
import "google/protobuf/timestamp.proto";
message DeviceSession {
// Device EUI.
bytes dev_eui = 1;
// Device address.
bytes dev_addr = 2;
// Join EUI.
bytes join_eui = 3;
// LoRaWAN mac-version.
common.MacVersion mac_version = 4;

View File

@ -2,6 +2,14 @@ include!(concat!(env!("OUT_DIR"), "/internal/internal.rs"));
#[cfg(feature = "json")]
include!(concat!(env!("OUT_DIR"), "/internal/internal.serde.rs"));
#[cfg(feature = "diesel")]
use std::io::Cursor;
#[cfg(feature = "diesel")]
use diesel::{backend::Backend, deserialize, serialize, sql_types::Binary};
#[cfg(feature = "diesel")]
use prost::Message;
impl DeviceSession {
pub fn get_a_f_cnt_down(&self) -> u32 {
if self.mac_version().to_string().starts_with("1.0") {
@ -23,3 +31,28 @@ impl DeviceSession {
}
}
}
#[cfg(feature = "diesel")]
impl<ST, DB> deserialize::FromSql<ST, DB> for DeviceSession
where
DB: Backend,
*const [u8]: deserialize::FromSql<ST, DB>,
{
fn from_sql(value: DB::RawValue<'_>) -> deserialize::Result<Self> {
let bytes = <Vec<u8> as deserialize::FromSql<ST, DB>>::from_sql(value)?;
Ok(DeviceSession::decode(&mut Cursor::new(bytes))?)
}
}
#[cfg(feature = "diesel")]
impl serialize::ToSql<Binary, diesel::pg::Pg> for DeviceSession
where
[u8]: serialize::ToSql<Binary, diesel::pg::Pg>,
{
fn to_sql<'b>(&self, out: &mut serialize::Output<'b, '_, diesel::pg::Pg>) -> serialize::Result {
<[u8] as serialize::ToSql<Binary, diesel::pg::Pg>>::to_sql(
&self.encode_to_vec(),
&mut out.reborrow(),
)
}
}

View File

@ -49,7 +49,7 @@ tracing-subscriber = { version = "0.3", features = [
], default-features = true }
# ChirpStack API definitions
chirpstack_api = { path = "../api/rust", features = ["default", "internal"] }
chirpstack_api = { path = "../api/rust", features = ["default", "internal", "diesel"] }
lrwn = { path = "../lrwn", features = ["serde", "diesel", "regions", "crypto"] }
backend = { path = "../backend" }

View File

@ -312,9 +312,10 @@ async fn _handle_pr_start_req_data(
};
// get device-session
let ds = device::get_for_phypayload(&mut ufs.phy_payload, ufs.dr, ufs.ch as u8).await?;
let d = device::get_for_phypayload(&mut ufs.phy_payload, ufs.dr, ufs.ch as u8).await?;
let pr_lifetime = roaming::get_passive_roaming_lifetime(sender_id)?;
let kek_label = roaming::get_passive_roaming_kek_label(sender_id)?;
let ds = d.get_device_session()?;
let nwk_s_key = if ds.mac_version().to_string().starts_with("1.0") {
Some(keywrap::wrap(
@ -343,7 +344,7 @@ async fn _handle_pr_start_req_data(
base: pl
.base
.to_base_payload_result(backend::ResultCode::Success, ""),
dev_eui: ds.dev_eui.clone(),
dev_eui: d.dev_eui.to_vec(),
lifetime: if pr_lifetime.is_zero() {
None
} else {

View File

@ -5,7 +5,6 @@ use std::time::SystemTime;
use bigdecimal::ToPrimitive;
use chrono::{DateTime, Local, Utc};
use prost::Message;
use tonic::{Request, Response, Status};
use uuid::Uuid;
@ -516,7 +515,6 @@ impl DeviceService for Device {
let mut ds = internal::DeviceSession {
region_config_id: "".to_string(),
dev_eui: dev_eui.to_vec(),
dev_addr: dev_addr.to_vec(),
mac_version: dp.mac_version.to_proto().into(),
s_nwk_s_int_key: s_nwk_s_int_key.to_vec(),
@ -535,7 +533,7 @@ impl DeviceService for Device {
dp.reset_session_to_boot_params(&mut ds);
let mut device_changeset = device::DeviceChangeset {
device_session: Some(Some(ds.encode_to_vec())),
device_session: Some(Some(ds)),
dev_addr: Some(Some(dev_addr)),
secondary_dev_addr: Some(None),
..Default::default()
@ -633,8 +631,8 @@ impl DeviceService for Device {
let mut resp = Response::new(api::GetDeviceActivationResponse {
device_activation: Some(api::DeviceActivation {
dev_eui: hex::encode(&ds.dev_eui),
dev_addr: hex::encode(&ds.dev_addr),
dev_eui: d.dev_eui.to_string(),
dev_addr: d.get_dev_addr().map_err(|e| e.status())?.to_string(),
app_s_key: match &ds.app_s_key {
Some(v) => hex::encode(&v.aes_key),
None => "".to_string(),
@ -1200,7 +1198,7 @@ impl DeviceService for Device {
let d = device::get(&dev_eui).await.map_err(|e| e.status())?;
let ds = match d.get_device_session() {
Ok(v) => v,
Ok(v) => v.clone(),
Err(StorageError::NotFound(_)) => Default::default(),
Err(e) => {
return Err(e.status());

View File

@ -1,23 +1,14 @@
use std::io::Cursor;
use anyhow::{Context, Result};
use prost::Message;
use crate::storage;
use crate::storage::device;
use chirpstack_api::internal;
use lrwn::EUI64;
pub async fn run(dev_eui: &EUI64) -> Result<()> {
storage::setup().await.context("Setup storage")?;
let d = device::get(dev_eui).await.context("Get device")?;
let ds = match d.device_session {
Some(v) => internal::DeviceSession::decode(&mut Cursor::new(&v))
.context("Decode device-session")?,
None => return Err(anyhow!("No device-session")),
};
let ds = d.get_device_session()?;
let json = serde_json::to_string_pretty(&ds)?;
println!("{}", json);

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,6 @@ pub struct JoinAccept<'a> {
relay_context: Option<&'a RelayContext>,
tenant: &'a tenant::Tenant,
device: &'a device::Device,
device_session: &'a internal::DeviceSession,
join_accept: &'a PhyPayload,
network_conf: config::RegionNetwork,
region_conf: Arc<Box<dyn lrwn::region::Region + Sync + Send>>,
@ -36,20 +35,12 @@ impl JoinAccept<'_> {
ufs: &UplinkFrameSet,
tenant: &tenant::Tenant,
device: &device::Device,
device_session: &internal::DeviceSession,
join_accept: &PhyPayload,
) -> Result<()> {
let downlink_id: u32 = rand::thread_rng().gen();
let span = span!(Level::INFO, "join_accept", downlink_id = downlink_id);
let fut = JoinAccept::_handle(
downlink_id,
ufs,
tenant,
device,
device_session,
join_accept,
);
let fut = JoinAccept::_handle(downlink_id, ufs, tenant, device, join_accept);
fut.instrument(span).await
}
@ -58,7 +49,6 @@ impl JoinAccept<'_> {
ufs: &UplinkFrameSet,
tenant: &tenant::Tenant,
device: &device::Device,
device_session: &internal::DeviceSession,
join_accept: &PhyPayload,
) -> Result<()> {
let downlink_id: u32 = rand::thread_rng().gen();
@ -68,15 +58,8 @@ impl JoinAccept<'_> {
downlink_id = downlink_id
);
let fut = JoinAccept::_handle_relayed(
downlink_id,
relay_ctx,
ufs,
tenant,
device,
device_session,
join_accept,
);
let fut =
JoinAccept::_handle_relayed(downlink_id, relay_ctx, ufs, tenant, device, join_accept);
fut.instrument(span).await
}
@ -85,7 +68,6 @@ impl JoinAccept<'_> {
ufs: &UplinkFrameSet,
tenant: &tenant::Tenant,
device: &device::Device,
device_session: &internal::DeviceSession,
join_accept: &PhyPayload,
) -> Result<()> {
let mut ctx = JoinAccept {
@ -93,7 +75,6 @@ impl JoinAccept<'_> {
relay_context: None,
tenant,
device,
device_session,
join_accept,
network_conf: config::get_region_network(&ufs.region_config_id)?,
region_conf: region::get(&ufs.region_config_id)?,
@ -122,7 +103,6 @@ impl JoinAccept<'_> {
ufs: &UplinkFrameSet,
tenant: &tenant::Tenant,
device: &device::Device,
device_session: &internal::DeviceSession,
join_accept: &PhyPayload,
) -> Result<()> {
let mut ctx = JoinAccept {
@ -130,7 +110,6 @@ impl JoinAccept<'_> {
relay_context: Some(relay_ctx),
tenant,
device,
device_session,
join_accept,
network_conf: config::get_region_network(&ufs.region_config_id)?,
region_conf: region::get(&ufs.region_config_id)?,
@ -302,6 +281,7 @@ impl JoinAccept<'_> {
let gw_down = self.downlink_gateway.as_ref().unwrap();
let relay_ctx = self.relay_context.unwrap();
let relay_ds = relay_ctx.device.get_device_session()?;
let mut tx_info = chirpstack_api::gw::DownlinkTxInfo {
board: gw_down.board,
@ -311,7 +291,7 @@ impl JoinAccept<'_> {
};
// Get RX1 DR offset.
let rx1_dr_offset = relay_ctx.device_session.rx1_dr_offset as usize;
let rx1_dr_offset = relay_ds.rx1_dr_offset as usize;
// get RX1 DR.
let rx1_dr_index = self
@ -337,8 +317,8 @@ impl JoinAccept<'_> {
}
// Set timestamp.
let delay = if relay_ctx.device_session.rx1_delay > 0 {
Duration::from_secs(relay_ctx.device_session.rx1_delay as u64)
let delay = if relay_ds.rx1_delay > 0 {
Duration::from_secs(relay_ds.rx1_delay as u64)
} else {
self.region_conf.get_defaults().rx1_delay
};
@ -415,9 +395,10 @@ impl JoinAccept<'_> {
let gw_down = self.downlink_gateway.as_ref().unwrap();
let relay_ctx = self.relay_context.unwrap();
let relay_ds = relay_ctx.device.get_device_session()?;
// Get frequency.
let frequency = relay_ctx.device_session.rx2_frequency;
let frequency = relay_ds.rx2_frequency;
let mut tx_info = chirpstack_api::gw::DownlinkTxInfo {
board: gw_down.board,
@ -428,7 +409,7 @@ impl JoinAccept<'_> {
};
// get RX2 DR
let rx2_dr_index = relay_ctx.device_session.rx2_dr as u8;
let rx2_dr_index = relay_ds.rx2_dr as u8;
let rx2_dr = self.region_conf.get_data_rate(rx2_dr_index)?;
// set DR to tx_info
@ -444,8 +425,8 @@ impl JoinAccept<'_> {
}
// Set timestamp.
let delay = if relay_ctx.device_session.rx1_delay > 0 {
Duration::from_secs(relay_ctx.device_session.rx1_delay as u64 + 1)
let delay = if relay_ds.rx1_delay > 0 {
Duration::from_secs(relay_ds.rx1_delay as u64 + 1)
} else {
self.region_conf.get_defaults().rx2_delay
};
@ -481,6 +462,7 @@ impl JoinAccept<'_> {
trace!("Setting ForwardDownlinkReq frame");
let relay_ctx = self.relay_context.as_ref().unwrap();
let relay_ds = relay_ctx.device.get_device_session()?;
let mut relay_phy = lrwn::PhyPayload {
mhdr: lrwn::MHDR {
@ -489,16 +471,11 @@ impl JoinAccept<'_> {
},
payload: lrwn::Payload::MACPayload(lrwn::MACPayload {
fhdr: lrwn::FHDR {
devaddr: lrwn::DevAddr::from_slice(&relay_ctx.device_session.dev_addr)?,
f_cnt: if relay_ctx
.device_session
.mac_version()
.to_string()
.starts_with("1.0")
{
relay_ctx.device_session.n_f_cnt_down
devaddr: relay_ctx.device.get_dev_addr()?,
f_cnt: if relay_ds.mac_version().to_string().starts_with("1.0") {
relay_ds.n_f_cnt_down
} else {
relay_ctx.device_session.a_f_cnt_down
relay_ds.a_f_cnt_down
},
f_ctrl: lrwn::FCtrl {
adr: !self.network_conf.adr_disabled,
@ -517,17 +494,15 @@ impl JoinAccept<'_> {
mic: None,
};
relay_phy.encrypt_frm_payload(&lrwn::AES128Key::from_slice(
&relay_ctx.device_session.nwk_s_enc_key,
)?)?;
relay_phy.encrypt_frm_payload(&lrwn::AES128Key::from_slice(&relay_ds.nwk_s_enc_key)?)?;
// Set MIC.
// If this is an ACK, then FCntUp has already been incremented by one. If
// this is not an ACK, then DownlinkDataMIC will zero out ConfFCnt.
relay_phy.set_downlink_data_mic(
relay_ctx.device_session.mac_version().from_proto(),
relay_ctx.device_session.f_cnt_up - 1,
&lrwn::AES128Key::from_slice(&relay_ctx.device_session.s_nwk_s_int_key)?,
relay_ds.mac_version().from_proto(),
relay_ds.f_cnt_up - 1,
&lrwn::AES128Key::from_slice(&relay_ds.s_nwk_s_int_key)?,
)?;
let relay_phy_b = relay_phy.to_vec()?;
@ -551,12 +526,13 @@ impl JoinAccept<'_> {
async fn save_downlink_frame(&self) -> Result<()> {
trace!("Saving downlink frame");
let ds = self.device.get_device_session()?;
let df = chirpstack_api::internal::DownlinkFrame {
dev_eui: self.device.dev_eui.to_be_bytes().to_vec(),
downlink_id: self.downlink_frame.downlink_id,
downlink_frame: Some(self.downlink_frame.clone()),
nwk_s_enc_key: self.device_session.nwk_s_enc_key.clone(),
nwk_s_enc_key: ds.nwk_s_enc_key.clone(),
..Default::default()
};
@ -571,14 +547,15 @@ impl JoinAccept<'_> {
trace!("Saving ForwardDownlinkReq frame");
let relay_ctx = self.relay_context.as_ref().unwrap();
let relay_ds = relay_ctx.device.get_device_session()?;
let df = chirpstack_api::internal::DownlinkFrame {
dev_eui: relay_ctx.device.dev_eui.to_be_bytes().to_vec(),
downlink_id: self.downlink_frame.downlink_id,
downlink_frame: Some(self.downlink_frame.clone()),
nwk_s_enc_key: relay_ctx.device_session.nwk_s_enc_key.clone(),
a_f_cnt_down: relay_ctx.device_session.get_a_f_cnt_down(),
n_f_cnt_down: relay_ctx.device_session.n_f_cnt_down,
nwk_s_enc_key: relay_ds.nwk_s_enc_key.clone(),
a_f_cnt_down: relay_ds.get_a_f_cnt_down(),
n_f_cnt_down: relay_ds.n_f_cnt_down,
..Default::default()
};

View File

@ -1,6 +1,5 @@
use anyhow::Result;
use chrono::{Duration, Utc};
use prost::Message;
use tracing::{error, info, span, trace, Instrument, Level};
use uuid::Uuid;
@ -26,8 +25,6 @@ pub struct TxAck {
downlink_frame_item: Option<gw::DownlinkFrameItem>,
phy_payload: Option<PhyPayload>,
phy_payload_relayed: Option<PhyPayload>,
device_session: Option<internal::DeviceSession>,
device_session_relayed: Option<internal::DeviceSession>,
tenant: Option<tenant::Tenant>,
tenant_relayed: Option<tenant::Tenant>,
application: Option<application::Application>,
@ -69,8 +66,6 @@ impl TxAck {
downlink_frame_item: None,
phy_payload: None,
phy_payload_relayed: None,
device_session: None,
device_session_relayed: None,
tenant: None,
tenant_relayed: None,
application: None,
@ -222,7 +217,6 @@ impl TxAck {
let dev_eui = EUI64::from_slice(&self.downlink_frame.as_ref().unwrap().dev_eui)?;
let (dev, app, t, dp) = get_all_device_data(dev_eui).await?;
self.device_session = Some(dev.get_device_session()?);
self.tenant = Some(t);
self.application = Some(app);
self.device_profile = Some(dp);
@ -236,7 +230,6 @@ impl TxAck {
let dev_eui = EUI64::from_slice(&self.downlink_frame.as_ref().unwrap().dev_eui_relayed)?;
let (dev, app, t, dp) = get_all_device_data(dev_eui).await?;
self.device_session_relayed = Some(dev.get_device_session()?);
self.tenant_relayed = Some(t);
self.application_relayed = Some(app);
self.device_profile_relayed = Some(dp);
@ -301,7 +294,8 @@ impl TxAck {
fn set_device_session_conf_f_cnt(&mut self) -> Result<()> {
trace!("Setting device-session conf_f_cnt");
let ds = self.device_session.as_mut().unwrap();
let d = self.device.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
let qi = self.device_queue_item.as_ref().unwrap();
ds.conf_f_cnt = match qi.f_cnt_down {
@ -318,7 +312,8 @@ impl TxAck {
fn set_device_session_conf_f_cnt_relayed(&mut self) -> Result<()> {
trace!("Setting relayed device-session conf_f_cnt");
let ds = self.device_session_relayed.as_mut().unwrap();
let d = self.device_relayed.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
let qi = self.device_queue_item.as_ref().unwrap();
ds.conf_f_cnt = match qi.f_cnt_down {
@ -335,7 +330,8 @@ impl TxAck {
fn increment_a_f_cnt_down(&mut self) -> Result<()> {
trace!("Incrementing a_f_cnt_down");
let ds = self.device_session.as_mut().unwrap();
let d = self.device.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
ds.set_a_f_cnt_down(self.downlink_frame.as_ref().unwrap().a_f_cnt_down + 1);
Ok(())
@ -344,7 +340,8 @@ impl TxAck {
fn increment_a_f_cnt_down_relayed(&mut self) -> Result<()> {
trace!("Incrementing relayed a_f_cnt_down");
let ds = self.device_session_relayed.as_mut().unwrap();
let d = self.device_relayed.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
ds.set_a_f_cnt_down(ds.get_a_f_cnt_down() + 1);
Ok(())
@ -353,7 +350,8 @@ impl TxAck {
fn increment_n_f_cnt_down(&mut self) -> Result<()> {
trace!("Incrementing n_f_cnt_down");
let ds = self.device_session.as_mut().unwrap();
let d = self.device.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
ds.n_f_cnt_down += 1;
Ok(())
@ -362,7 +360,8 @@ impl TxAck {
fn increment_n_f_cnt_down_relayed(&mut self) -> Result<()> {
trace!("Incrementing relayed n_f_cnt_down");
let ds = self.device_session_relayed.as_mut().unwrap();
let d = self.device_relayed.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
ds.n_f_cnt_down += 1;
Ok(())
@ -371,10 +370,12 @@ impl TxAck {
async fn save_device_session(&self) -> Result<()> {
trace!("Saving device-session");
let d = self.device.as_ref().unwrap();
device::partial_update(
self.device.as_ref().unwrap().dev_eui,
d.dev_eui,
&device::DeviceChangeset {
device_session: Some(Some(self.device_session.as_ref().unwrap().encode_to_vec())),
device_session: Some(d.device_session.clone()),
..Default::default()
},
)
@ -386,15 +387,12 @@ impl TxAck {
async fn save_device_session_relayed(&self) -> Result<()> {
trace!("Saving relayed device-session");
let d = self.device_relayed.as_ref().unwrap();
device::partial_update(
self.device.as_ref().unwrap().dev_eui,
d.dev_eui,
&device::DeviceChangeset {
device_session: Some(Some(
self.device_session_relayed
.as_ref()
.unwrap()
.encode_to_vec(),
)),
device_session: Some(d.device_session.clone()),
..Default::default()
},
)

View File

@ -5,11 +5,13 @@ use crate::storage::device;
use chirpstack_api::internal;
pub fn handle(
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
_block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() {
return Err(anyhow!("Expected pending ConfigureFwdLimitReq mac-command"));
}
@ -27,7 +29,7 @@ pub fn handle(
ds.relay = Some(internal::Relay::default());
}
info!(dev_eui = %dev.dev_eui, "ConfigureFwdLimitReq acknowledged");
info!(dev_eui = %dev_eui, "ConfigureFwdLimitReq acknowledged");
if let Some(relay) = &mut ds.relay {
relay.join_req_limit_reload_rate = req_pl.reload_rate.join_req_reload_rate as u32;

View File

@ -1,19 +1,19 @@
use std::iter::zip;
use anyhow::Result;
use prost::Message;
use tracing::{info, warn};
use crate::storage::device;
use chirpstack_api::internal;
use lrwn::EUI64;
pub async fn handle(
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() {
return Err(anyhow!("Expected pending CtrlUplinkListReq mac-command"));
}
@ -50,7 +50,7 @@ pub async fn handle(
if ans_pl.uplink_list_idx_ack {
if let Some(relay) = &mut ds.relay {
info!(
dev_eui = %dev.dev_eui,
dev_eui = %dev_eui,
uplink_list_idx = req_pl.ctrl_uplink_action.uplink_list_idx,
ctrl_uplink_action = action,
w_f_cnt = ans_pl.w_fcnt,
@ -61,15 +61,15 @@ pub async fn handle(
for rd in &relay.devices {
if req_pl.ctrl_uplink_action.uplink_list_idx as u32 == rd.index {
let dev_eui = EUI64::from_slice(&rd.dev_eui)?;
let d = device::get(&dev_eui).await?;
let mut ds = d.get_device_session()?;
let mut d = device::get(&dev_eui).await?;
let ds = d.get_device_session_mut()?;
if let Some(relay) = &mut ds.relay {
relay.w_f_cnt = ans_pl.w_fcnt;
};
device::partial_update(
dev_eui,
&device::DeviceChangeset {
device_session: Some(Some(ds.encode_to_vec())),
device_session: Some(d.device_session.clone()),
..Default::default()
},
)
@ -84,7 +84,7 @@ pub async fn handle(
}
} else {
warn!(
dev_eui = %dev.dev_eui,
dev_eui = %dev_eui,
uplink_list_idx = req_pl.ctrl_uplink_action.uplink_list_idx,
"CtrlUplinkListReq not acknowledged",
);

View File

@ -5,11 +5,13 @@ use crate::storage::device;
use chirpstack_api::internal;
pub fn handle(
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() {
return Err(anyhow!("Expected pending EndDeviceConfReq mac-command"));
}
@ -41,7 +43,7 @@ pub fn handle(
&& ans_pl.second_ch_idx_ack
&& ans_pl.backoff_ack
{
info!(dev_eui = %dev.dev_eui, "EndDeviceConfReq acknowledged");
info!(dev_eui = %dev_eui, "EndDeviceConfReq acknowledged");
if let Some(relay) = &mut ds.relay {
relay.ed_activation_mode =
@ -57,7 +59,7 @@ pub fn handle(
}
} else {
warn!(
dev_eui = %dev.dev_eui,
dev_eui = %dev_eui,
second_ch_freq_ack = ans_pl.second_ch_freq_ack,
second_ch_dr_ack = ans_pl.second_ch_dr_ack,
second_ch_idx_ack = ans_pl.second_ch_idx_ack,

View File

@ -2,14 +2,14 @@ use anyhow::Result;
use tracing::{info, warn};
use crate::storage::device;
use chirpstack_api::internal;
pub fn handle(
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> {
let ds = dev.get_device_session_mut()?;
if pending.is_none() {
return Err(anyhow!("Expected pending FilterListReq mac-command"));
}

View File

@ -4,15 +4,16 @@ use tracing::{info, warn};
use crate::region;
use crate::storage::device;
use crate::uplink::UplinkFrameSet;
use chirpstack_api::internal;
pub fn handle(
uplink_frame_set: &UplinkFrameSet,
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() {
return Err(anyhow!("Expected pending LinkADRReq mac-command"));
}
@ -82,7 +83,7 @@ pub fn handle(
ds.nb_trans = link_adr_req.redundancy.nb_rep as u32;
ds.enabled_uplink_channel_indices = chans.iter().map(|i| *i as u32).collect::<Vec<u32>>();
info!(dev_eui = %dev.dev_eui, tx_power_index = ds.tx_power_index, dr = ds.dr, nb_trans = ds.nb_trans, enabled_channels = ?ds.enabled_uplink_channel_indices, "LinkADRReq acknowledged");
info!(dev_eui = %dev_eui, tx_power_index = ds.tx_power_index, dr = ds.dr, nb_trans = ds.nb_trans, enabled_channels = ?ds.enabled_uplink_channel_indices, "LinkADRReq acknowledged");
} else if !ds.adr && ch_mask_ack {
// In case the device has ADR disabled, at least it must acknowledge the
// channel-mask. It does not have to acknowledge the other parameters.
@ -113,7 +114,7 @@ pub fn handle(
ds.tx_power_index = link_adr_req.tx_power as u32;
}
info!(dev_eui = %dev.dev_eui, tx_power_index = ds.tx_power_index, dr = ds.dr, nb_trans = ds.nb_trans, enabled_channels = ?ds.enabled_uplink_channel_indices, "LinkADRReq acknowledged (device has ADR disabled)");
info!(dev_eui = %dev_eui, tx_power_index = ds.tx_power_index, dr = ds.dr, nb_trans = ds.nb_trans, enabled_channels = ?ds.enabled_uplink_channel_indices, "LinkADRReq acknowledged (device has ADR disabled)");
} else {
// increase the error counter
let count = ds

View File

@ -7,8 +7,6 @@ use crate::config;
use crate::helpers::errors::PrintFullError;
use crate::storage::{application, device, device_profile, mac_command, tenant};
use crate::uplink::UplinkFrameSet;
use chirpstack_api::internal;
use lrwn::EUI64;
pub mod configure_fwd_limit;
pub mod ctrl_uplink_list;
@ -41,15 +39,13 @@ pub async fn handle_uplink<'a>(
tenant: &tenant::Tenant,
app: &application::Application,
dp: &device_profile::DeviceProfile,
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
) -> Result<(Vec<lrwn::MACCommandSet>, bool)> {
let conf = config::get();
if conf.network.mac_commands_disabled {
return Ok((Vec::new(), false));
}
let dev_eui = EUI64::from_slice(&ds.dev_eui)?;
let mut cids: Vec<lrwn::CID> = Vec::new(); // to maintain the CID order
let mut blocks: HashMap<lrwn::CID, lrwn::MACCommandSet> = HashMap::new();
@ -81,18 +77,18 @@ pub async fn handle_uplink<'a>(
);
// Get pending mac-command block, this could return None.
let pending = match mac_command::get_pending(&dev_eui, cid).await {
let pending = match mac_command::get_pending(&dev.dev_eui, cid).await {
Ok(v) => v,
Err(e) => {
error!(dev_eui = %dev_eui, cid = %cid, error = %e, "Get pending mac-command block error");
error!(dev_eui = %dev.dev_eui, cid = %cid, error = %e, "Get pending mac-command block error");
continue;
}
};
// Delete the pending mac-command.
if pending.is_some() {
if let Err(e) = mac_command::delete_pending(&dev_eui, cid).await {
error!(dev_eui = %dev_eui, cid = %cid, error = %e, "Delete pending mac-command error");
if let Err(e) = mac_command::delete_pending(&dev.dev_eui, cid).await {
error!(dev_eui = %dev.dev_eui, cid = %cid, error = %e, "Delete pending mac-command error");
}
}
@ -107,13 +103,12 @@ pub async fn handle_uplink<'a>(
app,
dp,
dev,
ds,
)
.await
{
Ok(v) => v,
Err(e) => {
warn!(dev_eui = %dev_eui, cid = %cid, error = %e.full(), "Handle mac-command error");
warn!(dev_eui = %dev.dev_eui, cid = %cid, error = %e.full(), "Handle mac-command error");
continue;
}
};
@ -135,8 +130,7 @@ async fn handle(
tenant: &tenant::Tenant,
app: &application::Application,
dp: &device_profile::DeviceProfile,
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
) -> Result<Option<lrwn::MACCommandSet>> {
match cid {
lrwn::CID::DevStatusAns => {
@ -144,30 +138,26 @@ async fn handle(
}
lrwn::CID::DeviceModeInd => device_mode_ind::handle(dev, block).await,
lrwn::CID::DeviceTimeReq => device_time::handle(uplink_frame_set, dev, block),
lrwn::CID::LinkADRAns => link_adr::handle(uplink_frame_set, dev, ds, block, pending_block),
lrwn::CID::LinkADRAns => link_adr::handle(uplink_frame_set, dev, block, pending_block),
lrwn::CID::LinkCheckReq => link_check::handle(uplink_frame_set, dev, block),
lrwn::CID::NewChannelAns => new_channel::handle(dev, ds, block, pending_block),
lrwn::CID::PingSlotChannelAns => ping_slot_channel::handle(dev, ds, block, pending_block),
lrwn::CID::PingSlotInfoReq => ping_slot_info::handle(dev, ds, block),
lrwn::CID::RejoinParamSetupAns => rejoin_param_setup::handle(dev, ds, block, pending_block),
lrwn::CID::NewChannelAns => new_channel::handle(dev, block, pending_block),
lrwn::CID::PingSlotChannelAns => ping_slot_channel::handle(dev, block, pending_block),
lrwn::CID::PingSlotInfoReq => ping_slot_info::handle(dev, block),
lrwn::CID::RejoinParamSetupAns => rejoin_param_setup::handle(dev, block, pending_block),
lrwn::CID::RekeyInd => rekey::handle(dev, block),
lrwn::CID::ResetInd => reset::handle(dev, dp, ds, block),
lrwn::CID::RxParamSetupAns => rx_param_setup::handle(dev, ds, block, pending_block),
lrwn::CID::RxTimingSetupAns => rx_timing_setup::handle(dev, ds, block, pending_block),
lrwn::CID::TxParamSetupAns => tx_param_setup::handle(dev, ds, block, pending_block),
lrwn::CID::RelayConfAns => relay_conf::handle(dev, ds, block, pending_block),
lrwn::CID::EndDeviceConfAns => end_device_conf::handle(dev, ds, block, pending_block),
lrwn::CID::FilterListAns => filter_list::handle(dev, ds, block, pending_block),
lrwn::CID::UpdateUplinkListAns => update_uplink_list::handle(dev, ds, block, pending_block),
lrwn::CID::ConfigureFwdLimitAns => {
configure_fwd_limit::handle(dev, ds, block, pending_block)
}
lrwn::CID::ResetInd => reset::handle(dev, dp, block),
lrwn::CID::RxParamSetupAns => rx_param_setup::handle(dev, block, pending_block),
lrwn::CID::RxTimingSetupAns => rx_timing_setup::handle(dev, block, pending_block),
lrwn::CID::TxParamSetupAns => tx_param_setup::handle(dev, block, pending_block),
lrwn::CID::RelayConfAns => relay_conf::handle(dev, block, pending_block),
lrwn::CID::EndDeviceConfAns => end_device_conf::handle(dev, block, pending_block),
lrwn::CID::FilterListAns => filter_list::handle(dev, block, pending_block),
lrwn::CID::UpdateUplinkListAns => update_uplink_list::handle(dev, block, pending_block),
lrwn::CID::ConfigureFwdLimitAns => configure_fwd_limit::handle(dev, block, pending_block),
lrwn::CID::NotifyNewEndDeviceReq => {
notify_new_end_device::handle(tenant, dp, app, dev, block).await
}
lrwn::CID::CtrlUplinkListAns => {
ctrl_uplink_list::handle(dev, ds, block, pending_block).await
}
lrwn::CID::CtrlUplinkListAns => ctrl_uplink_list::handle(dev, block, pending_block).await,
_ => {
warn!(cid = %cid, "Unexpected CID");
// Return OK, we don't want to break out of the uplink handling.

View File

@ -62,11 +62,13 @@ pub fn request(
}
pub fn handle(
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() {
return Err(anyhow!("Expected pending NewChannelReq"));
}
@ -115,7 +117,7 @@ pub fn handle(
.push(req_pl.ch_index as u32);
}
info!(dev_eui = %dev.dev_eui, freq = req_pl.freq, channel = req_pl.ch_index, min_dr = req_pl.min_dr, max_dr = req_pl.max_dr, "NewChannelReq acknowledged");
info!(dev_eui = %dev_eui, freq = req_pl.freq, channel = req_pl.ch_index, min_dr = req_pl.min_dr, max_dr = req_pl.max_dr, "NewChannelReq acknowledged");
} else {
let count = ds
.mac_command_error_count
@ -124,7 +126,7 @@ pub fn handle(
*count += 1;
warn!(
dev_eui = %dev.dev_eui,
dev_eui = %dev_eui,
freq = req_pl.freq,
channel = req_pl.ch_index,
min_dr = req_pl.min_dr,

View File

@ -2,7 +2,6 @@ use anyhow::Result;
use tracing::{info, warn};
use crate::storage::device;
use chirpstack_api::internal;
pub fn request(dr: u8, freq: u32) -> lrwn::MACCommandSet {
lrwn::MACCommandSet::new(vec![lrwn::MACCommand::PingSlotChannelReq(
@ -11,11 +10,12 @@ pub fn request(dr: u8, freq: u32) -> lrwn::MACCommandSet {
}
pub fn handle(
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> {
let ds = dev.get_device_session_mut()?;
if pending.is_none() {
return Err(anyhow!("Pending PingSlotChannelReq expected"));
}

View File

@ -2,13 +2,14 @@ use anyhow::Result;
use tracing::info;
use crate::storage::device;
use chirpstack_api::internal;
pub fn handle(
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
block: &lrwn::MACCommandSet,
) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
let mac = (**block)
.first()
.ok_or_else(|| anyhow!("MACCommandSet is empty"))?;
@ -21,7 +22,7 @@ pub fn handle(
ds.class_b_ping_slot_nb = 1 << (7 - pl.periodicity);
info!(dev_eui = %dev.dev_eui, periodicity = pl.periodicity, ping_slot_nb = ds.class_b_ping_slot_nb, "PingSlotInfoReq received");
info!(dev_eui = %dev_eui, periodicity = pl.periodicity, ping_slot_nb = ds.class_b_ping_slot_nb, "PingSlotInfoReq received");
Ok(Some(lrwn::MACCommandSet::new(vec![
lrwn::MACCommand::PingSlotInfoAns,

View File

@ -2,7 +2,6 @@ use anyhow::Result;
use tracing::{info, warn};
use crate::storage::device;
use chirpstack_api::internal;
pub fn request(max_time_n: u8, max_count_n: u8) -> lrwn::MACCommandSet {
lrwn::MACCommandSet::new(vec![lrwn::MACCommand::RejoinParamSetupReq(
@ -14,11 +13,12 @@ pub fn request(max_time_n: u8, max_count_n: u8) -> lrwn::MACCommandSet {
}
pub fn handle(
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> {
let ds = dev.get_device_session_mut()?;
if pending.is_none() {
return Err(anyhow!("Pending RejoinParamSetupReq expected"));
}

View File

@ -5,11 +5,13 @@ use crate::storage::device;
use chirpstack_api::internal;
pub fn handle(
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() {
return Err(anyhow!("Expected pending RelayConfReq mac-command"));
}
@ -43,7 +45,7 @@ pub fn handle(
&& ans_pl.default_ch_idx_ack
&& ans_pl.cad_periodicity_ack
{
info!(dev_eui = %dev.dev_eui, "RelayConfReq acknowledged");
info!(dev_eui = %dev_eui, "RelayConfReq acknowledged");
if let Some(relay) = &mut ds.relay {
relay.enabled = req_pl.channel_settings_relay.start_stop == 1;
@ -56,7 +58,7 @@ pub fn handle(
}
} else {
warn!(
dev_eui = %dev.dev_eui,
dev_eui = %dev_eui,
second_ch_ack_offset_ack = ans_pl.second_ch_ack_offset_ack,
second_ch_dr_ack = ans_pl.second_ch_dr_ack,
second_ch_idx_ack = ans_pl.second_ch_idx_ack,

View File

@ -2,16 +2,17 @@ use anyhow::Result;
use tracing::info;
use crate::storage::{device, device_profile};
use chirpstack_api::internal;
const SERV_LORAWAN_VERSION: lrwn::Version = lrwn::Version::LoRaWAN1_1;
pub fn handle(
dev: &device::Device,
dev: &mut device::Device,
dp: &device_profile::DeviceProfile,
ds: &mut internal::DeviceSession,
block: &lrwn::MACCommandSet,
) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
let block_mac = (**block)
.first()
.ok_or_else(|| anyhow!("MACCommandSet is empty"))?;
@ -21,7 +22,7 @@ pub fn handle(
return Err(anyhow!("ResetInd expected"));
};
info!(dev_eui = %dev.dev_eui, dev_lorawan_version = %block_pl.dev_lorawan_version, serv_lorawan_version = %SERV_LORAWAN_VERSION, "ResetInd received");
info!(dev_eui = %dev_eui, dev_lorawan_version = %block_pl.dev_lorawan_version, serv_lorawan_version = %SERV_LORAWAN_VERSION, "ResetInd received");
dp.reset_session_to_boot_params(ds);

View File

@ -2,7 +2,6 @@ use anyhow::Result;
use tracing::{info, warn};
use crate::storage::device;
use chirpstack_api::internal;
pub fn request(rx1_dr_offset: u8, rx2_freq: u32, rx2_dr: u8) -> lrwn::MACCommandSet {
lrwn::MACCommandSet::new(vec![lrwn::MACCommand::RxParamSetupReq(
@ -18,11 +17,12 @@ pub fn request(rx1_dr_offset: u8, rx2_freq: u32, rx2_dr: u8) -> lrwn::MACCommand
}
pub fn handle(
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> {
let ds = dev.get_device_session_mut()?;
if pending.is_none() {
return Err(anyhow!("Expected pending RxParamSetupReq"));
}

View File

@ -2,7 +2,6 @@ use anyhow::Result;
use tracing::info;
use crate::storage::device;
use chirpstack_api::internal;
pub fn request(rx1_delay: u8) -> lrwn::MACCommandSet {
lrwn::MACCommandSet::new(vec![lrwn::MACCommand::RxTimingSetupReq(
@ -11,11 +10,13 @@ pub fn request(rx1_delay: u8) -> lrwn::MACCommandSet {
}
pub fn handle(
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
_block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() {
return Err(anyhow!("Pending RxTimingSetupReq expected"));
}
@ -31,7 +32,7 @@ pub fn handle(
};
ds.rx1_delay = req_pl.delay as u32;
info!(dev_eui = %dev.dev_eui, rx1_delay = req_pl.delay, "RxTimingSetupReq acknowledged");
info!(dev_eui = %dev_eui, rx1_delay = req_pl.delay, "RxTimingSetupReq acknowledged");
Ok(None)
}

View File

@ -2,7 +2,6 @@ use anyhow::Result;
use tracing::info;
use crate::storage::device;
use chirpstack_api::internal;
pub fn request(
uplink_dwell_time_400ms: bool,
@ -29,11 +28,13 @@ pub fn request(
}
pub fn handle(
dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
_block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> {
let dev_eui = dev.dev_eui;
let ds = dev.get_device_session_mut()?;
if pending.is_none() {
return Err(anyhow!("Expected pending TxParamSetupReq"));
}
@ -52,7 +53,7 @@ pub fn handle(
ds.downlink_dwell_time_400ms = req_pl.downlink_dwell_time == lrwn::DwellTime::Limit400ms;
ds.uplink_max_eirp_index = req_pl.max_eirp as u32;
info!(dev_eui = %dev.dev_eui, uplink_dwell_time_400ms = ds.uplink_dwell_time_400ms, downlink_dwell_time_400ms = ds.downlink_dwell_time_400ms, uplink_max_eirp_index = ds.uplink_max_eirp_index, "TxParamSetupReq acknowledged");
info!(dev_eui = %dev_eui, uplink_dwell_time_400ms = ds.uplink_dwell_time_400ms, downlink_dwell_time_400ms = ds.downlink_dwell_time_400ms, uplink_max_eirp_index = ds.uplink_max_eirp_index, "TxParamSetupReq acknowledged");
Ok(None)
}

View File

@ -2,14 +2,14 @@ use anyhow::Result;
use tracing::info;
use crate::storage::device;
use chirpstack_api::internal;
pub fn handle(
_dev: &device::Device,
ds: &mut internal::DeviceSession,
dev: &mut device::Device,
_block: &lrwn::MACCommandSet,
pending: Option<&lrwn::MACCommandSet>,
) -> Result<Option<lrwn::MACCommandSet>> {
let ds = dev.get_device_session_mut()?;
if pending.is_none() {
return Err(anyhow!("Expected pending UpdateUplinkListReq mac-command"));
}

View File

@ -1,6 +1,5 @@
use std::collections::HashMap;
use std::fmt;
use std::io::Cursor;
use std::str::FromStr;
use anyhow::{Context, Result};
@ -8,7 +7,6 @@ use bigdecimal::BigDecimal;
use chrono::{DateTime, Duration, Utc};
use diesel::{backend::Backend, deserialize, dsl, prelude::*, serialize, sql_types::Text};
use diesel_async::RunQueryDsl;
use prost::Message;
use tracing::info;
use uuid::Uuid;
@ -21,9 +19,9 @@ use crate::api::helpers::FromProto;
use crate::config;
pub enum ValidationStatus {
Ok(u32, internal::DeviceSession),
Retransmission(u32, internal::DeviceSession),
Reset(u32, internal::DeviceSession),
Ok(u32, Device),
Retransmission(u32, Device),
Reset(u32, Device),
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, AsExpression, FromSqlRow)]
@ -106,7 +104,7 @@ pub struct Device {
pub variables: fields::KeyValue,
pub join_eui: EUI64,
pub secondary_dev_addr: Option<DevAddr>,
pub device_session: Option<Vec<u8>>,
pub device_session: Option<internal::DeviceSession>,
}
#[derive(AsChangeset, Debug, Clone, Default)]
@ -118,7 +116,7 @@ pub struct DeviceChangeset {
pub enabled_class: Option<DeviceClass>,
pub join_eui: Option<EUI64>,
pub secondary_dev_addr: Option<Option<DevAddr>>,
pub device_session: Option<Option<Vec<u8>>>,
pub device_session: Option<Option<internal::DeviceSession>>,
pub margin: Option<i32>,
pub external_power_source: Option<bool>,
pub battery_level: Option<Option<BigDecimal>>,
@ -133,15 +131,20 @@ impl Device {
Ok(())
}
pub fn set_device_session(&mut self, ds: &internal::DeviceSession) {
self.device_session = Some(ds.encode_to_vec())
pub fn get_device_session(&self) -> Result<&internal::DeviceSession, Error> {
self.device_session
.as_ref()
.ok_or_else(|| Error::NotFound(self.dev_eui.to_string()))
}
pub fn get_device_session(&self) -> Result<internal::DeviceSession, Error> {
match &self.device_session {
None => Err(Error::NotFound(self.dev_eui.to_string())),
Some(v) => Ok(internal::DeviceSession::decode(&mut Cursor::new(&v))?),
}
pub fn get_device_session_mut(&mut self) -> Result<&mut internal::DeviceSession, Error> {
self.device_session
.as_mut()
.ok_or_else(|| Error::NotFound(self.dev_eui.to_string()))
}
pub fn get_dev_addr(&self) -> Result<DevAddr> {
self.dev_addr.ok_or_else(|| anyhow!("DevAddr is not set"))
}
}
@ -303,8 +306,7 @@ pub async fn get_for_phypayload_and_incr_f_cnt_up(
c.build_transaction()
.run::<ValidationStatus, Error, _>(|c| {
Box::pin(async move {
let devices: Vec<(EUI64, Option<Vec<u8>>)> = device::dsl::device
.select((device::dev_eui, device::device_session))
let mut devices: Vec<Device> = device::dsl::device
.filter(
device::dsl::dev_addr
.eq(&dev_addr)
@ -319,107 +321,105 @@ pub async fn get_for_phypayload_and_incr_f_cnt_up(
return Err(Error::NotFound(dev_addr.to_string()));
}
let mut sessions: Vec<(EUI64, internal::DeviceSession)> = Vec::new();
for d in &mut devices {
let mut sessions = vec![];
for d in &devices {
if d.1.is_none() {
continue;
}
let ds =
internal::DeviceSession::decode(&mut Cursor::new(d.1.as_ref().unwrap()))?;
if let Some(pending_ds) = &ds.pending_rejoin_device_session {
sessions.push((d.0, *pending_ds.clone()));
}
sessions.push((d.0, ds));
}
for (dev_eui, ds) in &mut sessions {
if ds.dev_addr != dev_addr.to_vec() {
continue;
}
// Get the full 32bit frame-counter.
let full_f_cnt = get_full_f_cnt_up(ds.f_cnt_up, f_cnt_orig);
let f_nwk_s_int_key = lrwn::AES128Key::from_slice(&ds.f_nwk_s_int_key)?;
let s_nwk_s_int_key = lrwn::AES128Key::from_slice(&ds.s_nwk_s_int_key)?;
// Check both the full frame-counter and the received frame-counter
// truncated to the 16LSB.
// The latter is needed in case of a frame-counter reset as the
// GetFullFCntUp will think the 16LSB has rolled over and will
// increment the 16MSB bit.
let mut mic_ok = false;
for f_cnt in [full_f_cnt, f_cnt_orig] {
// Set the full f_cnt.
if let lrwn::Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = f_cnt;
}
mic_ok = phy
.validate_uplink_data_mic(
ds.mac_version().from_proto(),
ds.conf_f_cnt,
tx_dr,
tx_ch,
&f_nwk_s_int_key,
&s_nwk_s_int_key,
)
.context("Validate MIC")?;
if mic_ok {
break;
if let Some(ds) = &d.device_session {
sessions.push(ds.clone());
if let Some(ds) = &ds.pending_rejoin_device_session {
sessions.push(*ds.clone());
}
}
if mic_ok {
let full_f_cnt = if let lrwn::Payload::MACPayload(pl) = &phy.payload {
pl.fhdr.f_cnt
} else {
0
};
for ds in &mut sessions {
if ds.dev_addr != dev_addr.to_vec() {
continue;
}
if let Some(relay) = &ds.relay {
if !relayed && relay.ed_relay_only {
info!(
dev_eui = %dev_eui,
"Only communication through relay is allowed"
);
return Err(Error::NotFound(dev_addr.to_string()));
// Get the full 32bit frame-counter.
let full_f_cnt = get_full_f_cnt_up(ds.f_cnt_up, f_cnt_orig);
let f_nwk_s_int_key = lrwn::AES128Key::from_slice(&ds.f_nwk_s_int_key)?;
let s_nwk_s_int_key = lrwn::AES128Key::from_slice(&ds.s_nwk_s_int_key)?;
// Check both the full frame-counter and the received frame-counter
// truncated to the 16LSB.
// The latter is needed in case of a frame-counter reset as the
// GetFullFCntUp will think the 16LSB has rolled over and will
// increment the 16MSB bit.
let mut mic_ok = false;
for f_cnt in [full_f_cnt, f_cnt_orig] {
// Set the full f_cnt.
if let lrwn::Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = f_cnt;
}
mic_ok = phy
.validate_uplink_data_mic(
ds.mac_version().from_proto(),
ds.conf_f_cnt,
tx_dr,
tx_ch,
&f_nwk_s_int_key,
&s_nwk_s_int_key,
)
.context("Validate MIC")?;
if mic_ok {
break;
}
}
if full_f_cnt >= ds.f_cnt_up {
// We immediately save the device-session to make sure that concurrent calls for
// the same uplink will fail on the frame-counter validation.
let ds_f_cnt_up = ds.f_cnt_up;
ds.f_cnt_up = full_f_cnt + 1;
if mic_ok {
let full_f_cnt = if let lrwn::Payload::MACPayload(pl) = &phy.payload {
pl.fhdr.f_cnt
} else {
0
};
let _ = diesel::update(device::dsl::device.find(*dev_eui))
.set(device::device_session.eq(&ds.encode_to_vec()))
.execute(c)
.await?;
if let Some(relay) = &ds.relay {
if !relayed && relay.ed_relay_only {
info!(
dev_eui = %d.dev_eui,
"Only communication through relay is allowed"
);
return Err(Error::NotFound(dev_addr.to_string()));
}
}
// We do return the device-session with original frame-counter
ds.f_cnt_up = ds_f_cnt_up;
if full_f_cnt >= ds.f_cnt_up {
// We immediately save the device-session to make sure that concurrent calls for
// the same uplink will fail on the frame-counter validation.
let ds_f_cnt_up = ds.f_cnt_up;
ds.f_cnt_up = full_f_cnt + 1;
return Ok(ValidationStatus::Ok(full_f_cnt, ds.clone()));
} else if ds.skip_f_cnt_check {
// re-transmission or frame-counter reset
ds.f_cnt_up = 0;
return Ok(ValidationStatus::Ok(full_f_cnt, ds.clone()));
} else if full_f_cnt == (ds.f_cnt_up - 1) {
// re-transmission, the frame-counter did not increment
return Ok(ValidationStatus::Retransmission(full_f_cnt, ds.clone()));
} else {
return Ok(ValidationStatus::Reset(full_f_cnt, ds.clone()));
let _ = diesel::update(device::dsl::device.find(d.dev_eui))
.set(device::device_session.eq(&ds.clone()))
.execute(c)
.await?;
// We do return the device-session with original frame-counter
ds.f_cnt_up = ds_f_cnt_up;
d.device_session = Some(ds.clone());
return Ok(ValidationStatus::Ok(full_f_cnt, d.clone()));
} else if ds.skip_f_cnt_check {
// re-transmission or frame-counter reset
ds.f_cnt_up = 0;
d.device_session = Some(ds.clone());
return Ok(ValidationStatus::Ok(full_f_cnt, d.clone()));
} else if full_f_cnt == (ds.f_cnt_up - 1) {
// re-transmission, the frame-counter did not increment
d.device_session = Some(ds.clone());
return Ok(ValidationStatus::Retransmission(full_f_cnt, d.clone()));
} else {
d.device_session = Some(ds.clone());
return Ok(ValidationStatus::Reset(full_f_cnt, d.clone()));
}
}
}
// Restore the original f_cnt.
if let lrwn::Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = f_cnt_orig;
// Restore the original f_cnt.
if let lrwn::Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = f_cnt_orig;
}
}
}
@ -433,7 +433,7 @@ pub async fn get_for_phypayload(
phy: &mut lrwn::PhyPayload,
tx_dr: u8,
tx_ch: u8,
) -> Result<internal::DeviceSession, Error> {
) -> Result<Device, Error> {
// Get the dev_addr and original f_cnt.
let (dev_addr, f_cnt_orig) = if let lrwn::Payload::MACPayload(pl) = &phy.payload {
(pl.fhdr.devaddr, pl.fhdr.f_cnt)
@ -441,14 +441,13 @@ pub async fn get_for_phypayload(
return Err(Error::InvalidPayload("MacPayload".to_string()));
};
let devices: Vec<(EUI64, Option<Vec<u8>>)> = device::dsl::device
.select((device::dev_eui, device::device_session))
let devices: Vec<Device> = device::dsl::device
.filter(
device::dsl::dev_addr
.eq(&dev_addr)
.or(device::dsl::secondary_dev_addr.eq(&dev_addr)),
)
.for_update()
.filter(device::dsl::is_disabled.eq(false))
.load(&mut get_async_db_conn().await?)
.await?;
@ -457,40 +456,49 @@ pub async fn get_for_phypayload(
}
for d in &devices {
if d.1.is_none() {
continue;
let mut sessions = vec![];
if let Some(ds) = &d.device_session {
sessions.push(ds.clone());
if let Some(ds) = &ds.pending_rejoin_device_session {
sessions.push(*ds.clone());
}
}
let ds = internal::DeviceSession::decode(&mut Cursor::new(&d.1.as_ref().unwrap()))?;
for ds in &mut sessions {
if ds.dev_addr != dev_addr.to_vec() {
continue;
}
// Get the full 32bit frame-counter.
let full_f_cnt = get_full_f_cnt_up(ds.f_cnt_up, f_cnt_orig);
let f_nwk_s_int_key = lrwn::AES128Key::from_slice(&ds.f_nwk_s_int_key)?;
let s_nwk_s_int_key = lrwn::AES128Key::from_slice(&ds.s_nwk_s_int_key)?;
// Get the full 32bit frame-counter.
let full_f_cnt = get_full_f_cnt_up(ds.f_cnt_up, f_cnt_orig);
let f_nwk_s_int_key = lrwn::AES128Key::from_slice(&ds.f_nwk_s_int_key)?;
let s_nwk_s_int_key = lrwn::AES128Key::from_slice(&ds.s_nwk_s_int_key)?;
// Set the full f_cnt
if let lrwn::Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = full_f_cnt;
}
// Set the full f_cnt
if let lrwn::Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = full_f_cnt;
}
let mic_ok = phy
.validate_uplink_data_mic(
ds.mac_version().from_proto(),
ds.conf_f_cnt,
tx_dr,
tx_ch,
&f_nwk_s_int_key,
&s_nwk_s_int_key,
)
.context("Validate MIC")?;
let mic_ok = phy
.validate_uplink_data_mic(
ds.mac_version().from_proto(),
ds.conf_f_cnt,
tx_dr,
tx_ch,
&f_nwk_s_int_key,
&s_nwk_s_int_key,
)
.context("Validate MIC")?;
if mic_ok && full_f_cnt >= ds.f_cnt_up {
return Ok(ds);
}
if mic_ok && full_f_cnt >= ds.f_cnt_up {
return Ok(d.clone());
}
// Restore the original f_cnt.
if let lrwn::Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = f_cnt_orig;
// Restore the original f_cnt.
if let lrwn::Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = f_cnt_orig;
}
}
}
@ -1002,100 +1010,6 @@ pub mod test {
async fn test_device_session() {
let _guard = test::prepare().await;
let device_sessions = vec![
internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
dev_eui: vec![0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01],
s_nwk_s_int_key: vec![
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01,
],
f_nwk_s_int_key: vec![
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01,
],
nwk_s_enc_key: vec![
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01,
],
f_cnt_up: 100,
skip_f_cnt_check: true,
..Default::default()
},
internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
dev_eui: vec![0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02],
s_nwk_s_int_key: vec![
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02,
],
f_nwk_s_int_key: vec![
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02,
],
nwk_s_enc_key: vec![
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02,
],
f_cnt_up: 200,
..Default::default()
},
internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
dev_eui: vec![0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03],
s_nwk_s_int_key: vec![
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03,
],
f_nwk_s_int_key: vec![
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03,
],
nwk_s_enc_key: vec![
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03,
],
f_cnt_up: 300,
pending_rejoin_device_session: Some(Box::new(internal::DeviceSession {
dev_addr: vec![0x04, 0x03, 0x02, 0x01],
dev_eui: vec![0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03],
s_nwk_s_int_key: vec![
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04,
],
f_nwk_s_int_key: vec![
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04,
],
nwk_s_enc_key: vec![
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04,
],
f_cnt_up: 0,
..Default::default()
})),
..Default::default()
},
internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
dev_eui: vec![0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05],
s_nwk_s_int_key: vec![
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05,
],
f_nwk_s_int_key: vec![
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05,
],
nwk_s_enc_key: vec![
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05,
],
f_cnt_up: (1 << 16) + 1,
..Default::default()
},
];
let t = storage::tenant::create(storage::tenant::Tenant {
name: "test-tenant".into(),
..Default::default()
@ -1119,22 +1033,130 @@ pub mod test {
.await
.unwrap();
for ds in &device_sessions {
create(Device {
dev_eui: EUI64::from_slice(&ds.dev_eui).unwrap(),
dev_addr: Some(DevAddr::from_slice(&ds.dev_addr).unwrap()),
secondary_dev_addr: ds
.pending_rejoin_device_session
.as_ref()
.map(|v| DevAddr::from_slice(&v.dev_addr).unwrap()),
name: hex::encode(&ds.dev_eui),
let mut devices = vec![
Device {
application_id: app.id,
device_profile_id: dp.id,
device_session: Some(ds.encode_to_vec()),
name: "0101010101010101".into(),
dev_eui: EUI64::from_be_bytes([1, 1, 1, 1, 1, 1, 1, 1]),
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
device_session: Some(internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
s_nwk_s_int_key: vec![
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01,
],
f_nwk_s_int_key: vec![
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01,
],
nwk_s_enc_key: vec![
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01,
],
f_cnt_up: 100,
skip_f_cnt_check: true,
..Default::default()
}),
..Default::default()
})
.await
.unwrap();
},
Device {
application_id: app.id,
device_profile_id: dp.id,
name: "0202020202020202".into(),
dev_eui: EUI64::from_be_bytes([2, 2, 2, 2, 2, 2, 2, 2]),
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
device_session: Some(internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
s_nwk_s_int_key: vec![
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02,
],
f_nwk_s_int_key: vec![
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02,
],
nwk_s_enc_key: vec![
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02,
],
f_cnt_up: 200,
..Default::default()
}),
..Default::default()
},
Device {
application_id: app.id,
device_profile_id: dp.id,
name: "0303030303030303".into(),
dev_eui: EUI64::from_be_bytes([2, 2, 2, 2, 2, 2, 2, 2]),
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
secondary_dev_addr: Some(DevAddr::from_be_bytes([4, 3, 2, 1])),
device_session: Some(internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
s_nwk_s_int_key: vec![
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03,
],
f_nwk_s_int_key: vec![
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03,
],
nwk_s_enc_key: vec![
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03,
],
f_cnt_up: 300,
pending_rejoin_device_session: Some(Box::new(internal::DeviceSession {
dev_addr: vec![0x04, 0x03, 0x02, 0x01],
s_nwk_s_int_key: vec![
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04,
],
f_nwk_s_int_key: vec![
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04,
],
nwk_s_enc_key: vec![
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04,
],
f_cnt_up: 0,
..Default::default()
})),
..Default::default()
}),
..Default::default()
},
Device {
application_id: app.id,
device_profile_id: dp.id,
name: "0505050505050505".into(),
dev_eui: EUI64::from_be_bytes([5, 5, 5, 5, 5, 5, 5, 5]),
dev_addr: Some(DevAddr::from_be_bytes([1, 2, 3, 4])),
device_session: Some(internal::DeviceSession {
dev_addr: vec![0x01, 0x02, 0x03, 0x04],
s_nwk_s_int_key: vec![
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05,
],
f_nwk_s_int_key: vec![
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05,
],
nwk_s_enc_key: vec![
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05,
],
f_cnt_up: (1 << 16) + 1,
..Default::default()
}),
..Default::default()
},
];
for d in &mut devices {
*d = create(d.clone()).await.unwrap();
}
#[derive(Default)]
@ -1155,65 +1177,97 @@ pub mod test {
Test {
name: "matching dev_eui 0101010101010101".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_slice(&device_sessions[0].f_nwk_s_int_key)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(&device_sessions[0].s_nwk_s_int_key)
.unwrap(),
f_cnt: device_sessions[0].f_cnt_up,
f_nwk_s_int_key: AES128Key::from_slice(
&devices[0].device_session.as_ref().unwrap().f_nwk_s_int_key,
)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(
&devices[0].device_sessions.as_ref().unwrap().s_nwk_s_int_key,
)
.unwrap(),
f_cnt: devices[0].device_session.as_ref().unwrap().f_cnt_up,
expected_retransmission: false,
expected_reset: false,
expected_fcnt_up: device_sessions[0].f_cnt_up,
expected_dev_eui: EUI64::from_slice(&device_sessions[0].dev_eui).unwrap(),
expected_fcnt_up: devices[0].device_session.as_ref().f_cnt_up,
expected_dev_eui: EUI64::from_slice(
&devices[0].device_session.as_ref().unwrap().dev_eui,
)
.unwrap(),
expected_error: None,
},
Test {
name: "matching dev_eui 0202020202020202".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_slice(&device_sessions[1].f_nwk_s_int_key)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(&device_sessions[1].s_nwk_s_int_key)
.unwrap(),
f_cnt: device_sessions[1].f_cnt_up,
f_nwk_s_int_key: AES128Key::from_slice(
&devices[1].device_session.as_ref().unwrap().f_nwk_s_int_key,
)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(
&devices[1].device_session.as_ref().unwrap().s_nwk_s_int_key,
)
.unwrap(),
f_cnt: devices[1].device_session.as_ref().unwrap().f_cnt_up,
expected_retransmission: false,
expected_reset: false,
expected_fcnt_up: device_sessions[1].f_cnt_up,
expected_dev_eui: EUI64::from_slice(&device_sessions[1].dev_eui).unwrap(),
expected_fcnt_up: devices[1].device_session.as_ref().unwrap().f_cnt_up,
expected_dev_eui: EUI64::from_slice(
&devices[1].device_session.as_ref().unwrap().dev_eui,
)
.unwrap(),
expected_error: None,
},
Test {
name: "matching dev_eui 0101010101010101 with frame-counter reset".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_slice(&device_sessions[0].f_nwk_s_int_key)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(&device_sessions[0].s_nwk_s_int_key)
.unwrap(),
f_nwk_s_int_key: AES128Key::from_slice(
&devices[0].device_session.as_ref().unwrap().f_nwk_s_int_key,
)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(
&devices[0].device_session.as_ref().unwrap().s_nwk_s_int_key,
)
.unwrap(),
f_cnt: 0,
expected_retransmission: false,
expected_reset: false,
expected_fcnt_up: 0,
expected_dev_eui: EUI64::from_slice(&device_sessions[0].dev_eui).unwrap(),
expected_dev_eui: EUI64::from_slice(
&devices[0].device_session.as_ref().unwrap().dev_eui,
)
.unwrap(),
expected_error: None,
},
Test {
name: "matching dev_eui 0202020202020202 with invalid frame-counter".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_slice(&device_sessions[1].f_nwk_s_int_key)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(&device_sessions[1].s_nwk_s_int_key)
.unwrap(),
f_nwk_s_int_key: AES128Key::from_slice(
&devices[1].device_session.as_ref().unwrap().f_nwk_s_int_key,
)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(
&devices[1].device_session.as_ref().unwrap().s_nwk_s_int_key,
)
.unwrap(),
f_cnt: 0,
expected_reset: true,
expected_dev_eui: EUI64::from_slice(&device_sessions[1].dev_eui).unwrap(),
expected_dev_eui: EUI64::from_slice(
&devices[1].device_session.as_ref().unwrap().dev_eui,
)
.unwrap(),
..Default::default()
},
Test {
name: "invalid DevAddr".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x01, 0x01, 0x01]),
f_nwk_s_int_key: AES128Key::from_slice(&device_sessions[0].f_nwk_s_int_key)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(&device_sessions[0].s_nwk_s_int_key)
.unwrap(),
f_cnt: device_sessions[0].f_cnt_up,
f_nwk_s_int_key: AES128Key::from_slice(
&devices[0].device_session.as_ref().unwrap().f_nwk_s_int_key,
)
.unwrap(),
s_nwk_s_int_key: AES128Key::from_slice(
&devices[0].device_session.as_ref().unwrap().s_nwk_s_int_key,
)
.unwrap(),
f_cnt: devices[0].device_session.as_ref().unwrap().f_cnt_up,
expected_error: Some("Object does not exist (id: 01010101)".to_string()),
..Default::default()
},
@ -1226,7 +1280,7 @@ pub mod test {
s_nwk_s_int_key: AES128Key::from_bytes([
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
]),
f_cnt: device_sessions[0].f_cnt_up,
f_cnt: devices[0].device_session.as_ref().unwrap().f_cnt_up,
expected_error: Some("Invalid MIC".to_string()),
..Default::default()
},
@ -1242,7 +1296,10 @@ pub mod test {
0x04, 0x04, 0x04,
]),
f_cnt: 0,
expected_dev_eui: EUI64::from_slice(&device_sessions[2].dev_eui).unwrap(),
expected_dev_eui: EUI64::from_slice(
&devices[2].device_session.as_ref().unwrap().dev_eui,
)
.unwrap(),
expected_fcnt_up: 0,
expected_retransmission: false,
expected_error: None,
@ -1260,7 +1317,10 @@ pub mod test {
0x05, 0x05, 0x05,
]),
f_cnt: (1 << 16) + 11,
expected_dev_eui: EUI64::from_slice(&device_sessions[3].dev_eui).unwrap(),
expected_dev_eui: EUI64::from_slice(
&devices[3].device_session.as_ref().unwrap().dev_eui,
)
.unwrap(),
expected_fcnt_up: (1 << 16) + 11,
expected_retransmission: false,
expected_error: None,
@ -1302,18 +1362,18 @@ pub mod test {
pl.fhdr.f_cnt = tst.f_cnt % (1 << 16);
}
let ds_res = get_for_phypayload_and_incr_f_cnt_up(false, &mut phy, 0, 0).await;
let d = get_for_phypayload_and_incr_f_cnt_up(false, &mut phy, 0, 0).await;
if tst.expected_error.is_some() {
assert_eq!(true, ds_res.is_err());
assert_eq!(true, d.is_err());
assert_eq!(
tst.expected_error.as_ref().unwrap(),
&ds_res.err().unwrap().to_string()
&d.err().unwrap().to_string()
);
if let lrwn::Payload::MACPayload(pl) = &phy.payload {
assert_eq!(tst.f_cnt, pl.fhdr.f_cnt);
}
} else {
let ds = ds_res.unwrap();
let ds = d.device_session.unwrap();
// Validate that the f_cnt of the PhyPayload was set to the full frame-counter.
if let lrwn::Payload::MACPayload(pl) = &phy.payload {

View File

@ -6,7 +6,7 @@ use prost::Message;
use super::error::Error;
use super::{get_async_redis_conn, redis_key};
use chirpstack_api::internal;
use lrwn::{EUI64};
use lrwn::EUI64;
pub async fn get(dev_eui: &EUI64) -> Result<internal::DeviceSession, Error> {
let key = redis_key(format!("device:{{{}}}:ds", dev_eui));
@ -19,7 +19,7 @@ pub async fn get(dev_eui: &EUI64) -> Result<internal::DeviceSession, Error> {
if v.is_empty() {
return Err(Error::NotFound(dev_eui.to_string()));
}
let ds = internal::DeviceSession::decode(&mut Cursor::new(v))
.context("Decode device-session")?;
let ds =
internal::DeviceSession::decode(&mut Cursor::new(v)).context("Decode device-session")?;
Ok(ds)
}
}

View File

@ -3,7 +3,6 @@ use std::str::FromStr;
use anyhow::{Context, Result};
use chrono::{DateTime, Duration, Local, Utc};
use prost::Message;
use tracing::{debug, error, info, span, trace, warn, Instrument, Level};
use super::error::Error;
@ -41,7 +40,6 @@ pub struct Data {
retransmission: bool,
f_cnt_up_full: u32,
tenant: Option<tenant::Tenant>,
device_session: Option<internal::DeviceSession>,
device: Option<device::Device>,
device_profile: Option<device_profile::DeviceProfile>,
application: Option<application::Application>,
@ -101,7 +99,6 @@ impl Data {
reset: false,
retransmission: false,
tenant: None,
device_session: None,
device: None,
device_profile: None,
application: None,
@ -115,7 +112,7 @@ impl Data {
};
ctx.handle_passive_roaming_device().await?;
ctx.get_device_session().await?;
ctx.get_device_for_phy_payload().await?;
ctx.get_device_data().await?;
ctx.check_roaming_allowed()?;
@ -150,7 +147,6 @@ impl Data {
ctx.detect_and_save_measurements().await?;
ctx.sync_uplink_f_cnt()?;
ctx.set_region_config_id()?;
ctx.save_device_session().await?;
ctx.update_device().await?;
ctx.handle_uplink_ack().await?;
ctx.save_metrics().await?;
@ -178,7 +174,6 @@ impl Data {
reset: false,
retransmission: false,
tenant: None,
device_session: None,
device: None,
device_profile: None,
application: None,
@ -190,7 +185,7 @@ impl Data {
device_changeset: Default::default(),
};
ctx.get_device_session_relayed().await?;
ctx.get_device_for_phy_payload_relayed().await?;
ctx.get_device_data().await?;
ctx.set_device_info()?;
ctx.set_relay_rx_info()?;
@ -207,7 +202,6 @@ impl Data {
ctx.detect_and_save_measurements().await?;
ctx.sync_uplink_f_cnt()?;
ctx.set_region_config_id()?;
ctx.save_device_session().await?;
ctx.update_device().await?;
ctx.handle_uplink_ack().await?;
ctx.save_metrics_relayed().await?;
@ -234,8 +228,8 @@ impl Data {
Ok(())
}
async fn get_device_session(&mut self) -> Result<(), Error> {
trace!("Getting device-session for dev_addr");
async fn get_device_for_phy_payload(&mut self) -> Result<(), Error> {
trace!("Getting device for PhyPayload");
let dev_addr = if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload {
pl.fhdr.devaddr
@ -252,18 +246,18 @@ impl Data {
.await
{
Ok(v) => match v {
device::ValidationStatus::Ok(f_cnt, ds) => {
self.device_session = Some(ds);
device::ValidationStatus::Ok(f_cnt, d) => {
self.device = Some(d);
self.f_cnt_up_full = f_cnt;
}
device::ValidationStatus::Retransmission(f_cnt, ds) => {
device::ValidationStatus::Retransmission(f_cnt, d) => {
self.retransmission = true;
self.device_session = Some(ds);
self.device = Some(d);
self.f_cnt_up_full = f_cnt;
}
device::ValidationStatus::Reset(f_cnt, ds) => {
device::ValidationStatus::Reset(f_cnt, d) => {
self.reset = true;
self.device_session = Some(ds);
self.device = Some(d);
self.f_cnt_up_full = f_cnt;
}
},
@ -293,8 +287,8 @@ impl Data {
Ok(())
}
async fn get_device_session_relayed(&mut self) -> Result<(), Error> {
trace!("Getting device-session for dev_addr (relayed)");
async fn get_device_for_phy_payload_relayed(&mut self) -> Result<(), Error> {
trace!("Getting device for PhyPayload (relayed)");
let relay_ctx = self.relay_context.as_ref().unwrap();
@ -315,18 +309,18 @@ impl Data {
.await
{
Ok(v) => match v {
device::ValidationStatus::Ok(f_cnt, ds) => {
self.device_session = Some(ds);
device::ValidationStatus::Ok(f_cnt, d) => {
self.device = Some(d);
self.f_cnt_up_full = f_cnt;
}
device::ValidationStatus::Retransmission(f_cnt, ds) => {
device::ValidationStatus::Retransmission(f_cnt, d) => {
self.retransmission = true;
self.device_session = Some(ds);
self.device = Some(d);
self.f_cnt_up_full = f_cnt;
}
device::ValidationStatus::Reset(f_cnt, ds) => {
device::ValidationStatus::Reset(f_cnt, d) => {
self.reset = true;
self.device_session = Some(ds);
self.device = Some(d);
self.f_cnt_up_full = f_cnt;
}
},
@ -352,8 +346,9 @@ impl Data {
async fn get_device_data(&mut self) -> Result<()> {
trace!("Getting device data");
let dev_eui = lrwn::EUI64::from_slice(&self.device_session.as_ref().unwrap().dev_eui)?;
let (dev, app, t, dp) = get_all_device_data(dev_eui).await?;
let dev_eui = self.device.as_ref().unwrap().dev_eui;
let (_, app, t, dp) = get_all_device_data(dev_eui).await?;
if dp.region != self.uplink_frame_set.region_common_name {
return Err(anyhow!("Invalid device-profile region"));
@ -362,7 +357,6 @@ impl Data {
self.tenant = Some(t);
self.application = Some(app);
self.device_profile = Some(dp);
self.device = Some(dev);
Ok(())
}
@ -424,9 +418,10 @@ impl Data {
fn set_device_gateway_rx_info(&mut self) -> Result<()> {
trace!("Setting gateway rx-info for device");
let d = self.device.as_ref().unwrap();
self.device_gateway_rx_info = Some(internal::DeviceGatewayRxInfo {
dev_eui: self.device_session.as_ref().unwrap().dev_eui.clone(),
dev_eui: d.dev_eui.to_vec(),
dr: self.uplink_frame_set.dr as u32,
items: self
.uplink_frame_set
@ -562,12 +557,11 @@ impl Data {
// Restore the device-session in case of an error (no gateways available).
// This is because during the fcnt validation, we immediately store the
// device-session with incremented fcnt to avoid race conditions.
let d = self.device.as_ref().unwrap();
device::partial_update(
self.device.as_ref().unwrap().dev_eui,
d.dev_eui,
&device::DeviceChangeset {
device_session: Some(Some(
self.device_session.as_ref().unwrap().encode_to_vec(),
)),
device_session: Some(d.device_session.clone()),
..Default::default()
},
)
@ -591,7 +585,13 @@ impl Data {
fn decrypt_f_opts_mac_commands(&mut self) -> Result<()> {
trace!("Decrypting mac-commands");
let ds = self.device_session.as_ref().unwrap();
let ds = self
.device
.as_ref()
.unwrap()
.device_session
.as_ref()
.unwrap();
if ds.mac_version().to_string().starts_with("1.0") {
if let Err(e) = self.phy_payload.decode_f_opts_to_mac_commands() {
// This avoids failing in case of a corrupted mac-command in the frm_payload.
@ -610,7 +610,13 @@ impl Data {
fn decrypt_frm_payload(&mut self) -> Result<()> {
trace!("Decrypting FRMPayload");
let ds = self.device_session.as_ref().unwrap();
let ds = self
.device
.as_ref()
.unwrap()
.device_session
.as_ref()
.unwrap();
let mut f_port = 0;
if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload {
@ -650,7 +656,13 @@ impl Data {
fn set_adr(&mut self) -> Result<()> {
trace!("Set ADR flag in device-session");
let ds = self.device_session.as_mut().unwrap();
let ds = self
.device
.as_mut()
.unwrap()
.device_session
.as_mut()
.unwrap();
if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload {
ds.adr = pl.fhdr.f_ctrl.adr;
}
@ -659,14 +671,14 @@ impl Data {
async fn set_uplink_data_rate(&mut self) -> Result<()> {
trace!("Set uplink data-rate and reset tx-power on change");
let device = self.device.as_ref().unwrap();
let device = self.device.as_mut().unwrap();
self.device_changeset.last_seen_at = Some(Some(Utc::now()));
if device.dr.is_none() || self.uplink_frame_set.dr as i16 != device.dr.unwrap_or_default() {
self.device_changeset.dr = Some(Some(self.uplink_frame_set.dr.into()));
}
let ds = self.device_session.as_mut().unwrap();
let ds = device.get_device_session_mut()?;
// The node changed its data-rate. Possibly the node did also reset its
// tx-power to max power. Because of this, we need to reset the tx-power
// and the uplink history at the network-server side too.
@ -689,7 +701,7 @@ impl Data {
self.device_changeset.dr = Some(Some(self.uplink_frame_set.dr.into()));
}
let ds = self.device_session.as_mut().unwrap();
let ds = device.get_device_session_mut()?;
// The node changed its data-rate. Possibly the node did also reset its
// tx-power to max power. Because of this, we need to reset the tx-power
// and the uplink history at the network-server side too.
@ -773,11 +785,12 @@ impl Data {
// device did not reset these).
fn reset_channels_on_adr_ack_req(&mut self) -> Result<()> {
trace!("Reset channels on adr ack req");
let d = self.device.as_mut().unwrap();
if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload {
if pl.fhdr.f_ctrl.adr_ack_req {
let region_conf = region::get(&self.uplink_frame_set.region_config_id)?;
let ds = self.device_session.as_mut().unwrap();
let ds = d.device_session.as_mut().unwrap();
// We reset the device-session enabled_uplink_channel_indices and
// extra_uplink_channels. On the downlink path, the mac-command handling will
@ -807,8 +820,7 @@ impl Data {
self.tenant.as_ref().unwrap(),
self.application.as_ref().unwrap(),
self.device_profile.as_ref().unwrap(),
self.device.as_ref().unwrap(),
self.device_session.as_mut().unwrap(),
self.device.as_mut().unwrap(),
)
.await
.context("Handle uplink mac-commands")?;
@ -825,8 +837,7 @@ impl Data {
self.tenant.as_ref().unwrap(),
self.application.as_ref().unwrap(),
self.device_profile.as_ref().unwrap(),
self.device.as_ref().unwrap(),
self.device_session.as_mut().unwrap(),
self.device.as_mut().unwrap(),
)
.await
.context("Handle uplink mac-commands")?;
@ -850,7 +861,13 @@ impl Data {
}
fn append_meta_data_to_uplink_history(&mut self) -> Result<()> {
let ds = self.device_session.as_mut().unwrap();
let ds = self
.device
.as_mut()
.unwrap()
.device_session
.as_mut()
.unwrap();
// ignore re-transmissions we don't know the source of the
// re-transmission (it might be a replay-attack)
@ -895,7 +912,13 @@ impl Data {
fn append_meta_data_to_uplink_history_relayed(&mut self) -> Result<()> {
trace!("Apping meta-data of relayed uplink to upink history");
let ds = self.device_session.as_mut().unwrap();
let ds = self
.device
.as_mut()
.unwrap()
.device_session
.as_mut()
.unwrap();
let relay_ctx = self.relay_context.as_ref().unwrap();
// ignore re-transmissions we don't know the source of the
@ -932,7 +955,7 @@ impl Data {
let app = self.application.as_ref().unwrap();
let dp = self.device_profile.as_ref().unwrap();
let dev = self.device.as_ref().unwrap();
let ds = self.device_session.as_ref().unwrap();
let ds = dev.device_session.as_ref().unwrap();
let mac = if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload {
pl
} else {
@ -1095,7 +1118,8 @@ impl Data {
// required.
fn sync_uplink_f_cnt(&mut self) -> Result<()> {
trace!("Syncing uplink frame-counter");
let ds = self.device_session.as_mut().unwrap();
let d = self.device.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
ds.f_cnt_up = self.f_cnt_up_full + 1;
Ok(())
}
@ -1105,21 +1129,18 @@ impl Data {
// value is not set initially.
fn set_region_config_id(&mut self) -> Result<()> {
trace!("Setting region_config_id to device-session");
let ds = self.device_session.as_mut().unwrap();
let d = self.device.as_mut().unwrap();
let ds = d.get_device_session_mut()?;
ds.region_config_id = self.uplink_frame_set.region_config_id.clone();
Ok(())
}
async fn save_device_session(&mut self) -> Result<()> {
trace!("Setting device-session");
let ds = self.device_session.as_ref().unwrap();
self.device_changeset.device_session = Some(Some(ds.encode_to_vec()));
Ok(())
}
async fn update_device(&mut self) -> Result<()> {
trace!("Updating device");
let d = self.device.as_mut().unwrap();
self.device_changeset.device_session = Some(d.device_session.clone());
*d = device::partial_update(d.dev_eui, &self.device_changeset).await?;
Ok(())
}
@ -1274,7 +1295,6 @@ impl Data {
self.application.as_ref().cloned().unwrap(),
self.device_profile.as_ref().cloned().unwrap(),
self.device.as_ref().cloned().unwrap(),
self.device_session.as_ref().cloned().unwrap(),
pl.fhdr.f_ctrl.adr_ack_req || self.must_send_downlink,
self.phy_payload.mhdr.m_type == lrwn::MType::ConfirmedDataUp,
self.downlink_mac_commands.clone(),
@ -1300,7 +1320,6 @@ impl Data {
self.application.as_ref().cloned().unwrap(),
self.device_profile.as_ref().cloned().unwrap(),
self.device.as_ref().cloned().unwrap(),
self.device_session.as_ref().cloned().unwrap(),
pl.fhdr.f_ctrl.adr_ack_req || self.must_send_downlink,
self.phy_payload.mhdr.m_type == lrwn::MType::ConfirmedDataUp,
self.downlink_mac_commands.clone(),
@ -1323,7 +1342,6 @@ impl Data {
req: pl.clone(),
device: self.device.as_ref().unwrap().clone(),
device_profile: self.device_profile.as_ref().unwrap().clone(),
device_session: self.device_session.as_ref().unwrap().clone(),
must_ack: self.phy_payload.mhdr.m_type
== lrwn::MType::ConfirmedDataUp,
must_send_downlink: relay_pl.fhdr.f_ctrl.adr_ack_req,
@ -1338,7 +1356,6 @@ impl Data {
req: pl.clone(),
device: self.device.as_ref().unwrap().clone(),
device_profile: self.device_profile.as_ref().unwrap().clone(),
device_session: self.device_session.as_ref().unwrap().clone(),
must_ack: self.phy_payload.mhdr.m_type
== lrwn::MType::ConfirmedDataUp,
must_send_downlink: relay_pl.fhdr.f_ctrl.adr_ack_req,
@ -1378,7 +1395,13 @@ impl Data {
}
fn _is_end_to_end_encrypted(&self) -> bool {
let ds = self.device_session.as_ref().unwrap();
let ds = self
.device
.as_ref()
.unwrap()
.device_session
.as_ref()
.unwrap();
if !ds.js_session_key_id.is_empty() {
return true;

View File

@ -3,12 +3,11 @@ use std::sync::Arc;
use anyhow::{Context, Result};
use chrono::{DateTime, Local, Utc};
use prost::Message;
use tracing::{error, info, span, trace, warn, Instrument, Level};
use lrwn::{
keys, AES128Key, CFList, DLSettings, DevAddr, JoinAcceptPayload, JoinRequestPayload, JoinType,
MType, Major, Payload, PhyPayload, MHDR,
keys, AES128Key, CFList, DLSettings, JoinAcceptPayload, JoinRequestPayload, JoinType, MType,
Major, Payload, PhyPayload, MHDR,
};
use super::error::Error;
@ -40,12 +39,10 @@ pub struct JoinRequest {
join_request: Option<JoinRequestPayload>,
join_accept: Option<PhyPayload>,
device: Option<device::Device>,
device_session: Option<internal::DeviceSession>,
application: Option<application::Application>,
tenant: Option<tenant::Tenant>,
device_profile: Option<device_profile::DeviceProfile>,
device_keys: Option<device_keys::DeviceKeys>,
dev_addr: Option<DevAddr>,
device_info: Option<integration_pb::DeviceInfo>,
relay_rx_info: Option<integration_pb::UplinkRelayRxInfo>,
f_nwk_s_int_key: Option<AES128Key>,
@ -53,7 +50,6 @@ pub struct JoinRequest {
nwk_s_enc_key: Option<AES128Key>,
app_s_key: Option<common::KeyEnvelope>,
js_session_key_id: Vec<u8>,
device_changeset: device::DeviceChangeset,
}
impl JoinRequest {
@ -97,12 +93,10 @@ impl JoinRequest {
js_client: None,
join_request: None,
device: None,
device_session: None,
application: None,
tenant: None,
device_profile: None,
device_keys: None,
dev_addr: None,
join_accept: None,
device_info: None,
relay_rx_info: None,
@ -111,7 +105,6 @@ impl JoinRequest {
nwk_s_enc_key: None,
app_s_key: None,
js_session_key_id: vec![],
device_changeset: Default::default(),
};
ctx.get_join_request_payload()?;
@ -132,7 +125,7 @@ impl JoinRequest {
ctx.abort_on_relay_only_comm()?;
ctx.log_uplink_frame_set().await?;
ctx.abort_on_otaa_is_disabled()?;
ctx.get_random_dev_addr()?;
ctx.set_random_dev_addr()?;
if ctx.js_client.is_some() {
// Using join-server
ctx.get_join_accept_from_js().await?;
@ -146,8 +139,6 @@ impl JoinRequest {
ctx.set_device_session().await?;
ctx.flush_device_queue().await?;
ctx.set_device_mode().await?;
ctx.set_dev_addr().await?;
ctx.set_join_eui().await?;
ctx.update_device().await?;
ctx.start_downlink_join_accept_flow().await?;
ctx.send_join_event().await?;
@ -162,12 +153,10 @@ impl JoinRequest {
js_client: None,
join_request: None,
device: None,
device_session: None,
application: None,
tenant: None,
device_profile: None,
device_keys: None,
dev_addr: None,
join_accept: None,
device_info: None,
relay_rx_info: None,
@ -176,7 +165,6 @@ impl JoinRequest {
nwk_s_enc_key: None,
app_s_key: None,
js_session_key_id: vec![],
device_changeset: Default::default(),
};
ctx.get_join_request_payload_relayed()?;
@ -187,7 +175,7 @@ impl JoinRequest {
ctx.abort_on_device_is_disabled()?;
ctx.abort_on_otaa_is_disabled()?;
ctx.abort_on_relay_only_comm()?;
ctx.get_random_dev_addr()?;
ctx.set_random_dev_addr()?;
if ctx.js_client.is_some() {
// Using join-server
ctx.get_join_accept_from_js().await?;
@ -200,8 +188,6 @@ impl JoinRequest {
ctx.set_device_session().await?;
ctx.flush_device_queue().await?;
ctx.set_device_mode().await?;
ctx.set_dev_addr().await?;
ctx.set_join_eui().await?;
ctx.update_device().await?;
ctx.start_downlink_join_accept_flow_relayed().await?;
ctx.send_join_event().await?;
@ -519,8 +505,10 @@ impl JoinRequest {
Ok(())
}
fn get_random_dev_addr(&mut self) -> Result<()> {
self.dev_addr = Some(get_random_dev_addr());
fn set_random_dev_addr(&mut self) -> Result<()> {
trace!("Setting random DevAddr");
let d = self.device.as_mut().unwrap();
d.dev_addr = Some(get_random_dev_addr());
Ok(())
}
@ -555,7 +543,7 @@ impl JoinRequest {
mac_version: dp.mac_version.to_string(),
phy_payload: phy_b,
dev_eui: dev.dev_eui.to_vec(),
dev_addr: self.dev_addr.unwrap().to_vec(),
dev_addr: dev.dev_addr.unwrap().to_vec(),
dl_settings: dl_settings.to_le_bytes()?.to_vec(),
rx_delay: region_network.rx1_delay,
cf_list: match region_conf.get_cf_list(dp.mac_version) {
@ -624,6 +612,7 @@ impl JoinRequest {
let region_conf = region::get(&self.uplink_frame_set.region_config_id)?;
let join_request = self.join_request.as_ref().unwrap();
let d = self.device.as_ref().unwrap();
let dk = self.device_keys.as_mut().unwrap();
let join_nonce = dk.join_nonce - 1; // this was incremented on validation
@ -648,7 +637,7 @@ impl JoinRequest {
payload: Payload::JoinAccept(JoinAcceptPayload {
join_nonce: join_nonce as u32,
home_netid: conf.network.net_id,
devaddr: self.dev_addr.unwrap(),
devaddr: d.dev_addr.unwrap(),
dl_settings: DLSettings {
opt_neg,
rx2_dr: region_network.rx2_dr,
@ -779,15 +768,12 @@ impl JoinRequest {
let region_conf = region::get(&self.uplink_frame_set.region_config_id)?;
let region_network = config::get_region_network(&self.uplink_frame_set.region_config_id)?;
let device = self.device.as_ref().unwrap();
let device = self.device.as_mut().unwrap();
let device_profile = self.device_profile.as_ref().unwrap();
let join_request = self.join_request.as_ref().unwrap();
let mut ds = internal::DeviceSession {
region_config_id: self.uplink_frame_set.region_config_id.clone(),
dev_eui: device.dev_eui.to_be_bytes().to_vec(),
dev_addr: self.dev_addr.unwrap().to_be_bytes().to_vec(),
join_eui: join_request.join_eui.to_be_bytes().to_vec(),
dev_addr: device.dev_addr.unwrap().to_be_bytes().to_vec(),
f_nwk_s_int_key: self.f_nwk_s_int_key.as_ref().unwrap().to_vec(),
s_nwk_s_int_key: self.s_nwk_s_int_key.as_ref().unwrap().to_vec(),
nwk_s_enc_key: self.nwk_s_enc_key.as_ref().unwrap().to_vec(),
@ -852,8 +838,7 @@ impl JoinRequest {
None => {}
}
self.device_changeset.device_session = Some(Some(ds.encode_to_vec()));
self.device_session = Some(ds);
device.device_session = Some(ds);
Ok(())
}
@ -872,35 +857,37 @@ impl JoinRequest {
async fn set_device_mode(&mut self) -> Result<()> {
let dp = self.device_profile.as_ref().unwrap();
let d = self.device.as_mut().unwrap();
// LoRaWAN 1.1 devices send a mac-command when changing to Class-C.
if dp.supports_class_c && dp.mac_version.to_string().starts_with("1.0") {
self.device_changeset.enabled_class = Some(DeviceClass::C);
d.enabled_class = DeviceClass::C;
} else {
self.device_changeset.enabled_class = Some(DeviceClass::A);
d.enabled_class = DeviceClass::A;
}
Ok(())
}
async fn set_dev_addr(&mut self) -> Result<()> {
trace!("Setting DevAddr");
self.device_changeset.dev_addr = Some(Some(self.dev_addr.unwrap()));
self.device_changeset.secondary_dev_addr = Some(None);
Ok(())
}
async fn set_join_eui(&mut self) -> Result<()> {
trace!("Setting JoinEUI");
let req = self.join_request.as_ref().unwrap();
self.device_changeset.join_eui = Some(req.join_eui);
Ok(())
}
async fn update_device(&mut self) -> Result<()> {
trace!("Updating device");
let req = self.join_request.as_ref().unwrap();
let d = self.device.as_mut().unwrap();
*d = device::partial_update(d.dev_eui, &self.device_changeset).await?;
*d = device::partial_update(
d.dev_eui,
&device::DeviceChangeset {
enabled_class: Some(d.enabled_class),
dev_addr: Some(d.dev_addr),
secondary_dev_addr: Some(None),
join_eui: Some(req.join_eui),
device_session: Some(d.device_session.clone()),
..Default::default()
},
)
.await?;
Ok(())
}
@ -910,7 +897,6 @@ impl JoinRequest {
&self.uplink_frame_set,
self.tenant.as_ref().unwrap(),
self.device.as_ref().unwrap(),
self.device_session.as_ref().unwrap(),
self.join_accept.as_ref().unwrap(),
)
.await?;
@ -924,7 +910,6 @@ impl JoinRequest {
&self.uplink_frame_set,
self.tenant.as_ref().unwrap(),
self.device.as_ref().unwrap(),
self.device_session.as_ref().unwrap(),
self.join_accept.as_ref().unwrap(),
)
.await?;
@ -945,7 +930,7 @@ impl JoinRequest {
time: Some(ts.into()),
device_info: self.device_info.clone(),
relay_rx_info: self.relay_rx_info.clone(),
dev_addr: self.dev_addr.as_ref().unwrap().to_string(),
dev_addr: dev.dev_addr.unwrap().to_string(),
join_server_context: if !self.js_session_key_id.is_empty() {
Some(common::JoinServerContext {
app_s_key: None,

View File

@ -2,7 +2,6 @@ use std::sync::Arc;
use anyhow::{Context, Result};
use chrono::{DateTime, Local, Utc};
use prost::Message;
use tracing::{span, trace, Instrument, Level};
use super::{error::Error, helpers, UplinkFrameSet};
@ -29,7 +28,6 @@ pub struct JoinRequest {
join_request: Option<lrwn::JoinRequestPayload>,
join_accept: Option<lrwn::PhyPayload>,
device: Option<device::Device>,
device_session: Option<internal::DeviceSession>,
js_client: Option<Arc<backend::Client>>,
application: Option<application::Application>,
tenant: Option<tenant::Tenant>,
@ -67,7 +65,6 @@ impl JoinRequest {
join_request: None,
join_accept: None,
device: None,
device_session: None,
js_client: None,
application: None,
tenant: None,
@ -100,7 +97,7 @@ impl JoinRequest {
ctx.construct_join_accept_and_set_keys()?;
}
ctx.log_uplink_meta().await?;
ctx.create_device_session().await?;
ctx.set_device_session().await?;
ctx.flush_device_queue().await?;
ctx.update_device().await?;
ctx.send_join_event().await?;
@ -562,21 +559,18 @@ impl JoinRequest {
Ok(())
}
async fn create_device_session(&mut self) -> Result<()> {
trace!("Creating device-session");
async fn set_device_session(&mut self) -> Result<()> {
trace!("Setting device-session");
let region_conf = region::get(&self.uplink_frame_set.region_config_id)?;
let region_network = config::get_region_network(&self.uplink_frame_set.region_config_id)?;
let device = self.device.as_ref().unwrap();
let device = self.device.as_mut().unwrap();
let device_profile = self.device_profile.as_ref().unwrap();
let join_request = self.join_request.as_ref().unwrap();
let mut ds = internal::DeviceSession {
region_config_id: self.uplink_frame_set.region_config_id.clone(),
dev_eui: device.dev_eui.to_be_bytes().to_vec(),
dev_addr: self.dev_addr.unwrap().to_be_bytes().to_vec(),
join_eui: join_request.join_eui.to_be_bytes().to_vec(),
f_nwk_s_int_key: self.f_nwk_s_int_key.as_ref().unwrap().to_vec(),
s_nwk_s_int_key: self.s_nwk_s_int_key.as_ref().unwrap().to_vec(),
nwk_s_enc_key: self.nwk_s_enc_key.as_ref().unwrap().to_vec(),
@ -627,7 +621,7 @@ impl JoinRequest {
}
}
self.device_session = Some(ds);
device.device_session = Some(ds);
Ok(())
}
@ -647,14 +641,19 @@ impl JoinRequest {
async fn update_device(&mut self) -> Result<()> {
trace!("Updating device");
let dp = self.device_profile.as_ref().unwrap();
let ds = self
.device
.as_ref()
.unwrap()
.device_session
.as_ref()
.unwrap();
self.device = Some(
device::partial_update(
self.device.as_ref().unwrap().dev_eui,
&device::DeviceChangeset {
device_session: Some(Some(
self.device_session.as_ref().unwrap().encode_to_vec(),
)),
device_session: Some(Some(ds.clone())),
join_eui: Some(self.join_request.as_ref().unwrap().join_eui),
dev_addr: Some(Some(self.dev_addr.unwrap())),
secondary_dev_addr: Some(None),
@ -717,7 +716,9 @@ impl JoinRequest {
fn set_pr_start_ans_payload(&mut self) -> Result<()> {
trace!("Setting PRStartAnsPayload");
let ds = self.device_session.as_ref().unwrap();
let d = self.device.as_ref().unwrap();
let ds = d.get_device_session()?;
let region_conf = region::get(&self.uplink_frame_set.region_config_id)?;
let sender_id = NetID::from_slice(&self.pr_start_req.base.sender_id)?;
@ -756,8 +757,8 @@ impl JoinRequest {
.base
.to_base_payload_result(backend::ResultCode::Success, ""),
phy_payload: self.join_accept.as_ref().unwrap().to_vec()?,
dev_eui: ds.dev_eui.clone(),
dev_addr: ds.dev_addr.clone(),
dev_eui: d.dev_eui.to_vec(),
dev_addr: d.get_dev_addr()?.to_vec(),
lifetime: if pr_lifetime.is_zero() {
None
} else {
@ -767,7 +768,7 @@ impl JoinRequest {
nwk_s_key,
f_cnt_up: Some(0),
dl_meta_data: Some(backend::DLMetaData {
dev_eui: ds.dev_eui.clone(),
dev_eui: d.dev_eui.to_vec(),
dl_freq_1: Some(rx1_freq as f64 / 1_000_000.0),
dl_freq_2: Some(rx2_freq as f64 / 1_000_000.0),
rx_delay_1: Some(rx1_delay.as_secs() as usize),

View File

@ -21,7 +21,7 @@ use crate::storage::{
device, device_profile, error::Error as StorageError, gateway, get_async_redis_conn, redis_key,
};
use crate::stream;
use chirpstack_api::{common, gw, internal, stream as stream_pb};
use chirpstack_api::{common, gw, stream as stream_pb};
use lrwn::region::CommonName;
use lrwn::{ForwardUplinkReq, MType, PhyPayload, EUI64};
@ -75,7 +75,6 @@ pub struct RelayContext {
pub req: ForwardUplinkReq,
pub device: device::Device,
pub device_profile: device_profile::DeviceProfile,
pub device_session: internal::DeviceSession,
pub must_ack: bool,
pub must_send_downlink: bool,
}