From ddea09d9d47de6d624e631fe1a670e31c60f5b83 Mon Sep 17 00:00:00 2001 From: Orne Brocaar Date: Thu, 2 Mar 2023 12:21:42 +0000 Subject: [PATCH] Decode frm_payload mac-commands in device frame log. --- api/proto/internal/internal.proto | 5 ++++- .../proto/chirpstack/internal/internal.proto | 5 ++++- chirpstack/src/downlink/data.rs | 2 ++ chirpstack/src/downlink/tx_ack.rs | 7 +++++++ chirpstack/src/framelog.rs | 2 ++ lrwn/src/phy_payload.rs | 19 +++++++++++++++++++ 6 files changed, 38 insertions(+), 2 deletions(-) diff --git a/api/proto/internal/internal.proto b/api/proto/internal/internal.proto index 93823dfe..720dff91 100644 --- a/api/proto/internal/internal.proto +++ b/api/proto/internal/internal.proto @@ -229,8 +229,11 @@ message DownlinkFrame { // Encrypted FOpts (LoRaWAN 1.1). bool encrypted_fopts = 8; - // Network session encryption key (for FOpts). + // Network session encryption key (for FOpts and FRMPayload mac-commands). bytes nwk_s_enc_key = 9; + + // NFCntDown (for decrypting mac-commands). + uint32 n_f_cnt_down = 10; } message LoraCloudGeolocBuffer { diff --git a/api/rust/proto/chirpstack/internal/internal.proto b/api/rust/proto/chirpstack/internal/internal.proto index 93823dfe..720dff91 100644 --- a/api/rust/proto/chirpstack/internal/internal.proto +++ b/api/rust/proto/chirpstack/internal/internal.proto @@ -229,8 +229,11 @@ message DownlinkFrame { // Encrypted FOpts (LoRaWAN 1.1). bool encrypted_fopts = 8; - // Network session encryption key (for FOpts). + // Network session encryption key (for FOpts and FRMPayload mac-commands). bytes nwk_s_enc_key = 9; + + // NFCntDown (for decrypting mac-commands). + uint32 n_f_cnt_down = 10; } message LoraCloudGeolocBuffer { diff --git a/chirpstack/src/downlink/data.rs b/chirpstack/src/downlink/data.rs index 123a6d07..c2d61953 100644 --- a/chirpstack/src/downlink/data.rs +++ b/chirpstack/src/downlink/data.rs @@ -288,6 +288,7 @@ impl Data { // The queue item should fit within the max payload size and should not be pending // already. if qi.data.len() <= max_payload_size && !qi.is_pending { + trace!(id = %qi.id, more_in_queue = more_in_queue, "Found device queue-item for downlink"); self.device_queue_item = Some(qi); self.more_device_queue_items = more_in_queue; return Ok(()); @@ -634,6 +635,7 @@ impl Data { .starts_with("1.1"), nwk_s_enc_key: self.device_session.nwk_s_enc_key.clone(), downlink_frame: Some(self.downlink_frame.clone()), + n_f_cnt_down: self.device_session.n_f_cnt_down, ..Default::default() }) .await diff --git a/chirpstack/src/downlink/tx_ack.rs b/chirpstack/src/downlink/tx_ack.rs index 760fda38..7fb9621d 100644 --- a/chirpstack/src/downlink/tx_ack.rs +++ b/chirpstack/src/downlink/tx_ack.rs @@ -433,6 +433,13 @@ impl TxAck { let nwk_s_enc_key = AES128Key::from_slice(&df.nwk_s_enc_key)?; + if let Payload::MACPayload(pl) = &mut phy.payload { + if pl.f_port.unwrap_or(0) == 0 { + // We need to set the full NFcntDown to decrypt the mac-commands. + pl.fhdr.f_cnt = df.n_f_cnt_down; + } + } + if let Payload::MACPayload(pl) = &phy.payload { // f_port must be either None or 0 if pl.f_port.unwrap_or(0) == 0 { diff --git a/chirpstack/src/framelog.rs b/chirpstack/src/framelog.rs index aa2e1ef8..2d0c3844 100644 --- a/chirpstack/src/framelog.rs +++ b/chirpstack/src/framelog.rs @@ -283,6 +283,7 @@ pub async fn get_frame_logs( let mut phy = lrwn::PhyPayload::from_slice(&pl.phy_payload)?; if pl.plaintext_mac_commands { phy.decode_f_opts_to_mac_commands()?; + phy.decode_frm_payload_to_mac_commands()?; } let pl = api::LogItem { @@ -314,6 +315,7 @@ pub async fn get_frame_logs( let mut phy = lrwn::PhyPayload::from_slice(&pl.phy_payload)?; if pl.plaintext_mac_commands { phy.decode_f_opts_to_mac_commands()?; + phy.decode_frm_payload_to_mac_commands()?; } let pl = api::LogItem { diff --git a/lrwn/src/phy_payload.rs b/lrwn/src/phy_payload.rs index 689e2ff7..366492bd 100644 --- a/lrwn/src/phy_payload.rs +++ b/lrwn/src/phy_payload.rs @@ -654,6 +654,25 @@ impl PhyPayload { Ok(()) } + /// Decode frm_payload to mac-commands. + pub fn decode_frm_payload_to_mac_commands(&mut self) -> Result<()> { + if let Payload::MACPayload(pl) = &mut self.payload { + let uplink = is_uplink(self.mhdr.m_type); + if pl.f_port.unwrap_or(0) == 0 { + let b = match &pl.frm_payload { + Some(FRMPayload::Raw(v)) => v.clone(), + _ => vec![], + }; + + let mut macs = MACCommandSet::new(vec![MACCommand::Raw(b)]); + macs.decode_from_raw(uplink)?; + pl.frm_payload = Some(FRMPayload::MACCommandSet(macs)); + } + } + + Ok(()) + } + /// Encrypt the frm_payload with the given key. pub fn encrypt_frm_payload(&mut self, key: &AES128Key) -> Result<()> { if let Payload::MACPayload(pl) = &mut self.payload {