Compare commits

...

4 Commits

Author SHA1 Message Date
fd061d4657 Bump version to 4.1.1 2022-12-13 13:48:42 +00:00
e3fae6260b Make get device-session for phypayload functions update f_cnt.
This fixes the FrmPayload decryption in case of frame-counter rollover
(16lsb) as it was using the f_cnt as sent over the air (16lsb) and not
the full frame-counter (32b).

Before, these functions would return the device-session for the given
uplink PhyPayload (if a matching device-session was found), together
with the full frame-counter. However it would not modify the f_cnt of
the PhyPayload to the full frame-counter making it prone to errors like
the above.
2022-12-13 12:44:00 +00:00
07d4e89a92 Update JS API dependencies to latest versions. 2022-12-13 10:57:54 +00:00
8e7f321e93 [Rust API] Replace relative paths to .proto files with absolute paths (#69) 2022-12-13 10:37:56 +00:00
16 changed files with 238 additions and 135 deletions

8
Cargo.lock generated
View File

@ -672,7 +672,7 @@ dependencies = [
[[package]]
name = "backend"
version = "4.1.0"
version = "4.1.1"
dependencies = [
"aes-kw",
"anyhow",
@ -889,7 +889,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chirpstack"
version = "4.1.0"
version = "4.1.1"
dependencies = [
"aes",
"anyhow",
@ -968,7 +968,7 @@ dependencies = [
[[package]]
name = "chirpstack_api"
version = "4.1.0"
version = "4.1.1"
dependencies = [
"hex",
"pbjson",
@ -2207,7 +2207,7 @@ dependencies = [
[[package]]
name = "lrwn"
version = "4.1.0"
version = "4.1.1"
dependencies = [
"aes",
"anyhow",

View File

@ -1,6 +1,6 @@
{
"name": "@chirpstack/chirpstack-api-grpc-web",
"version": "4.1.0",
"version": "4.1.1",
"description": "Chirpstack gRPC-web API",
"license": "MIT",
"devDependencies": {

14
api/js/package.json vendored
View File

@ -1,17 +1,17 @@
{
"name": "@chirpstack/chirpstack-api",
"version": "4.1.0",
"version": "4.1.1",
"description": "Chirpstack JS and TS API",
"license": "MIT",
"devDependencies": {
"grpc-tools": "^1.11.2",
"grpc-tools": "^1.12.3",
"ts-protoc-gen": "^0.15.0",
"typescript": "^4.3.5"
"typescript": "^4.9.4"
},
"dependencies": {
"@grpc/grpc-js": "^1.3.7",
"@mapbox/node-pre-gyp": "^1.0.5",
"@types/google-protobuf": "^3.15.5",
"google-protobuf": "^3.17.3"
"@grpc/grpc-js": "^1.8.0",
"@mapbox/node-pre-gyp": "^1.0.10",
"@types/google-protobuf": "^3.15.6",
"google-protobuf": "^3.21.2"
}
}

82
api/js/yarn.lock vendored
View File

@ -2,25 +2,40 @@
# yarn lockfile v1
"@grpc/grpc-js@^1.3.7":
version "1.6.2"
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.6.2.tgz#fbaceefd163f4886e39501aea32a19c0fe802232"
integrity sha512-9+89Ne1K8F9u86T+l1yIV2DS+dWHYVK61SsDZN4MFTFehOOaJ4rHxa1cW8Lwdn2/6tOx7N3+SY/vfcjztOHopA==
"@grpc/grpc-js@^1.8.0":
version "1.8.0"
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.8.0.tgz#ebfbeff2b76e2991f2831e46cad27fa573396555"
integrity sha512-ySMTXQuMvvswoobvN+0LsaPf7ITO2JVfJmHxQKI4cGehNrrUms+n81BlHEX7Hl/LExji6XE3fnI9U04GSkRruA==
dependencies:
"@grpc/proto-loader" "^0.6.4"
"@grpc/proto-loader" "^0.7.0"
"@types/node" ">=12.12.47"
"@grpc/proto-loader@^0.6.4":
version "0.6.9"
resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.6.9.tgz#4014eef366da733f8e04a9ddd7376fe8a58547b7"
integrity sha512-UlcCS8VbsU9d3XTXGiEVFonN7hXk+oMXZtoHHG2oSA1/GcDP1q6OUgs20PzHDGizzyi8ufGSUDlk3O2NyY7leg==
"@grpc/proto-loader@^0.7.0":
version "0.7.4"
resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.4.tgz#4946a84fbf47c3ddd4e6a97acb79d69a9f47ebf2"
integrity sha512-MnWjkGwqQ3W8fx94/c1CwqLsNmHHv2t0CFn+9++6+cDphC1lolpg9M2OU0iebIjK//pBNX9e94ho+gjx6vz39w==
dependencies:
"@types/long" "^4.0.1"
lodash.camelcase "^4.3.0"
long "^4.0.0"
protobufjs "^6.10.0"
protobufjs "^7.0.0"
yargs "^16.2.0"
"@mapbox/node-pre-gyp@^1.0.10":
version "1.0.10"
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz#8e6735ccebbb1581e5a7e652244cadc8a844d03c"
integrity sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==
dependencies:
detect-libc "^2.0.0"
https-proxy-agent "^5.0.0"
make-dir "^3.1.0"
node-fetch "^2.6.7"
nopt "^5.0.0"
npmlog "^5.0.1"
rimraf "^3.0.2"
semver "^7.3.5"
tar "^6.1.11"
"@mapbox/node-pre-gyp@^1.0.5":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc"
@ -89,10 +104,10 @@
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
"@types/google-protobuf@^3.15.5":
version "3.15.5"
resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.15.5.tgz#644b2be0f5613b1f822c70c73c6b0e0b5b5fa2ad"
integrity sha512-6bgv24B+A2bo9AfzReeg5StdiijKzwwnRflA8RLd1V4Yv995LeTmo0z69/MPbBDFSiZWdZHQygLo/ccXhMEDgw==
"@types/google-protobuf@^3.15.6":
version "3.15.6"
resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.15.6.tgz#674a69493ef2c849b95eafe69167ea59079eb504"
integrity sha512-pYVNNJ+winC4aek+lZp93sIKxnXt5qMkuKmaqS3WGuTq0Bw1ZDYNBgzG5kkdtwcv+GmYJGo3yEg6z2cKKAiEdw==
"@types/long@^4.0.1":
version "4.0.2"
@ -266,15 +281,20 @@ glob@^7.1.3:
once "^1.3.0"
path-is-absolute "^1.0.0"
google-protobuf@^3.15.5, google-protobuf@^3.17.3:
google-protobuf@^3.15.5:
version "3.20.0"
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.20.0.tgz#8705ab5fb7e91e9578250a4a8ac533a3cc0bc0bb"
integrity sha512-hhXv5IKLDIkb0pEm53G053UZGhRAhw3wM5Jk7ly5sGIQRkO1s63FaDqM9QjlrPHygKEE2awUlLP9fFrG6M9vfQ==
grpc-tools@^1.11.2:
version "1.11.2"
resolved "https://registry.yarnpkg.com/grpc-tools/-/grpc-tools-1.11.2.tgz#22d802d40012510ccc6591d11f9c94109ac07aab"
integrity sha512-4+EgpnnkJraamY++oyBCw5Hp9huRYfgakjNVKbiE3PgO9Tv5ydVlRo7ZyGJ0C0SEiA7HhbVc1sNNtIyK7FiEtg==
google-protobuf@^3.21.2:
version "3.21.2"
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4"
integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==
grpc-tools@^1.12.3:
version "1.12.3"
resolved "https://registry.yarnpkg.com/grpc-tools/-/grpc-tools-1.12.3.tgz#bedbb880e564a52b192d693300280ed7ab45e61d"
integrity sha512-KJgk65dbGqkMuj0xiuT5uk45GcqrFfWTSqpk6Ktd0Ds2cEe9QtPQG/uWCGk185ShXCdgYFLRwfh+FyjQ3nlBNw==
dependencies:
"@mapbox/node-pre-gyp" "^1.0.5"
@ -319,6 +339,11 @@ long@^4.0.0:
resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
long@^5.0.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/long/-/long-5.2.1.tgz#e27595d0083d103d2fa2c20c7699f8e0c92b897f"
integrity sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==
lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
@ -406,10 +431,10 @@ path-is-absolute@^1.0.0:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
protobufjs@^6.10.0:
version "6.11.3"
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.3.tgz#637a527205a35caa4f3e2a9a4a13ddffe0e7af74"
integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg==
protobufjs@^7.0.0:
version "7.1.2"
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.1.2.tgz#a0cf6aeaf82f5625bffcf5a38b7cd2a7de05890c"
integrity sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==
dependencies:
"@protobufjs/aspromise" "^1.1.2"
"@protobufjs/base64" "^1.1.2"
@ -421,9 +446,8 @@ protobufjs@^6.10.0:
"@protobufjs/path" "^1.1.2"
"@protobufjs/pool" "^1.1.0"
"@protobufjs/utf8" "^1.1.0"
"@types/long" "^4.0.1"
"@types/node" ">=13.7.0"
long "^4.0.0"
long "^5.0.0"
readable-stream@^3.6.0:
version "3.6.0"
@ -520,10 +544,10 @@ ts-protoc-gen@^0.15.0:
dependencies:
google-protobuf "^3.15.5"
typescript@^4.3.5:
version "4.6.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c"
integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==
typescript@^4.9.4:
version "4.9.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78"
integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==
util-deprecate@^1.0.1:
version "1.0.2"

View File

@ -18,7 +18,7 @@ CLASSIFIERS = [
setup(
name='chirpstack-api',
version = "4.1.0",
version = "4.1.1",
url='https://github.com/brocaar/chirpstack-api',
author='Orne Brocaar',
author_email='info@brocaar.com',

2
api/rust/Cargo.lock generated vendored
View File

@ -117,7 +117,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chirpstack_api"
version = "4.1.0"
version = "4.1.1"
dependencies = [
"hex",
"pbjson",

2
api/rust/Cargo.toml vendored
View File

@ -1,7 +1,7 @@
[package]
name = "chirpstack_api"
description = "ChirpStack Protobuf / gRPC API definitions."
version = "4.1.0"
version = "4.1.1"
authors = ["Orne Brocaar <info@brocaar.com>"]
license = "MIT"
homepage = "https://www.chirpstack.io"

62
api/rust/build.rs vendored
View File

@ -7,6 +7,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let proto_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let proto_dir = Path::new(&proto_dir);
let proto_dir = proto_dir.join("proto");
let cs_dir = proto_dir.join("chirpstack");
std::fs::create_dir_all(out_dir.join("common")).unwrap();
std::fs::create_dir_all(out_dir.join("gw")).unwrap();
@ -22,7 +23,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.compile_well_known_types(true)
.extern_path(".google.protobuf", "::pbjson_types")
.compile(
&["common/common.proto"],
&[cs_dir.join("common").join("common.proto").to_str().unwrap()],
&[
proto_dir.join("chirpstack").to_str().unwrap(),
proto_dir.join("google").to_str().unwrap(),
@ -43,7 +44,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.extern_path(".google.protobuf", "::pbjson_types")
.extern_path(".common", "crate::common")
.compile(
&["gw/gw.proto"],
&[cs_dir.join("gw").join("gw.proto").to_str().unwrap()],
&[
proto_dir.join("chirpstack").to_str().unwrap(),
proto_dir.join("google").to_str().unwrap(),
@ -65,7 +66,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.extern_path(".google.protobuf", "::pbjson_types")
.extern_path(".common", "crate::common")
.compile(
&["internal/internal.proto"],
&[cs_dir
.join("internal")
.join("internal.proto")
.to_str()
.unwrap()],
&[
proto_dir.join("chirpstack").to_str().unwrap(),
proto_dir.join("google").to_str().unwrap(),
@ -88,7 +93,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.extern_path(".common", "crate::common")
.extern_path(".gw", "crate::gw")
.compile(
&["integration/integration.proto"],
&[cs_dir
.join("integration")
.join("integration.proto")
.to_str()
.unwrap()],
&[
proto_dir.join("chirpstack").to_str().unwrap(),
proto_dir.join("google").to_str().unwrap(),
@ -112,7 +121,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.extern_path(".common", "crate::common")
.extern_path(".gw", "crate::gw")
.compile(
&["meta/meta.proto"],
&[cs_dir.join("meta").join("meta.proto").to_str().unwrap()],
&[proto_dir.join("chirpstack").to_str().unwrap()],
)?;
@ -132,18 +141,37 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.extern_path(".gw", "crate::gw")
.compile(
&[
"api/internal.proto",
"api/user.proto",
"api/tenant.proto",
"api/application.proto",
"api/device_profile.proto",
"api/device_profile_template.proto",
"api/device.proto",
"api/gateway.proto",
"api/frame_log.proto",
"api/multicast_group.proto",
"api/frame_log.proto",
"api/request_log.proto",
cs_dir.join("api").join("internal.proto").to_str().unwrap(),
cs_dir.join("api").join("user.proto").to_str().unwrap(),
cs_dir.join("api").join("tenant.proto").to_str().unwrap(),
cs_dir
.join("api")
.join("application.proto")
.to_str()
.unwrap(),
cs_dir
.join("api")
.join("device_profile.proto")
.to_str()
.unwrap(),
cs_dir
.join("api")
.join("device_profile_template.proto")
.to_str()
.unwrap(),
cs_dir.join("api").join("device.proto").to_str().unwrap(),
cs_dir.join("api").join("gateway.proto").to_str().unwrap(),
cs_dir.join("api").join("frame_log.proto").to_str().unwrap(),
cs_dir
.join("api")
.join("multicast_group.proto")
.to_str()
.unwrap(),
cs_dir
.join("api")
.join("request_log.proto")
.to_str()
.unwrap(),
],
&[
proto_dir.join("chirpstack").to_str().unwrap(),

View File

@ -1,6 +1,6 @@
[package]
name = "backend"
version = "4.1.0"
version = "4.1.1"
authors = ["Orne Brocaar <info@brocaar.com>"]
edition = "2018"
publish = false

View File

@ -3,7 +3,7 @@ name = "chirpstack"
description = "ChirpStack is an open-source LoRaWAN(TM) Network Server"
repository = "https://github.com/chirpstack/chirpstack"
homepage="https://www.chirpstack.io/"
version = "4.1.0"
version = "4.1.1"
authors = ["Orne Brocaar <info@brocaar.com>"]
edition = "2021"
publish = false

View File

@ -262,7 +262,7 @@ async fn _handle_pr_start_req_data(
let region_name = region::get_region_name(region_common_name)?;
let dr = pl.ul_meta_data.data_rate.unwrap_or_default();
let ufs = UplinkFrameSet {
let mut ufs = UplinkFrameSet {
uplink_set_id: Uuid::new_v4(),
dr,
ch: helpers::get_uplink_ch(&region_name, tx_info.frequency, dr)?,
@ -280,7 +280,7 @@ async fn _handle_pr_start_req_data(
};
// get device-session
let ds = device_session::get_for_phypayload(&ufs.phy_payload, ufs.dr, ufs.ch as u8).await?;
let ds = device_session::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)?;

View File

@ -122,15 +122,13 @@ pub async fn delete(dev_eui: &EUI64) -> Result<()> {
// This function will increment the uplink frame-counter and will immediately update the
// device-session in the database, to make sure that in case this function is called multiple
// times, at most one will be valid.
// On Ok response, the PhyPayload f_cnt will be set to the full 32bit frame-counter based on the
// device-session context.
pub async fn get_for_phypayload_and_incr_f_cnt_up(
phy: &PhyPayload,
phy: &mut PhyPayload,
tx_dr: u8,
tx_ch: u8,
) -> Result<ValidationStatus, Error> {
// Clone the PhyPayload, as we will update the f_cnt to the full (32bit) frame-counter value
// for calculating the MIC.
let mut phy = phy.clone();
let mut _dev_addr = DevAddr::from_be_bytes([0x00, 0x00, 0x00, 0x00]);
let mut _f_cnt_orig = 0;
@ -150,11 +148,6 @@ pub async fn get_for_phypayload_and_incr_f_cnt_up(
}
for mut ds in device_sessions {
// Restore the original f_cnt.
if let Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = _f_cnt_orig;
}
// 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 = AES128Key::from_slice(&ds.f_nwk_s_int_key)?;
@ -236,6 +229,11 @@ pub async fn get_for_phypayload_and_incr_f_cnt_up(
return Ok(ValidationStatus::Reset(full_f_cnt, ds));
}
}
// Restore the original f_cnt.
if let Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = _f_cnt_orig;
}
}
Err(Error::InvalidMIC)
@ -244,15 +242,13 @@ pub async fn get_for_phypayload_and_incr_f_cnt_up(
// Simmilar to get_for_phypayload_and_incr_f_cnt_up, but only retrieves the device-session for the
// given PhyPayload. As it does not return the ValidationStatus, it only returns the DeviceSession
// in case of a valid frame-counter.
// On Ok response, the PhyPayload f_cnt will be set to the full 32bit frame-counter based on the
// device-session context.
pub async fn get_for_phypayload(
phy: &PhyPayload,
phy: &mut PhyPayload,
tx_dr: u8,
tx_ch: u8,
) -> Result<internal::DeviceSession, Error> {
// Clone the PhyPayload, as we will update the f_cnt to the full (32bit) frame-counter value
// for calculating the MIC.
let mut phy = phy.clone();
// Get the dev_addr and original f_cnt.
let (dev_addr, f_cnt_orig) = if let Payload::MACPayload(pl) = &phy.payload {
(pl.fhdr.devaddr, pl.fhdr.f_cnt)
@ -268,11 +264,6 @@ pub async fn get_for_phypayload(
}
for ds in device_sessions {
// Restore the original f_cnt.
if let Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = f_cnt_orig;
}
// 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 = AES128Key::from_slice(&ds.f_nwk_s_int_key)?;
@ -297,6 +288,11 @@ pub async fn get_for_phypayload(
if mic_ok && full_f_cnt >= ds.f_cnt_up {
return Ok(ds);
}
// Restore the original f_cnt.
if let Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = f_cnt_orig;
}
}
Err(Error::InvalidMIC)
@ -511,6 +507,24 @@ pub mod test {
})),
..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()
},
];
for ds in &device_sessions {
@ -628,6 +642,24 @@ pub mod test {
expected_error: None,
expected_reset: false,
},
Test {
name: "frame-counter rollover (16lsb)".to_string(),
dev_addr: DevAddr::from_be_bytes([0x01, 0x02, 0x03, 0x04]),
f_nwk_s_int_key: AES128Key::from_bytes([
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05,
]),
s_nwk_s_int_key: AES128Key::from_bytes([
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05,
]),
f_cnt: (1 << 16) + 11,
expected_dev_eui: EUI64::from_slice(&device_sessions[3].dev_eui).unwrap(),
expected_fcnt_up: (1 << 16) + 11,
expected_retransmission: false,
expected_error: None,
expected_reset: false,
},
];
for tst in &tests {
@ -658,15 +690,29 @@ pub mod test {
)
.unwrap();
let ds_res = get_for_phypayload_and_incr_f_cnt_up(&phy, 0, 0).await;
// Truncate to 16LSB (as it would be transmitted over the air).
if let lrwn::Payload::MACPayload(pl) = &mut phy.payload {
pl.fhdr.f_cnt = tst.f_cnt % (1 << 16);
}
let ds_res = get_for_phypayload_and_incr_f_cnt_up(&mut phy, 0, 0).await;
if tst.expected_error.is_some() {
assert_eq!(true, ds_res.is_err());
assert_eq!(
tst.expected_error.as_ref().unwrap(),
&ds_res.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();
// Validate that the f_cnt of the PhyPayload was set to the full frame-counter.
if let lrwn::Payload::MACPayload(pl) = &phy.payload {
assert_eq!(tst.expected_fcnt_up, pl.fhdr.f_cnt);
}
if let ValidationStatus::Ok(full_f_cnt, ds) = ds {
assert_eq!(false, tst.expected_retransmission);
assert_eq!(

View File

@ -132,53 +132,58 @@ impl Data {
async fn get_device_session(&mut self) -> Result<(), Error> {
trace!("Getting device-session for dev_addr");
if let lrwn::Payload::MACPayload(pl) = &self.uplink_frame_set.phy_payload.payload {
match device_session::get_for_phypayload_and_incr_f_cnt_up(
&self.uplink_frame_set.phy_payload,
self.uplink_frame_set.dr,
self.uplink_frame_set.ch as u8,
)
.await
{
Ok(v) => match v {
device_session::ValidationStatus::Ok(f_cnt, ds) => {
self.device_session = Some(ds);
self.f_cnt_up_full = f_cnt;
}
device_session::ValidationStatus::Retransmission(f_cnt, ds) => {
self.retransmission = true;
self.device_session = Some(ds);
self.f_cnt_up_full = f_cnt;
}
device_session::ValidationStatus::Reset(f_cnt, ds) => {
self.reset = true;
self.device_session = Some(ds);
self.f_cnt_up_full = f_cnt;
}
},
Err(e) => match e {
StorageError::NotFound(s) => {
warn!(dev_addr = %s, "No device-session exists for dev_addr");
return Err(Error::Abort);
}
StorageError::InvalidMIC => {
warn!(dev_addr = %pl.fhdr.devaddr, "None of the device-sessions for dev_addr resulted in valid MIC");
// Log uplink for null DevEUI.
let mut ufl: api::UplinkFrameLog = (&self.uplink_frame_set).try_into()?;
ufl.dev_eui = "0000000000000000".to_string();
framelog::log_uplink_for_device(&ufl).await?;
return Err(Error::Abort);
}
_ => {
return Err(Error::AnyhowError(
anyhow::Error::new(e).context("Get device-session"),
));
}
},
let dev_addr =
if let lrwn::Payload::MACPayload(pl) = &self.uplink_frame_set.phy_payload.payload {
pl.fhdr.devaddr
} else {
return Err(Error::AnyhowError(anyhow!("No MacPayload in PhyPayload")));
};
}
match device_session::get_for_phypayload_and_incr_f_cnt_up(
&mut self.uplink_frame_set.phy_payload,
self.uplink_frame_set.dr,
self.uplink_frame_set.ch as u8,
)
.await
{
Ok(v) => match v {
device_session::ValidationStatus::Ok(f_cnt, ds) => {
self.device_session = Some(ds);
self.f_cnt_up_full = f_cnt;
}
device_session::ValidationStatus::Retransmission(f_cnt, ds) => {
self.retransmission = true;
self.device_session = Some(ds);
self.f_cnt_up_full = f_cnt;
}
device_session::ValidationStatus::Reset(f_cnt, ds) => {
self.reset = true;
self.device_session = Some(ds);
self.f_cnt_up_full = f_cnt;
}
},
Err(e) => match e {
StorageError::NotFound(s) => {
warn!(dev_addr = %s, "No device-session exists for dev_addr");
return Err(Error::Abort);
}
StorageError::InvalidMIC => {
warn!(dev_addr = %dev_addr, "None of the device-sessions for dev_addr resulted in valid MIC");
// Log uplink for null DevEUI.
let mut ufl: api::UplinkFrameLog = (&self.uplink_frame_set).try_into()?;
ufl.dev_eui = "0000000000000000".to_string();
framelog::log_uplink_for_device(&ufl).await?;
return Err(Error::Abort);
}
_ => {
return Err(Error::AnyhowError(
anyhow::Error::new(e).context("Get device-session"),
));
}
},
};
Ok(())
}

View File

@ -3,7 +3,7 @@ name = "lrwn"
description = "Library for encoding / decoding LoRaWAN frames."
homepage = "https://www.chirpstack.io"
license = "MIT"
version = "4.1.0"
version = "4.1.1"
authors = ["Orne Brocaar <info@brocaar.com>"]
edition = "2018"
repository = "https://github.com/chirpstack/chirpstack"

View File

@ -1,6 +1,6 @@
{
"name": "chirpstack-ui",
"version": "4.1.0",
"version": "4.1.1",
"private": true,
"dependencies": {
"@ant-design/colors": "^6.0.0",

View File

@ -1881,7 +1881,7 @@
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@chirpstack/chirpstack-api-grpc-web@file:../api/grpc-web":
version "4.1.0"
version "4.1.1"
dependencies:
"@types/google-protobuf" "^3.15.2"
google-protobuf "^3.17.3"