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, Copy)]
306pub struct StatusReportInfo {
307    general_code: u16,
308    protocol_id: u32,
309    protocol_code: u16,
310}
311impl std::fmt::Display for StatusReportInfo {
312    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
313        if self.general_code == 0 {
314            return write!(f, "StatusReportInfo: OK");
315        }
316        let gc = Into::<SecureChannelGeneralCode>::into(self.general_code);
317        match self.protocol_id as u16{
318            ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL => {
319                let pc = Into::<SecureChannelProtocolCode>::into(self.protocol_code);
320                write!(
321                    f,
322                    "StatusReportInfo: general_code={}, protocol_id={}, protocol_code={}",
323                    gc, self.protocol_id, pc
324                )
325
326            },
327            _ => {
328                write!(f, "StatusReportInfo: general_code={}, protocol_id={}, protocol_code={}",
329                    gc, self.protocol_id, self.protocol_code
330                )
331            }
332
333        }
334    }
335}
336impl StatusReportInfo {
337    pub fn parse(data: &[u8]) -> Result<Self> {
338        let mut cursor = std::io::Cursor::new(data);
339        let general_code = cursor.read_u16::<LittleEndian>()?;
340        let protocol_id = cursor.read_u32::<LittleEndian>()?;
341        let protocol_code = cursor.read_u16::<LittleEndian>()?;
342        Ok(Self {
343            general_code,
344            protocol_id,
345            protocol_code,
346        })
347    }
348    pub fn is_ok(&self) -> bool {
349        self.general_code == 0 && self.protocol_id == 0 && self.protocol_code == 0
350    }
351}
352
353pub struct Message {
354    pub message_header: MessageHeader,
355    pub protocol_header: ProtocolMessageHeader,
356    pub payload: Vec<u8>,
357    pub tlv: TlvItem,
358    pub status_report_info: Option<StatusReportInfo>,
359}
360
361impl fmt::Debug for Message {
362    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
363        f.debug_struct("Message")
364            .field("message_header", &self.message_header)
365            .field("protocol_header", &self.protocol_header)
366            .field("payload", &hex::encode(&self.payload))
367            .field("tlv", &self.tlv)
368            .field("status_report_info", &self.status_report_info)
369            .finish()
370    }
371}
372
373impl Message {
374    pub fn decode(data: &[u8]) -> Result<Self> {
375        let (message_header, rest) = MessageHeader::decode(data)?;
376        let (protocol_header, rest) = ProtocolMessageHeader::decode(&rest)?;
377        if (protocol_header.protocol_id == ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL)
378            && (protocol_header.opcode == ProtocolMessageHeader::OPCODE_STATUS)
379        {
380            let status_report_info = StatusReportInfo::parse(&rest)?;
381            return Ok(Self {
382                message_header,
383                protocol_header,
384                payload: rest,
385                tlv: TlvItem {
386                    tag: 0,
387                    value: tlv::TlvItemValue::Invalid(),
388                },
389                status_report_info: Some(status_report_info),
390            });
391        }
392        let tlv = tlv::decode_tlv(&rest)?;
393        Ok(Self {
394            message_header,
395            protocol_header,
396            payload: rest,
397            tlv,
398            status_report_info: None,
399        })
400    }
401}
402
403pub fn ack(exchange: u16, ack: i64) -> Result<Vec<u8>> {
404    let mut flags = ProtocolMessageHeader::FLAG_INITIATOR;
405    flags |= ProtocolMessageHeader::FLAG_ACK;
406    ProtocolMessageHeader {
407        exchange_flags: flags,
408        opcode: ProtocolMessageHeader::OPCODE_ACK,
409        exchange_id: exchange,
410        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
411        ack_counter: ack as u32,
412    }
413    .encode()
414}
415
416pub fn pbkdf_req(exchange: u16) -> Result<Vec<u8>> {
417    let mut b = ProtocolMessageHeader {
418        exchange_flags: ProtocolMessageHeader::FLAG_INITIATOR
419            | ProtocolMessageHeader::FLAG_RELIABILITY,
420        opcode: ProtocolMessageHeader::OPCODE_PBKDF_REQ,
421        exchange_id: exchange,
422        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
423        ack_counter: 0,
424    }
425    .encode()?;
426    let mut tlv = tlv::TlvBuffer::new();
427    tlv.write_anon_struct()?;
428    let mut initiator_random = [0u8; 32];
429    rand::thread_rng().fill_bytes(&mut initiator_random);
430    tlv.write_octetstring(0x1, &initiator_random)?;
431    tlv.write_uint16(2, 1)?;
432    tlv.write_uint8(3, 0)?;
433    tlv.write_bool(4, false)?;
434    tlv.write_struct_end()?;
435    b.write_all(&tlv.data)?;
436    Ok(b)
437}
438
439pub fn pake1(exchange: u16, key: &[u8], ack: i64) -> Result<Vec<u8>> {
440    let mut flags = ProtocolMessageHeader::FLAG_INITIATOR | ProtocolMessageHeader::FLAG_RELIABILITY;
441    if ack >= 0 {
442        flags |= ProtocolMessageHeader::FLAG_ACK
443    }
444    let mut b = ProtocolMessageHeader {
445        exchange_flags: flags,
446        opcode: ProtocolMessageHeader::OPCODE_PASE_PAKE1,
447        exchange_id: exchange,
448        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
449        ack_counter: ack as u32,
450    }
451    .encode()?;
452
453    let tlv = TlvItemEnc {
454        tag: 0,
455        value: TlvItemValueEnc::StructAnon(vec![TlvItemEnc {
456            tag: 1,
457            value: TlvItemValueEnc::OctetString(key.to_owned()),
458        }]),
459    }
460    .encode()?;
461    b.write_all(&tlv)?;
462
463    Ok(b)
464}
465
466pub fn pake3(exchange: u16, key: &[u8], ack: i64) -> Result<Vec<u8>> {
467    let mut flags = 0x5;
468    if ack >= 0 {
469        flags |= 2
470    }
471    let mut b = ProtocolMessageHeader {
472        exchange_flags: flags,
473        opcode: ProtocolMessageHeader::OPCODE_PASE_PAKE3,
474        exchange_id: exchange,
475        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
476        ack_counter: ack as u32,
477    }
478    .encode()?;
479    let mut tlv = tlv::TlvBuffer::new();
480    tlv.write_anon_struct()?;
481    tlv.write_octetstring(0x1, key)?;
482    tlv.write_struct_end()?;
483
484    b.write_all(&tlv.data)?;
485    Ok(b)
486}
487
488pub fn sigma1(exchange: u16, payload: &[u8]) -> Result<Vec<u8>> {
489    let mut b = ProtocolMessageHeader {
490        exchange_flags: 5,
491        opcode: ProtocolMessageHeader::OPCODE_CASE_SIGMA1,
492        exchange_id: exchange,
493        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
494        ack_counter: 0,
495    }
496    .encode()?;
497    b.write_all(payload)?;
498    Ok(b)
499}
500
501pub fn sigma3(exchange: u16, payload: &[u8], ack: u32) -> Result<Vec<u8>> {
502    let mut b = ProtocolMessageHeader {
503        exchange_flags: 5 | ProtocolMessageHeader::FLAG_ACK,
504        opcode: ProtocolMessageHeader::OPCODE_CASE_SIGMA3,
505        exchange_id: exchange,
506        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_SECURE_CHANNEL,
507        ack_counter: ack,
508    }
509    .encode()?;
510    b.write_all(payload)?;
511    Ok(b)
512}
513
514pub fn im_invoke_request(
515    endpoint: u16,
516    cluster: u32,
517    command: u32,
518    exchange_id: u16,
519    payload: &[u8],
520    timed: bool,
521) -> Result<Vec<u8>> {
522    let b = ProtocolMessageHeader {
523        exchange_flags: 5,
524        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_INVOKE_REQ,
525        exchange_id,
526        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
527        ack_counter: 0,
528    }
529    .encode()?;
530
531    let mut tlv = tlv::TlvBuffer::from_vec(b);
532    tlv.write_anon_struct()?;
533    tlv.write_bool(0x0, false)?;
534    tlv.write_bool(0x1, timed)?; // timed
535    tlv.write_array(2)?;
536    tlv.write_anon_struct()?;
537    tlv.write_list(0)?;
538    tlv.write_uint16(0, endpoint)?;
539    tlv.write_uint32(1, cluster)?;
540    tlv.write_uint32(2, command)?;
541    tlv.write_struct_end()?;
542    tlv.write_struct(1)?;
543    tlv.write_raw(payload)?;
544    tlv.write_struct_end()?;
545    tlv.write_struct_end()?;
546    tlv.write_struct_end()?;
547    tlv.write_uint8(0xff, 10)?;
548    tlv.write_struct_end()?;
549    Ok(tlv.data)
550}
551
552pub fn im_timed_request(exchange_id: u16, timeout: u16) -> Result<Vec<u8>> {
553    let b = ProtocolMessageHeader {
554        exchange_flags: 5,
555        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_TIMED_REQ,
556        exchange_id,
557        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
558        ack_counter: 0,
559    }
560    .encode()?;
561
562    let mut tlv = tlv::TlvBuffer::from_vec(b);
563    tlv.write_anon_struct()?;
564    tlv.write_uint16(0, timeout)?;
565    tlv.write_uint8(0xff, 10)?;
566    tlv.write_struct_end()?;
567    Ok(tlv.data)
568}
569
570pub fn im_read_request(endpoint: u16, cluster: u32, attr: u32, exchange: u16) -> Result<Vec<u8>> {
571    let b = ProtocolMessageHeader {
572        exchange_flags: 5,
573        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_READ_REQ,
574        exchange_id: exchange,
575        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
576        ack_counter: 0,
577    }
578    .encode()?;
579
580    let mut tlv = tlv::TlvBuffer::from_vec(b);
581    tlv.write_anon_struct()?;
582    tlv.write_array(0)?;
583    tlv.write_anon_list()?;
584    tlv.write_uint16(2, endpoint)?;
585    tlv.write_uint32(3, cluster)?;
586    tlv.write_uint32(4, attr)?;
587    tlv.write_struct_end()?;
588    tlv.write_struct_end()?;
589    tlv.write_bool(3, true)?;
590    tlv.write_uint8(0xff, 10)?;
591    tlv.write_struct_end()?;
592    Ok(tlv.data)
593}
594
595pub fn im_subscribe_request(endpoint: u16, cluster: u32, exchange: u16, event: u32) -> Result<Vec<u8>> {
596    let b = ProtocolMessageHeader {
597        exchange_flags: 5,
598        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_SUBSCRIBE_REQ,
599        exchange_id: exchange,
600        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
601        ack_counter: 0,
602    }
603    .encode()?;
604
605    let mut tlv = tlv::TlvBuffer::from_vec(b);
606    tlv.write_anon_struct()?;
607    tlv.write_bool(0, false)?; // keep subscriptions
608    tlv.write_uint16(1, 10)?; // min interval
609    tlv.write_uint16(2, 30)?; // max interval
610    tlv.write_array(4)?;
611
612
613    tlv.write_anon_list()?;
614    tlv.write_uint16(1, endpoint)?;
615    tlv.write_uint32(2, cluster)?;
616    tlv.write_uint32(3, event)?;
617    tlv.write_bool(4, true)?; // urgent
618
619    tlv.write_struct_end()?;
620    tlv.write_struct_end()?;
621
622    tlv.write_bool(7, false)?;  // fabric filtered
623    tlv.write_uint8(0xff, 10)?;
624    tlv.write_struct_end()?;
625    Ok(tlv.data)
626}
627
628/// Build a SubscribeRequest for an attribute path (AttributeRequests, tag 3).
629/// `keep_subscriptions`: if true the device keeps existing subscriptions alive;
630/// if false the device cancels all prior subscriptions before creating this one.
631pub fn im_subscribe_request_attr(endpoint: u16, cluster: u32, attr: u32, exchange: u16, keep_subscriptions: bool) -> Result<Vec<u8>> {
632    let b = ProtocolMessageHeader {
633        exchange_flags: 5,
634        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_SUBSCRIBE_REQ,
635        exchange_id: exchange,
636        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
637        ack_counter: 0,
638    }
639    .encode()?;
640
641    let mut tlv = tlv::TlvBuffer::from_vec(b);
642    tlv.write_anon_struct()?;
643    tlv.write_bool(0, keep_subscriptions)?; // KeepSubscriptions
644    tlv.write_uint16(1, 10)?;       // MinIntervalFloor
645    tlv.write_uint16(2, 30)?;       // MaxIntervalCeiling
646    tlv.write_array(3)?;            // AttributeRequests
647
648    tlv.write_anon_list()?;
649    tlv.write_uint16(2, endpoint)?;
650    tlv.write_uint32(3, cluster)?;
651    tlv.write_uint32(4, attr)?;
652
653    tlv.write_struct_end()?;        // end AttributePathIB
654    tlv.write_struct_end()?;        // end AttributeRequests array
655
656    tlv.write_bool(7, false)?;      // FabricFiltered
657    tlv.write_uint8(0xff, 10)?;     // InteractionModelRevision
658    tlv.write_struct_end()?;
659    Ok(tlv.data)
660}
661
662/// Build a SubscribeRequest with `KeepSubscriptions = false` and no attribute/event paths.
663/// Sending this causes the device to cancel all existing subscriptions for this session.
664pub fn im_unsubscribe_all(exchange: u16) -> Result<Vec<u8>> {
665    let b = ProtocolMessageHeader {
666        exchange_flags: 5,
667        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_SUBSCRIBE_REQ,
668        exchange_id: exchange,
669        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
670        ack_counter: 0,
671    }
672    .encode()?;
673
674    let mut tlv = tlv::TlvBuffer::from_vec(b);
675    tlv.write_anon_struct()?;
676    tlv.write_bool(0, false)?;       // KeepSubscriptions = false - cancel all
677    tlv.write_uint16(1, 0)?;         // MinIntervalFloor
678    tlv.write_uint16(2, 0)?;         // MaxIntervalCeiling
679    tlv.write_array(3)?;             // AttributeRequests - empty
680    tlv.write_struct_end()?;
681    tlv.write_bool(7, false)?;       // FabricFiltered
682    tlv.write_uint8(0xff, 10)?;      // InteractionModelRevision
683    tlv.write_struct_end()?;
684    Ok(tlv.data)
685}
686
687pub fn im_status_response(exchange: u16, flags: u8, ack: u32) -> Result<Vec<u8>> {
688    let b = ProtocolMessageHeader {
689        exchange_flags: 4 | flags,
690        opcode: ProtocolMessageHeader::INTERACTION_OPCODE_STATUS_RESP,
691        exchange_id: exchange,
692        protocol_id: ProtocolMessageHeader::PROTOCOL_ID_INTERACTION,
693        ack_counter: ack,
694    }
695    .encode()?;
696
697    let mut tlv = tlv::TlvBuffer::from_vec(b);
698    tlv.write_anon_struct()?;
699    tlv.write_uint8(0, 0)?;
700    tlv.write_struct_end()?;
701    Ok(tlv.data)
702}
703
704pub fn parse_im_invoke_resp(resp: &TlvItem) -> Result<(u32, u32)> {
705    let common_status = resp
706        .get_int(&[1, 0, 1, 1, 0])
707        .context("parse_im_invoke_resp: status not found")?;
708    if common_status == 0 {
709        return Ok((0, 0));
710    }
711    let stat = resp
712        .get_int(&[1, 0, 1, 1, 1])
713        .context("parse_im_invoke_resp: unexpected response")?;
714    Ok((common_status as u32, stat as u32))
715}
716
717#[cfg(test)]
718mod tests {
719    use super::Message;
720
721    #[test]
722    pub fn test_1() {
723        let msg = "04000000a5a0b90d3320764c7d52ef86052060d5000015300120cabe444262d4e5dd568c755ed77e0829b9983c4d62b480b579811ec383eb69c625020837240300280418";
724        let msg = hex::decode(msg).unwrap();
725        let m = Message::decode(&msg).unwrap();
726        println!("{:?}", m);
727
728        let msg = "04000000000000000000000000000000012001000000153001203052998af1897150086e6c84003c074df93a796b4f68a9221ee4e40325014aaf25020100240300280418";
729        let msg = hex::decode(msg).unwrap();
730        let m = Message::decode(&msg).unwrap();
731        println!("{:?}", m);
732    }
733}