use anyhow::Result;
use byteorder::{LittleEndian, WriteBytesExt};
use rand::RngCore;
use std::io::Write;
use crate::messages::ProtocolMessageHeader;
use crate::tlv;
fn device_flags(ack: i64) -> u8 {
let mut flags = ProtocolMessageHeader::FLAG_RELIABILITY;
if ack >= 0 {
flags |= ProtocolMessageHeader::FLAG_ACK;
}
flags
}
fn device_flags_initiator() -> u8 {
ProtocolMessageHeader::FLAG_INITIATOR | ProtocolMessageHeader::FLAG_RELIABILITY
}
pub fn pbkdf_resp(exchange: u16, responder_session: u16, salt: &[u8], iterations: u32, ack: i64, initiator_random: &[u8]) -> Result<Vec<u8>> {
let mut b = ProtocolMessageHeader {
exchange_flags: device_flags(ack),
opcode: ProtocolMessageHeader::OPCODE_PBKDF_RESP,
exchange_id: exchange,
protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
ack_counter: ack as u32,
}
.encode()?;
let mut tlv = tlv::TlvBuffer::new();
tlv.write_anon_struct()?;
let mut responder_random = [0u8; 32];
rand::thread_rng().fill_bytes(&mut responder_random);
tlv.write_octetstring(1, initiator_random)?;
tlv.write_octetstring(2, &responder_random)?;
tlv.write_uint16(3, responder_session)?;
tlv.write_struct(4)?;
tlv.write_uint32(1, iterations)?;
tlv.write_octetstring(2, salt)?;
tlv.write_struct_end()?;
tlv.write_struct_end()?;
b.write_all(&tlv.data)?;
Ok(b)
}
pub fn pake2(exchange: u16, pb: &[u8], cb: &[u8], ack: i64) -> Result<Vec<u8>> {
let mut b = ProtocolMessageHeader {
exchange_flags: device_flags(ack),
opcode: ProtocolMessageHeader::OPCODE_PASE_PAKE2,
exchange_id: exchange,
protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
ack_counter: ack as u32,
}
.encode()?;
let mut tlv = tlv::TlvBuffer::new();
tlv.write_anon_struct()?;
tlv.write_octetstring(1, pb)?;
tlv.write_octetstring(2, cb)?;
tlv.write_struct_end()?;
b.write_all(&tlv.data)?;
Ok(b)
}
pub fn status_report(exchange: u16, general_code: u16, protocol_id: u32, protocol_code: u16, ack: i64) -> Result<Vec<u8>> {
let mut b = ProtocolMessageHeader {
exchange_flags: device_flags(ack),
opcode: ProtocolMessageHeader::OPCODE_STATUS,
exchange_id: exchange,
protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
ack_counter: ack as u32,
}
.encode()?;
b.write_u16::<LittleEndian>(general_code)?;
b.write_u32::<LittleEndian>(protocol_id)?;
b.write_u16::<LittleEndian>(protocol_code)?;
Ok(b)
}
pub fn sigma2_msg(exchange: u16, payload: &[u8], ack: i64) -> Result<Vec<u8>> {
let mut b = ProtocolMessageHeader {
exchange_flags: device_flags(ack),
opcode: ProtocolMessageHeader::OPCODE_CASE_SIGMA2,
exchange_id: exchange,
protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
ack_counter: ack as u32,
}
.encode()?;
b.write_all(payload)?;
Ok(b)
}
pub fn device_ack(exchange: u16, ack: u32) -> Result<Vec<u8>> {
ProtocolMessageHeader {
exchange_flags: ProtocolMessageHeader::FLAG_ACK,
opcode: ProtocolMessageHeader::OPCODE_ACK,
exchange_id: exchange,
protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
ack_counter: ack,
}
.encode()
}
pub fn device_ack_initiator(exchange: u16, ack: u32) -> Result<Vec<u8>> {
ProtocolMessageHeader {
exchange_flags: ProtocolMessageHeader::FLAG_INITIATOR | ProtocolMessageHeader::FLAG_ACK,
opcode: ProtocolMessageHeader::OPCODE_ACK,
exchange_id: exchange,
protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
ack_counter: ack,
}
.encode()
}
pub fn im_subscribe_response(subscription_id: u32, exchange: u16, ack: i64, max_interval: u16) -> Result<Vec<u8>> {
let b = ProtocolMessageHeader {
exchange_flags: device_flags(ack),
opcode: ProtocolMessageHeader::INTERACTION_OPCODE_SUBSCRIBE_RESP,
exchange_id: exchange,
protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
ack_counter: if ack >= 0 { ack as u32 } else { 0 },
}
.encode()?;
let mut tlv = tlv::TlvBuffer::from_vec(b);
tlv.write_anon_struct()?;
tlv.write_uint32(0, subscription_id)?;
tlv.write_uint16(2, max_interval)?;
tlv.write_struct_end()?;
Ok(tlv.data)
}
pub fn im_invoke_response_data(
exchange: u16,
endpoint: u16,
cluster: u32,
command: u32,
response_fields_tlv: &[u8],
ack: i64,
) -> Result<Vec<u8>> {
let b = ProtocolMessageHeader {
exchange_flags: device_flags(ack),
opcode: ProtocolMessageHeader::INTERACTION_OPCODE_INVOKE_RESP,
exchange_id: exchange,
protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
ack_counter: ack as u32,
}
.encode()?;
let mut tlv = tlv::TlvBuffer::from_vec(b);
tlv.write_anon_struct()?;
tlv.write_bool(0, false)?; tlv.write_array(1)?; tlv.write_anon_struct()?; tlv.write_struct(0)?; tlv.write_list(0)?; tlv.write_uint16(0, endpoint)?;
tlv.write_uint32(1, cluster)?;
tlv.write_uint32(2, command)?;
tlv.write_struct_end()?; tlv.write_struct(1)?; tlv.write_raw(response_fields_tlv)?;
tlv.write_struct_end()?; tlv.write_struct_end()?; tlv.write_struct_end()?; tlv.write_struct_end()?; tlv.write_struct_end()?; Ok(tlv.data)
}
#[derive(Clone)]
pub(crate) enum AttrReport {
Data {
endpoint: u16,
cluster: u32,
attribute: u32,
value_tlv: Vec<u8>,
},
Status {
endpoint: u16,
cluster: u32,
attribute: u32,
status: u8,
},
}
pub fn im_report_data(exchange: u16, reports: &[AttrReport], ack: i64, subscription_id: Option<u32>, more_chunks: bool) -> Result<Vec<u8>> {
let b = ProtocolMessageHeader {
exchange_flags: device_flags(ack),
opcode: ProtocolMessageHeader::INTERACTION_OPCODE_REPORT_DATA,
exchange_id: exchange,
protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
ack_counter: ack as u32,
}
.encode()?;
let mut tlv = tlv::TlvBuffer::from_vec(b);
tlv.write_anon_struct()?; if let Some(sub_id) = subscription_id {
tlv.write_uint32(0, sub_id)?; }
tlv.write_array(1)?; for report in reports {
match report {
AttrReport::Data { endpoint, cluster, attribute, value_tlv } => {
tlv.write_anon_struct()?; tlv.write_struct(1)?; tlv.write_uint32(0, 0)?; tlv.write_list(1)?; tlv.write_uint16(2, *endpoint)?; tlv.write_uint32(3, *cluster)?; tlv.write_uint32(4, *attribute)?; tlv.write_struct_end()?; tlv.write_raw(value_tlv)?; tlv.write_struct_end()?; tlv.write_struct_end()?; }
AttrReport::Status { endpoint, cluster, attribute, status } => {
tlv.write_anon_struct()?; tlv.write_struct(0)?; tlv.write_list(0)?; tlv.write_uint16(2, *endpoint)?; tlv.write_uint32(3, *cluster)?; tlv.write_uint32(4, *attribute)?; tlv.write_struct_end()?; tlv.write_struct(1)?; tlv.write_uint8(0, *status)?; tlv.write_struct_end()?; tlv.write_struct_end()?; tlv.write_struct_end()?; }
}
}
tlv.write_struct_end()?; if more_chunks {
tlv.write_bool(3, true)?; }
tlv.write_struct_end()?; Ok(tlv.data)
}
pub fn im_report_data_unsolicited(exchange: u16, reports: &[AttrReport], subscription_id: u32) -> Result<Vec<u8>> {
let b = ProtocolMessageHeader {
exchange_flags: device_flags_initiator(),
opcode: ProtocolMessageHeader::INTERACTION_OPCODE_REPORT_DATA,
exchange_id: exchange,
protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
ack_counter: 0,
}
.encode()?;
let mut tlv = tlv::TlvBuffer::from_vec(b);
tlv.write_anon_struct()?;
tlv.write_uint32(0, subscription_id)?; tlv.write_array(1)?; for report in reports {
match report {
AttrReport::Data { endpoint, cluster, attribute, value_tlv } => {
tlv.write_anon_struct()?;
tlv.write_struct(1)?;
tlv.write_uint32(0, 0)?;
tlv.write_list(1)?;
tlv.write_uint16(2, *endpoint)?;
tlv.write_uint32(3, *cluster)?;
tlv.write_uint32(4, *attribute)?;
tlv.write_struct_end()?;
tlv.write_raw(value_tlv)?;
tlv.write_struct_end()?;
tlv.write_struct_end()?;
}
AttrReport::Status { endpoint, cluster, attribute, status } => {
tlv.write_anon_struct()?;
tlv.write_struct(0)?;
tlv.write_list(0)?;
tlv.write_uint16(2, *endpoint)?;
tlv.write_uint32(3, *cluster)?;
tlv.write_uint32(4, *attribute)?;
tlv.write_struct_end()?;
tlv.write_struct(1)?;
tlv.write_uint8(0, *status)?;
tlv.write_struct_end()?;
tlv.write_struct_end()?;
tlv.write_struct_end()?;
}
}
}
tlv.write_struct_end()?; tlv.write_struct_end()?; Ok(tlv.data)
}
#[allow(dead_code)]
pub fn im_report_data_status(
exchange: u16,
endpoint: u16,
cluster: u32,
attribute: u32,
status: u8,
ack: i64,
) -> Result<Vec<u8>> {
im_report_data(exchange, &[AttrReport::Status { endpoint, cluster, attribute, status }], ack, None, false)
}
#[allow(dead_code)]
pub fn im_report_data_multi_status(
exchange: u16,
attrs: &[(u16, u32, u32, u8)],
ack: i64,
) -> Result<Vec<u8>> {
let reports: Vec<AttrReport> = attrs
.iter()
.map(|&(endpoint, cluster, attribute, status)| {
AttrReport::Status { endpoint, cluster, attribute, status }
})
.collect();
im_report_data(exchange, &reports, ack, None, false)
}
pub fn im_invoke_response_status(
exchange: u16,
endpoint: u16,
cluster: u32,
command: u32,
status: u16,
ack: i64,
) -> Result<Vec<u8>> {
let b = ProtocolMessageHeader {
exchange_flags: device_flags(ack),
opcode: ProtocolMessageHeader::INTERACTION_OPCODE_INVOKE_RESP,
exchange_id: exchange,
protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
ack_counter: ack as u32,
}
.encode()?;
let mut tlv = tlv::TlvBuffer::from_vec(b);
tlv.write_anon_struct()?;
tlv.write_bool(0, false)?;
tlv.write_array(1)?;
tlv.write_anon_struct()?;
tlv.write_struct(1)?; tlv.write_list(0)?; tlv.write_uint16(0, endpoint)?;
tlv.write_uint32(1, cluster)?;
tlv.write_uint32(2, command)?;
tlv.write_struct_end()?; tlv.write_struct(1)?; tlv.write_uint16(0, status)?;
tlv.write_struct_end()?; tlv.write_struct_end()?; tlv.write_struct_end()?; tlv.write_struct_end()?; tlv.write_struct_end()?; Ok(tlv.data)
}
pub fn im_write_response_success(exchange: u16, ack: i64, paths: &[(u16, u32, u32)]) -> Result<Vec<u8>> {
let b = ProtocolMessageHeader {
exchange_flags: device_flags(ack),
opcode: ProtocolMessageHeader::INTERACTION_OPCODE_WRITE_RESP,
exchange_id: exchange,
protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
ack_counter: ack as u32,
}
.encode()?;
let mut tlv = tlv::TlvBuffer::from_vec(b);
tlv.write_anon_struct()?;
tlv.write_array(0)?; for &(endpoint, cluster, attribute) in paths {
tlv.write_anon_struct()?; tlv.write_list(0)?; tlv.write_uint16(2, endpoint)?; tlv.write_uint32(3, cluster)?; tlv.write_uint32(4, attribute)?; tlv.write_struct_end()?; tlv.write_struct(1)?; tlv.write_uint8(0, 0)?; tlv.write_struct_end()?; tlv.write_struct_end()?; }
tlv.write_struct_end()?; tlv.write_struct_end()?; Ok(tlv.data)
}