Skip to main content

matc/
messages.rs

1use anyhow::{Context, Result};
2use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
3use core::fmt;
4use rand::RngCore;
5use std::io::{Read, Write};
6
7use crate::tlv::{self, TlvItem, TlvItemEnc, TlvItemValueEnc};
8
9#[derive(Debug)]
10pub struct MessageHeader {
11    pub flags: u8,
12    pub security_flags: u8,
13    pub session_id: u16,
14    pub message_counter: u32,
15    pub source_node_id: Option<Vec<u8>>,
16    pub destination_node_id: Option<Vec<u8>>,
17}
18
19impl MessageHeader {
20    const FLAG_SRC_PRESENT: u8 = 4;
21    const DSIZ_64: u8 = 1;
22    const DSIZ_16: u8 = 2;
23    pub fn encode(&self) -> Result<Vec<u8>> {
24        let mut flags: u8 = 0;
25        if self.source_node_id.as_ref().is_some_and(|x| x.len() == 8) {
26            flags |= Self::FLAG_SRC_PRESENT;
27        }
28        if let Some(destination_node_id) = &self.destination_node_id {
29            if destination_node_id.len() == 2 {
30                flags |= Self::DSIZ_16
31            } else if destination_node_id.len() == 8 {
32                flags |= Self::DSIZ_64
33            }
34        }
35        let mut out = Vec::with_capacity(1024);
36        out.write_u8(flags)?;
37        out.write_u16::<LittleEndian>(self.session_id)?;
38        out.write_u8(self.security_flags)?;
39        out.write_u32::<LittleEndian>(self.message_counter)?;
40        if let Some(sn) = &self.source_node_id {
41            if sn.len() == 8 {
42                out.write_all(sn)?;
43            }
44        }
45        if let Some(destination_node_id) = &self.destination_node_id {
46            out.write_all(destination_node_id)?;
47        }
48        Ok(out)
49    }
50    pub fn decode(data: &[u8]) -> Result<(Self, Vec<u8>)> {
51        let mut cursor = std::io::Cursor::new(data);
52        let flags = cursor.read_u8()?;
53        let session_id = cursor.read_u16::<LittleEndian>()?;
54        let security_flags = cursor.read_u8()?;
55        let message_counter = cursor.read_u32::<LittleEndian>()?;
56        let source_node_id = if (flags & Self::FLAG_SRC_PRESENT) != 0 {
57            let mut sn = vec![0; 8];
58            cursor.read_exact(sn.as_mut())?;
59            Some(sn)
60        } else {
61            None
62        };
63        let destination_node_id = if (flags & 3) != 0 {
64            let dst_size = match flags & 3 {
65                Self::DSIZ_64 => 8,
66                Self::DSIZ_16 => 2,
67                _ => 0,
68            };
69            if dst_size > 0 {
70                let mut dn = vec![0; dst_size];
71                cursor.read_exact(dn.as_mut())?;
72                Some(dn)
73            } else {
74                None
75            }
76        } else {
77            None
78        };
79        let mut rest = Vec::new();
80        cursor.read_to_end(&mut rest)?;
81        Ok((
82            Self {
83                flags,
84                security_flags,
85                session_id,
86                message_counter,
87                source_node_id,
88                destination_node_id,
89            },
90            rest,
91        ))
92    }
93}
94
95/*#[derive(Debug)]
96enum SecChannelOpcode {
97    None = 0x0,
98    Ack = 0x10,
99    PbkdfReq = 0x20,
100    PbkdfResp = 0x21,
101    Pake1 = 0x22,
102    Pake2 = 0x23,
103    Pake3 = 0x24,
104    Sigma1 = 0x30,
105    Sigma2 = 0x31,
106    Sigma3 = 0x32,
107    Status = 0x40,
108}*/
109
110#[derive(Debug)]
111pub struct ProtocolMessageHeader {
112    pub exchange_flags: u8,
113    pub opcode: u8,
114    pub exchange_id: u16,
115    pub protocol_id: u16,
116    pub ack_counter: u32,
117}
118
119impl ProtocolMessageHeader {
120    pub const FLAG_INITIATOR: u8 = 1;
121    pub const FLAG_ACK: u8 = 2;
122    pub const FLAG_RELIABILITY: u8 = 4;
123
124    pub const OPCODE_ACK: u8 = 0x10;
125    pub const OPCODE_PBKDF_REQ: u8 = 0x20;
126    pub const OPCODE_PBKDF_RESP: u8 = 0x21;
127    pub const OPCODE_PASE_PAKE1: u8 = 0x22;
128    pub const OPCODE_PASE_PAKE2: u8 = 0x23;
129    pub const OPCODE_PASE_PAKE3: u8 = 0x24;
130    pub const OPCODE_CASE_SIGMA1: u8 = 0x30;
131    pub const OPCODE_CASE_SIGMA2: u8 = 0x31;
132    pub const OPCODE_CASE_SIGMA3: u8 = 0x32;
133    pub const OPCODE_STATUS: u8 = 0x40;
134
135    pub const INTERACTION_OPCODE_STATUS_RESP:    u8 = 0x1;
136    pub const INTERACTION_OPCODE_READ_REQ:       u8 = 0x2;
137    pub const INTERACTION_OPCODE_SUBSCRIBE_REQ:  u8 = 0x3;
138    pub const INTERACTION_OPCODE_SUBSCRIBE_RESP: u8 = 0x4;
139    pub const INTERACTION_OPCODE_REPORT_DATA:    u8 = 0x5;
140    pub const INTERACTION_OPCODE_WRITE_REQ:      u8 = 0x6;
141    pub const INTERACTION_OPCODE_WRITE_RESP:     u8 = 0x7;
142    pub const INTERACTION_OPCODE_INVOKE_REQ:     u8 = 0x8;
143    pub const INTERACTION_OPCODE_INVOKE_RESP:    u8 = 0x9;
144    pub const INTERACTION_OPCODE_TIMED_REQ:      u8 = 0xa;
145
146    pub const PROTOCOL_ID_SECURE_CHANNEL: u16 = 0;
147    pub const PROTOCOL_ID_INTERACTION: u16 = 1;
148
149    pub const IM_STATUS_UNSUPPORTED_ATTRIBUTE: u8 = 0x86;
150    pub const IM_STATUS_INVALID_ACTION:        u8 = 0x80;
151    pub const IM_STATUS_UNSUPPORTED_CLUSTER:   u8 = 0xC3;
152    pub const IM_STATUS_UNSUPPORTED_EVENT:     u8 = 0xC7;
153
154    pub fn encode(&self) -> Result<Vec<u8>> {
155        let mut out = Vec::with_capacity(1024);
156        out.write_u8(self.exchange_flags)?;
157        out.write_u8(self.opcode)?;
158        out.write_u16::<LittleEndian>(self.exchange_id)?;
159        out.write_u16::<LittleEndian>(self.protocol_id)?;
160        if (self.exchange_flags & Self::FLAG_ACK) != 0 {
161            out.write_u32::<LittleEndian>(self.ack_counter)?;
162        }
163        Ok(out)
164    }
165    pub fn decode(data: &[u8]) -> Result<(Self, Vec<u8>)> {
166        let mut cursor = std::io::Cursor::new(data);
167        let exchange_flags = cursor.read_u8()?;
168        let opcode = cursor.read_u8()?;
169        let exchange_id = cursor.read_u16::<LittleEndian>()?;
170        let protocol_id = cursor.read_u16::<LittleEndian>()?;
171        let mut ack_counter = 0;
172        if (exchange_flags & Self::FLAG_ACK) != 0 {
173            ack_counter = cursor.read_u32::<LittleEndian>()?;
174        }
175        let mut rest = Vec::new();
176        cursor.read_to_end(&mut rest)?;
177        Ok((
178            Self {
179                exchange_flags,
180                opcode,
181                exchange_id,
182                protocol_id,
183                ack_counter,
184            },
185            rest,
186        ))
187    }
188}
189
190
191#[derive(Debug, Clone, Copy)]
192pub enum SecureChannelGeneralCode {
193    Success = 0,
194    Failure = 1,
195    BadPrecondition = 2,
196    OutOfRange = 3,
197    BadRequest = 4,
198    Unsupported = 5,
199    Unexpected = 6,
200    ResourceExhausted = 7,
201    Busy = 8,
202    Timeout = 9,
203    Continue = 10,
204    Aborted = 11,
205    InvalidArgument = 12,
206    NotFound = 13,
207    AlreadyExists = 14,
208    PermissionDenied = 15,
209    DataLoss = 16,
210    MessageTooLarge = 17,
211    Unknown = 0xffff
212}
213
214impl From<u16> for SecureChannelGeneralCode {
215    fn from(value: u16) -> Self {
216        match value {
217            0 => SecureChannelGeneralCode::Success,
218            1 => SecureChannelGeneralCode::Failure,
219            2 => SecureChannelGeneralCode::BadPrecondition,
220            3 => SecureChannelGeneralCode::OutOfRange,
221            4 => SecureChannelGeneralCode::BadRequest,
222            5 => SecureChannelGeneralCode::Unsupported,
223            6 => SecureChannelGeneralCode::Unexpected,
224            7 => SecureChannelGeneralCode::ResourceExhausted,
225            8 => SecureChannelGeneralCode::Busy,
226            9 => SecureChannelGeneralCode::Timeout,
227            10 => SecureChannelGeneralCode::Continue,
228            11 => SecureChannelGeneralCode::Aborted,
229            12 => SecureChannelGeneralCode::InvalidArgument,
230            13 => SecureChannelGeneralCode::NotFound,
231            14 => SecureChannelGeneralCode::AlreadyExists,
232            15 => SecureChannelGeneralCode::PermissionDenied,
233            16 => SecureChannelGeneralCode::DataLoss,
234            17 => SecureChannelGeneralCode::MessageTooLarge,
235            _ => SecureChannelGeneralCode::Unknown
236        }
237    }
238}
239
240impl std::fmt::Display for SecureChannelGeneralCode {
241    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
242        match self {
243            SecureChannelGeneralCode::Success => write!(f, "SUCCESS"),
244            SecureChannelGeneralCode::Failure => write!(f, "FAILURE"),
245            SecureChannelGeneralCode::BadPrecondition => write!(f, "BAD_PRECONDITION"),
246            SecureChannelGeneralCode::OutOfRange => write!(f, "OUT_OF_RANGE"),
247            SecureChannelGeneralCode::BadRequest => write!(f, "BAD_REQUEST"),
248            SecureChannelGeneralCode::Unsupported => write!(f, "UNSUPPORTED"),
249            SecureChannelGeneralCode::Unexpected => write!(f, "UNEXPECTED"),
250            SecureChannelGeneralCode::ResourceExhausted => write!(f, "RESOURCE_EXHAUSTED"),
251            SecureChannelGeneralCode::Busy => write!(f, "BUSY"),
252            SecureChannelGeneralCode::Timeout => write!(f, "TIMEOUT"),
253            SecureChannelGeneralCode::Continue => write!(f, "CONTINUE"),
254            SecureChannelGeneralCode::Aborted => write!(f, "ABORTED"),
255            SecureChannelGeneralCode::InvalidArgument => write!(f, "INVALID_ARGUMENT"),
256            SecureChannelGeneralCode::NotFound => write!(f, "NOT_FOUND"),
257            SecureChannelGeneralCode::AlreadyExists => write!(f, "ALREADY_EXISTS"),
258            SecureChannelGeneralCode::PermissionDenied => write!(f, "PERMISSION_DENIED"),
259            SecureChannelGeneralCode::DataLoss => write!(f, "DATA_LOSS"),
260            SecureChannelGeneralCode::MessageTooLarge => write!(f, "MESSAGE_TOO_LARGE"),
261            SecureChannelGeneralCode::Unknown => write!(f, "UNKNOWN {}", *self as u16),
262        }
263    }
264}
265
266#[derive(Debug, Clone, Copy)]
267pub enum SecureChannelProtocolCode {
268    SessionEstablishmentSuccess = 0,
269    NoSharedTrustRoots = 1,
270    InvalidParameter = 2,
271    CloseSession = 3,
272    Busy = 4,
273    RequiredCatMismatch = 5,
274    Unknown = 0xffff
275}
276
277impl std::fmt::Display for SecureChannelProtocolCode {
278    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279        match self {
280            SecureChannelProtocolCode::SessionEstablishmentSuccess => write!(f, "SESSION_ESTABLISHMENT_SUCCESS"),
281            SecureChannelProtocolCode::NoSharedTrustRoots => write!(f, "NO_SHARED_TRUST_ROOTS"),
282            SecureChannelProtocolCode::InvalidParameter => write!(f, "INVALID_PARAMETER"),
283            SecureChannelProtocolCode::CloseSession => write!(f, "CLOSE_SESSION"),
284            SecureChannelProtocolCode::Busy => write!(f, "BUSY"),
285            SecureChannelProtocolCode::RequiredCatMismatch => write!(f, "REQUIRED_CAT_MISMATCH"),
286            SecureChannelProtocolCode::Unknown => write!(f, "UNKNOWN {}", *self as u16),
287        }
288    }
289}
290
291impl From<u16> for SecureChannelProtocolCode {
292    fn from(value: u16) -> Self {
293        match value {
294            0 => SecureChannelProtocolCode::SessionEstablishmentSuccess,
295            1 => SecureChannelProtocolCode::NoSharedTrustRoots,
296            2 => SecureChannelProtocolCode::InvalidParameter,
297            3 => SecureChannelProtocolCode::CloseSession,
298            4 => SecureChannelProtocolCode::Busy,
299            5 => SecureChannelProtocolCode::RequiredCatMismatch,
300            _ => SecureChannelProtocolCode::Unknown,
301        }
302    }
303}
304
305#[derive(Debug, Clone)]
306pub struct StatusReportInfo {
307    general_code: u16,
308    protocol_id: u32,
309    protocol_code: u16,
310    protocol_data: Vec<u8>,
311}
312impl std::fmt::Display for StatusReportInfo {
313    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
314        if self.general_code == 0 {
315            return write!(f, "StatusReportInfo: OK");
316        }
317        let gc = Into::<SecureChannelGeneralCode>::into(self.general_code);
318        match self.protocol_id as u16{
319            ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL => {
320                let pc = Into::<SecureChannelProtocolCode>::into(self.protocol_code);
321                write!(
322                    f,
323                    "StatusReportInfo: general_code={}, protocol_id={}, protocol_code={}",
324                    gc, self.protocol_id, pc
325                )
326
327            },
328            _ => {
329                write!(f, "StatusReportInfo: general_code={}, protocol_id={}, protocol_code={}",
330                    gc, self.protocol_id, self.protocol_code
331                )
332            }
333
334        }
335    }
336}
337impl StatusReportInfo {
338    pub fn parse(data: &[u8]) -> Result<Self> {
339        let mut cursor = std::io::Cursor::new(data);
340        let general_code = cursor.read_u16::<LittleEndian>()?;
341        let protocol_id = cursor.read_u32::<LittleEndian>()?;
342        let protocol_code = cursor.read_u16::<LittleEndian>()?;
343        let mut protocol_data = Vec::new();
344        cursor.read_to_end(&mut protocol_data).ok();
345        Ok(Self {
346            general_code,
347            protocol_id,
348            protocol_code,
349            protocol_data,
350        })
351    }
352    pub fn is_ok(&self) -> bool {
353        self.general_code == 0 && self.protocol_id == 0 && self.protocol_code == 0
354    }
355    pub fn is_busy(&self) -> bool {
356        self.general_code == SecureChannelGeneralCode::Busy as u16
357            && self.protocol_id == ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL as u32
358            && self.protocol_code == SecureChannelProtocolCode::Busy as u16
359    }
360    /// Returns the Minimum Wait Time (ms) from the protocol-specific data of a SC BUSY response.
361    /// Per Matter spec this is u32 LE; some stacks emit u16 -- both are accepted.
362    pub fn minimum_wait_time_ms(&self) -> Option<u32> {
363        if !self.is_busy() { return None; }
364        match self.protocol_data.len() {
365            n if n >= 4 => Some(u32::from_le_bytes(self.protocol_data[..4].try_into().ok()?)),
366            2 => Some(u16::from_le_bytes(self.protocol_data[..2].try_into().ok()?) as u32),
367            _ => None,
368        }
369    }
370}
371
372pub struct Message {
373    pub message_header: MessageHeader,
374    pub protocol_header: ProtocolMessageHeader,
375    pub payload: Vec<u8>,
376    pub tlv: TlvItem,
377    pub status_report_info: Option<StatusReportInfo>,
378}
379
380impl fmt::Debug for Message {
381    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
382        f.debug_struct("Message")
383            .field("message_header", &self.message_header)
384            .field("protocol_header", &self.protocol_header)
385            .field("payload", &hex::encode(&self.payload))
386            .field("tlv", &self.tlv)
387            .field("status_report_info", &self.status_report_info)
388            .finish()
389    }
390}
391
392impl Message {
393    pub fn decode(data: &[u8]) -> Result<Self> {
394        let (message_header, rest) = MessageHeader::decode(data)?;
395        let (protocol_header, rest) = ProtocolMessageHeader::decode(&rest)?;
396        if (protocol_header.protocol_id == ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL)
397            && (protocol_header.opcode == ProtocolMessageHeader::OPCODE_STATUS)
398        {
399            let status_report_info = StatusReportInfo::parse(&rest)?;
400            return Ok(Self {
401                message_header,
402                protocol_header,
403                payload: rest,
404                tlv: TlvItem {
405                    tag: 0,
406                    value: tlv::TlvItemValue::Invalid(),
407                },
408                status_report_info: Some(status_report_info),
409            });
410        }
411        let tlv = tlv::decode_tlv(&rest)?;
412        Ok(Self {
413            message_header,
414            protocol_header,
415            payload: rest,
416            tlv,
417            status_report_info: None,
418        })
419    }
420}
421
422pub fn ack(exchange: u16, ack: i64) -> Result<Vec<u8>> {
423    let mut flags = ProtocolMessageHeader::FLAG_INITIATOR;
424    flags |= ProtocolMessageHeader::FLAG_ACK;
425    ProtocolMessageHeader {
426        exchange_flags: flags,
427        opcode: ProtocolMessageHeader::OPCODE_ACK,
428        exchange_id: exchange,
429        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
430        ack_counter: ack as u32,
431    }
432    .encode()
433}
434
435pub fn pbkdf_req(exchange: u16) -> Result<Vec<u8>> {
436    let mut b = ProtocolMessageHeader {
437        exchange_flags: ProtocolMessageHeader::FLAG_INITIATOR
438            | ProtocolMessageHeader::FLAG_RELIABILITY,
439        opcode: ProtocolMessageHeader::OPCODE_PBKDF_REQ,
440        exchange_id: exchange,
441        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
442        ack_counter: 0,
443    }
444    .encode()?;
445    let mut tlv = tlv::TlvBuffer::new();
446    tlv.write_anon_struct()?;
447    let mut initiator_random = [0u8; 32];
448    rand::thread_rng().fill_bytes(&mut initiator_random);
449    tlv.write_octetstring(0x1, &initiator_random)?;
450    tlv.write_uint16(2, 1)?;
451    tlv.write_uint8(3, 0)?;
452    tlv.write_bool(4, false)?;
453    tlv.write_struct_end()?;
454    b.write_all(&tlv.data)?;
455    Ok(b)
456}
457
458pub fn pake1(exchange: u16, key: &[u8], ack: i64) -> Result<Vec<u8>> {
459    let mut flags = ProtocolMessageHeader::FLAG_INITIATOR | ProtocolMessageHeader::FLAG_RELIABILITY;
460    if ack >= 0 {
461        flags |= ProtocolMessageHeader::FLAG_ACK
462    }
463    let mut b = ProtocolMessageHeader {
464        exchange_flags: flags,
465        opcode: ProtocolMessageHeader::OPCODE_PASE_PAKE1,
466        exchange_id: exchange,
467        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
468        ack_counter: ack as u32,
469    }
470    .encode()?;
471
472    let tlv = TlvItemEnc {
473        tag: 0,
474        value: TlvItemValueEnc::StructAnon(vec![TlvItemEnc {
475            tag: 1,
476            value: TlvItemValueEnc::OctetString(key.to_owned()),
477        }]),
478    }
479    .encode()?;
480    b.write_all(&tlv)?;
481
482    Ok(b)
483}
484
485pub fn pake3(exchange: u16, key: &[u8], ack: i64) -> Result<Vec<u8>> {
486    let mut flags = 0x5;
487    if ack >= 0 {
488        flags |= 2
489    }
490    let mut b = ProtocolMessageHeader {
491        exchange_flags: flags,
492        opcode: ProtocolMessageHeader::OPCODE_PASE_PAKE3,
493        exchange_id: exchange,
494        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
495        ack_counter: ack as u32,
496    }
497    .encode()?;
498    let mut tlv = tlv::TlvBuffer::new();
499    tlv.write_anon_struct()?;
500    tlv.write_octetstring(0x1, key)?;
501    tlv.write_struct_end()?;
502
503    b.write_all(&tlv.data)?;
504    Ok(b)
505}
506
507pub fn status_report_success(exchange: u16) -> Result<Vec<u8>> {
508    let mut b = ProtocolMessageHeader {
509        exchange_flags: ProtocolMessageHeader::FLAG_INITIATOR,
510        opcode: ProtocolMessageHeader::OPCODE_STATUS,
511        exchange_id: exchange,
512        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
513        ack_counter: 0,
514    }
515    .encode()?;
516    b.write_u16::<LittleEndian>(0)?; // GeneralStatusCode::SUCCESS
517    b.write_u32::<LittleEndian>(0)?; // ProtocolId::SECURE_CHANNEL
518    b.write_u16::<LittleEndian>(0)?; // ProtocolCode::SUCCESS
519    Ok(b)
520}
521
522pub fn sigma1(exchange: u16, payload: &[u8]) -> Result<Vec<u8>> {
523    let mut b = ProtocolMessageHeader {
524        exchange_flags: 5,
525        opcode: ProtocolMessageHeader::OPCODE_CASE_SIGMA1,
526        exchange_id: exchange,
527        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
528        ack_counter: 0,
529    }
530    .encode()?;
531    b.write_all(payload)?;
532    Ok(b)
533}
534
535pub fn sigma3(exchange: u16, payload: &[u8], ack: u32) -> Result<Vec<u8>> {
536    let mut b = ProtocolMessageHeader {
537        exchange_flags: 5 | ProtocolMessageHeader::FLAG_ACK,
538        opcode: ProtocolMessageHeader::OPCODE_CASE_SIGMA3,
539        exchange_id: exchange,
540        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
541        ack_counter: ack,
542    }
543    .encode()?;
544    b.write_all(payload)?;
545    Ok(b)
546}
547
548pub fn im_invoke_request(
549    endpoint: u16,
550    cluster: u32,
551    command: u32,
552    exchange_id: u16,
553    payload: &[u8],
554    timed: bool,
555) -> Result<Vec<u8>> {
556    let b = ProtocolMessageHeader {
557        exchange_flags: 5,
558        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_INVOKE_REQ,
559        exchange_id,
560        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
561        ack_counter: 0,
562    }
563    .encode()?;
564
565    let mut tlv = tlv::TlvBuffer::from_vec(b);
566    tlv.write_anon_struct()?;
567    tlv.write_bool(0x0, false)?;
568    tlv.write_bool(0x1, timed)?; // timed
569    tlv.write_array(2)?;
570    tlv.write_anon_struct()?;
571    tlv.write_list(0)?;
572    tlv.write_uint16(0, endpoint)?;
573    tlv.write_uint32(1, cluster)?;
574    tlv.write_uint32(2, command)?;
575    tlv.write_struct_end()?;
576    tlv.write_struct(1)?;
577    tlv.write_raw(payload)?;
578    tlv.write_struct_end()?;
579    tlv.write_struct_end()?;
580    tlv.write_struct_end()?;
581    tlv.write_uint8(0xff, 10)?;
582    tlv.write_struct_end()?;
583    Ok(tlv.data)
584}
585
586pub fn im_timed_request(exchange_id: u16, timeout: u16) -> Result<Vec<u8>> {
587    let b = ProtocolMessageHeader {
588        exchange_flags: 5,
589        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_TIMED_REQ,
590        exchange_id,
591        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
592        ack_counter: 0,
593    }
594    .encode()?;
595
596    let mut tlv = tlv::TlvBuffer::from_vec(b);
597    tlv.write_anon_struct()?;
598    tlv.write_uint16(0, timeout)?;
599    tlv.write_uint8(0xff, 10)?;
600    tlv.write_struct_end()?;
601    Ok(tlv.data)
602}
603
604pub fn im_read_request(endpoint: u16, cluster: u32, attr: u32, exchange: u16) -> Result<Vec<u8>> {
605    let b = ProtocolMessageHeader {
606        exchange_flags: 5,
607        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_READ_REQ,
608        exchange_id: exchange,
609        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
610        ack_counter: 0,
611    }
612    .encode()?;
613
614    let mut tlv = tlv::TlvBuffer::from_vec(b);
615    tlv.write_anon_struct()?;
616    tlv.write_array(0)?;
617    tlv.write_anon_list()?;
618    tlv.write_uint16(2, endpoint)?;
619    tlv.write_uint32(3, cluster)?;
620    tlv.write_uint32(4, attr)?;
621    tlv.write_struct_end()?;
622    tlv.write_struct_end()?;
623    tlv.write_bool(3, true)?;
624    tlv.write_uint8(0xff, 10)?;
625    tlv.write_struct_end()?;
626    Ok(tlv.data)
627}
628
629pub fn im_write_request(endpoint: u16, cluster: u32, attr: u32, exchange: u16, data: &[u8]) -> Result<Vec<u8>> {
630    let b = ProtocolMessageHeader {
631        exchange_flags: 5,
632        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_WRITE_REQ,
633        exchange_id: exchange,
634        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
635        ack_counter: 0,
636    }
637    .encode()?;
638
639    let mut tlv = tlv::TlvBuffer::from_vec(b);
640    tlv.write_anon_struct()?;
641    //tlv.write_bool(0, false)?;
642    tlv.write_bool(1, false)?; // timed
643    tlv.write_array(2)?;
644    tlv.write_anon_struct()?;
645    //tlv.write_uint32(0, 0)?; // dataversion
646    tlv.write_list(1)?;
647    tlv.write_uint16(2, endpoint)?;
648    tlv.write_uint32(3, cluster)?;
649    tlv.write_uint32(4, attr)?;
650    tlv.write_struct_end()?;
651    tlv.write_raw(data)?;
652    tlv.write_struct_end()?;
653    tlv.write_struct_end()?;
654    tlv.write_bool(3, false)?;
655    tlv.write_uint8(0xff, 10)?; // InteractionModelRevision
656    tlv.write_struct_end()?;
657    Ok(tlv.data)
658}
659
660/// Build a SubscribeRequest for an attribute path (AttributeRequests, tag 3).
661/// `keep_subscriptions`: if true the device keeps existing subscriptions alive;
662/// if false the device cancels all prior subscriptions before creating this one.
663pub fn im_subscribe_request_attr(endpoint: Option<u16>, cluster: Option<u32>, attr: Option<u32>, exchange: u16, keep_subscriptions: bool) -> Result<Vec<u8>> {
664    let b = ProtocolMessageHeader {
665        exchange_flags: 5,
666        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_SUBSCRIBE_REQ,
667        exchange_id: exchange,
668        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
669        ack_counter: 0,
670    }
671    .encode()?;
672
673    let mut tlv = tlv::TlvBuffer::from_vec(b);
674    tlv.write_anon_struct()?;
675    tlv.write_bool(0, keep_subscriptions)?; // KeepSubscriptions
676    tlv.write_uint16(1, 10)?;       // MinIntervalFloor
677    tlv.write_uint16(2, 30)?;       // MaxIntervalCeiling
678    tlv.write_array(3)?;            // AttributeRequests
679
680    tlv.write_anon_list()?;
681    if let Some(endpoint) = endpoint {
682        tlv.write_uint16(2, endpoint)?;
683    }
684    if let Some(cluster) = cluster {
685        tlv.write_uint32(3, cluster)?;
686    }
687    if let Some(attr) = attr {
688        tlv.write_uint32(4, attr)?;
689    }
690
691    tlv.write_struct_end()?;        // end AttributePathIB
692    tlv.write_struct_end()?;        // end AttributeRequests array
693
694    tlv.write_bool(7, false)?;      // FabricFiltered
695    tlv.write_uint8(0xff, 10)?;     // InteractionModelRevision
696    tlv.write_struct_end()?;
697    Ok(tlv.data)
698}
699
700/// Build a SubscribeRequest for an event path (EventRequests, tag 4).
701/// Any `None` field is omitted from the EventPathIB, acting as a wildcard.
702pub fn im_subscribe_request_event(endpoint: Option<u16>, cluster: Option<u32>, event: Option<u32>, exchange: u16, keep_subscriptions: bool) -> Result<Vec<u8>> {
703    let b = ProtocolMessageHeader {
704        exchange_flags: 5,
705        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_SUBSCRIBE_REQ,
706        exchange_id: exchange,
707        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
708        ack_counter: 0,
709    }
710    .encode()?;
711
712    let mut tlv = tlv::TlvBuffer::from_vec(b);
713    tlv.write_anon_struct()?;
714    tlv.write_bool(0, keep_subscriptions)?;
715    tlv.write_uint16(1, 0)?;
716    tlv.write_uint16(2, 60)?;
717    tlv.write_array(4)?;            // EventRequests
718
719    tlv.write_anon_list()?;
720    if let Some(endpoint) = endpoint {
721        tlv.write_uint16(1, endpoint)?;
722    }
723    if let Some(cluster) = cluster {
724        tlv.write_uint32(2, cluster)?;
725    }
726    if let Some(event) = event {
727        tlv.write_uint32(3, event)?;
728    }
729    tlv.write_bool(4, true)?; // urgent
730
731    tlv.write_struct_end()?;        // end EventPathIB
732    tlv.write_struct_end()?;        // end EventRequests array
733
734    tlv.write_bool(7, false)?;
735    tlv.write_uint8(0xff, 10)?;
736    tlv.write_struct_end()?;
737    Ok(tlv.data)
738}
739
740/// Build a SubscribeRequest with `KeepSubscriptions = false` and no attribute/event paths.
741/// Sending this causes the device to cancel all existing subscriptions for this session.
742pub fn im_unsubscribe_all(exchange: u16) -> Result<Vec<u8>> {
743    let b = ProtocolMessageHeader {
744        exchange_flags: 5,
745        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_SUBSCRIBE_REQ,
746        exchange_id: exchange,
747        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
748        ack_counter: 0,
749    }
750    .encode()?;
751
752    let mut tlv = tlv::TlvBuffer::from_vec(b);
753    tlv.write_anon_struct()?;
754    tlv.write_bool(0, false)?;       // KeepSubscriptions = false - cancel all
755    tlv.write_uint16(1, 0)?;         // MinIntervalFloor
756    tlv.write_uint16(2, 0)?;         // MaxIntervalCeiling
757    tlv.write_array(3)?;             // AttributeRequests - empty
758    tlv.write_struct_end()?;
759    tlv.write_bool(7, false)?;       // FabricFiltered
760    tlv.write_uint8(0xff, 10)?;      // InteractionModelRevision
761    tlv.write_struct_end()?;
762    Ok(tlv.data)
763}
764
765/// Compute exchange flags for a StatusResponse acknowledging a message with
766/// `incoming_exchange_flags`. On an exchange we initiated (incoming message has
767/// FLAG_INITIATOR clear) our reply keeps FLAG_INITIATOR set; on a peer-initiated
768/// exchange it must be clear.
769pub fn im_status_flags_for(incoming_exchange_flags: u8) -> u8 {
770    if incoming_exchange_flags & ProtocolMessageHeader::FLAG_INITIATOR == 0 {
771        ProtocolMessageHeader::FLAG_INITIATOR | ProtocolMessageHeader::FLAG_ACK
772    } else {
773        ProtocolMessageHeader::FLAG_ACK
774    }
775}
776
777pub fn im_status_response(exchange: u16, flags: u8, ack: u32) -> Result<Vec<u8>> {
778    let b = ProtocolMessageHeader {
779        exchange_flags: 4 | flags,
780        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_STATUS_RESP,
781        exchange_id: exchange,
782        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
783        ack_counter: ack,
784    }
785    .encode()?;
786
787    let mut tlv = tlv::TlvBuffer::from_vec(b);
788    tlv.write_anon_struct()?;
789    tlv.write_uint8(0, 0)?;
790    tlv.write_uint8(0xff, 10)?; // InteractionModelRevision
791    tlv.write_struct_end()?;
792    Ok(tlv.data)
793}
794
795pub fn parse_im_invoke_resp(resp: &TlvItem) -> Result<(u32, u32)> {
796    let common_status = resp
797        .get_int(&[1, 0, 1, 1, 0])
798        .context("parse_im_invoke_resp: status not found")?;
799    if common_status == 0 {
800        return Ok((0, 0));
801    }
802    let stat = resp
803        .get_int(&[1, 0, 1, 1, 1])
804        .context("parse_im_invoke_resp: unexpected response")?;
805    Ok((common_status as u32, stat as u32))
806}
807
808#[cfg(test)]
809mod tests {
810    use super::Message;
811
812    #[test]
813    pub fn test_1() {
814        let msg = "04000000a5a0b90d3320764c7d52ef86052060d5000015300120cabe444262d4e5dd568c755ed77e0829b9983c4d62b480b579811ec383eb69c625020837240300280418";
815        let msg = hex::decode(msg).unwrap();
816        let m = Message::decode(&msg).unwrap();
817        println!("{:?}", m);
818
819        let msg = "04000000000000000000000000000000012001000000153001203052998af1897150086e6c84003c074df93a796b4f68a9221ee4e40325014aaf25020100240300280418";
820        let msg = hex::decode(msg).unwrap();
821        let m = Message::decode(&msg).unwrap();
822        println!("{:?}", m);
823    }
824}