1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19#[repr(u8)]
20pub enum ICACCSRResponseStatusCode {
21 Ok = 0,
23 Busy = 1,
25 Pakeparametererror = 2,
27 Windownotopen = 3,
29 Vidnotverified = 4,
31 Invalidadministratorfabricindex = 5,
33}
34
35impl ICACCSRResponseStatusCode {
36 pub fn from_u8(value: u8) -> Option<Self> {
38 match value {
39 0 => Some(ICACCSRResponseStatusCode::Ok),
40 1 => Some(ICACCSRResponseStatusCode::Busy),
41 2 => Some(ICACCSRResponseStatusCode::Pakeparametererror),
42 3 => Some(ICACCSRResponseStatusCode::Windownotopen),
43 4 => Some(ICACCSRResponseStatusCode::Vidnotverified),
44 5 => Some(ICACCSRResponseStatusCode::Invalidadministratorfabricindex),
45 _ => None,
46 }
47 }
48
49 pub fn to_u8(self) -> u8 {
51 self as u8
52 }
53}
54
55impl From<ICACCSRResponseStatusCode> for u8 {
56 fn from(val: ICACCSRResponseStatusCode) -> Self {
57 val as u8
58 }
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
62#[repr(u8)]
63pub enum ICACResponseStatus {
64 Ok = 0,
66 Invalidpublickey = 1,
68 Invalidicac = 2,
70}
71
72impl ICACResponseStatus {
73 pub fn from_u8(value: u8) -> Option<Self> {
75 match value {
76 0 => Some(ICACResponseStatus::Ok),
77 1 => Some(ICACResponseStatus::Invalidpublickey),
78 2 => Some(ICACResponseStatus::Invalidicac),
79 _ => None,
80 }
81 }
82
83 pub fn to_u8(self) -> u8 {
85 self as u8
86 }
87}
88
89impl From<ICACResponseStatus> for u8 {
90 fn from(val: ICACResponseStatus) -> Self {
91 val as u8
92 }
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
96#[repr(u8)]
97pub enum TransferAnchorResponseStatus {
98 Ok = 0,
100 Transferanchorstatusdatastorebusy = 1,
102 Transferanchorstatusnouserconsent = 2,
104}
105
106impl TransferAnchorResponseStatus {
107 pub fn from_u8(value: u8) -> Option<Self> {
109 match value {
110 0 => Some(TransferAnchorResponseStatus::Ok),
111 1 => Some(TransferAnchorResponseStatus::Transferanchorstatusdatastorebusy),
112 2 => Some(TransferAnchorResponseStatus::Transferanchorstatusnouserconsent),
113 _ => None,
114 }
115 }
116
117 pub fn to_u8(self) -> u8 {
119 self as u8
120 }
121}
122
123impl From<TransferAnchorResponseStatus> for u8 {
124 fn from(val: TransferAnchorResponseStatus) -> Self {
125 val as u8
126 }
127}
128
129pub fn encode_add_icac(icac_value: Vec<u8>) -> anyhow::Result<Vec<u8>> {
133 let tlv = tlv::TlvItemEnc {
134 tag: 0,
135 value: tlv::TlvItemValueEnc::StructInvisible(vec![
136 (1, tlv::TlvItemValueEnc::OctetString(icac_value)).into(),
137 ]),
138 };
139 Ok(tlv.encode()?)
140}
141
142pub fn encode_open_joint_commissioning_window(commissioning_timeout: u16, pake_passcode_verifier: Vec<u8>, discriminator: u16, iterations: u32, salt: Vec<u8>) -> anyhow::Result<Vec<u8>> {
144 let tlv = tlv::TlvItemEnc {
145 tag: 0,
146 value: tlv::TlvItemValueEnc::StructInvisible(vec![
147 (0, tlv::TlvItemValueEnc::UInt16(commissioning_timeout)).into(),
148 (1, tlv::TlvItemValueEnc::OctetString(pake_passcode_verifier)).into(),
149 (2, tlv::TlvItemValueEnc::UInt16(discriminator)).into(),
150 (3, tlv::TlvItemValueEnc::UInt32(iterations)).into(),
151 (4, tlv::TlvItemValueEnc::OctetString(salt)).into(),
152 ]),
153 };
154 Ok(tlv.encode()?)
155}
156
157pub fn encode_announce_joint_fabric_administrator(endpoint_id: u16) -> anyhow::Result<Vec<u8>> {
159 let tlv = tlv::TlvItemEnc {
160 tag: 0,
161 value: tlv::TlvItemValueEnc::StructInvisible(vec![
162 (0, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
163 ]),
164 };
165 Ok(tlv.encode()?)
166}
167
168pub fn decode_administrator_fabric_index(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
172 if let tlv::TlvItemValue::Int(v) = inp {
173 Ok(Some(*v as u8))
174 } else {
175 Ok(None)
176 }
177}
178
179
180pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
192 if cluster_id != 0x0753 {
194 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0753, got {}\"}}", cluster_id);
195 }
196
197 match attribute_id {
198 0x0000 => {
199 match decode_administrator_fabric_index(tlv_value) {
200 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
201 Err(e) => format!("{{\"error\": \"{}\"}}", e),
202 }
203 }
204 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
205 }
206}
207
208pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
213 vec![
214 (0x0000, "AdministratorFabricIndex"),
215 ]
216}
217
218pub fn get_command_list() -> Vec<(u32, &'static str)> {
221 vec![
222 (0x00, "ICACCSRRequest"),
223 (0x02, "AddICAC"),
224 (0x04, "OpenJointCommissioningWindow"),
225 (0x05, "TransferAnchorRequest"),
226 (0x07, "TransferAnchorComplete"),
227 (0x08, "AnnounceJointFabricAdministrator"),
228 ]
229}
230
231pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
232 match cmd_id {
233 0x00 => Some("ICACCSRRequest"),
234 0x02 => Some("AddICAC"),
235 0x04 => Some("OpenJointCommissioningWindow"),
236 0x05 => Some("TransferAnchorRequest"),
237 0x07 => Some("TransferAnchorComplete"),
238 0x08 => Some("AnnounceJointFabricAdministrator"),
239 _ => None,
240 }
241}
242
243pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
244 match cmd_id {
245 0x00 => Some(vec![]),
246 0x02 => Some(vec![
247 crate::clusters::codec::CommandField { tag: 1, name: "icac_value", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
248 ]),
249 0x04 => Some(vec![
250 crate::clusters::codec::CommandField { tag: 0, name: "commissioning_timeout", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
251 crate::clusters::codec::CommandField { tag: 1, name: "pake_passcode_verifier", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
252 crate::clusters::codec::CommandField { tag: 2, name: "discriminator", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
253 crate::clusters::codec::CommandField { tag: 3, name: "iterations", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
254 crate::clusters::codec::CommandField { tag: 4, name: "salt", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
255 ]),
256 0x05 => Some(vec![]),
257 0x07 => Some(vec![]),
258 0x08 => Some(vec![
259 crate::clusters::codec::CommandField { tag: 0, name: "endpoint_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
260 ]),
261 _ => None,
262 }
263}
264
265pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
266 match cmd_id {
267 0x00 => Ok(vec![]),
268 0x02 => {
269 let icac_value = crate::clusters::codec::json_util::get_octstr(args, "icac_value")?;
270 encode_add_icac(icac_value)
271 }
272 0x04 => {
273 let commissioning_timeout = crate::clusters::codec::json_util::get_u16(args, "commissioning_timeout")?;
274 let pake_passcode_verifier = crate::clusters::codec::json_util::get_octstr(args, "pake_passcode_verifier")?;
275 let discriminator = crate::clusters::codec::json_util::get_u16(args, "discriminator")?;
276 let iterations = crate::clusters::codec::json_util::get_u32(args, "iterations")?;
277 let salt = crate::clusters::codec::json_util::get_octstr(args, "salt")?;
278 encode_open_joint_commissioning_window(commissioning_timeout, pake_passcode_verifier, discriminator, iterations, salt)
279 }
280 0x05 => Ok(vec![]),
281 0x07 => Ok(vec![]),
282 0x08 => {
283 let endpoint_id = crate::clusters::codec::json_util::get_u16(args, "endpoint_id")?;
284 encode_announce_joint_fabric_administrator(endpoint_id)
285 }
286 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
287 }
288}
289
290#[derive(Debug, serde::Serialize)]
291pub struct ICACCSRResponse {
292 pub status_code: Option<ICACCSRResponseStatusCode>,
293 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
294 pub icaccsr: Option<Vec<u8>>,
295}
296
297#[derive(Debug, serde::Serialize)]
298pub struct ICACResponse {
299 pub status_code: Option<ICACResponseStatus>,
300}
301
302#[derive(Debug, serde::Serialize)]
303pub struct TransferAnchorResponse {
304 pub status_code: Option<TransferAnchorResponseStatus>,
305}
306
307pub fn decode_icaccsr_response(inp: &tlv::TlvItemValue) -> anyhow::Result<ICACCSRResponse> {
311 if let tlv::TlvItemValue::List(_fields) = inp {
312 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
313 Ok(ICACCSRResponse {
314 status_code: item.get_int(&[0]).and_then(|v| ICACCSRResponseStatusCode::from_u8(v as u8)),
315 icaccsr: item.get_octet_string_owned(&[1]),
316 })
317 } else {
318 Err(anyhow::anyhow!("Expected struct fields"))
319 }
320}
321
322pub fn decode_icac_response(inp: &tlv::TlvItemValue) -> anyhow::Result<ICACResponse> {
324 if let tlv::TlvItemValue::List(_fields) = inp {
325 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
326 Ok(ICACResponse {
327 status_code: item.get_int(&[0]).and_then(|v| ICACResponseStatus::from_u8(v as u8)),
328 })
329 } else {
330 Err(anyhow::anyhow!("Expected struct fields"))
331 }
332}
333
334pub fn decode_transfer_anchor_response(inp: &tlv::TlvItemValue) -> anyhow::Result<TransferAnchorResponse> {
336 if let tlv::TlvItemValue::List(_fields) = inp {
337 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
338 Ok(TransferAnchorResponse {
339 status_code: item.get_int(&[0]).and_then(|v| TransferAnchorResponseStatus::from_u8(v as u8)),
340 })
341 } else {
342 Err(anyhow::anyhow!("Expected struct fields"))
343 }
344}
345
346pub async fn icaccsr_request(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ICACCSRResponse> {
350 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_ADMINISTRATOR, crate::clusters::defs::CLUSTER_JOINT_FABRIC_ADMINISTRATOR_CMD_ID_ICACCSRREQUEST, &[]).await?;
351 decode_icaccsr_response(&tlv)
352}
353
354pub async fn add_icac(conn: &crate::controller::Connection, endpoint: u16, icac_value: Vec<u8>) -> anyhow::Result<ICACResponse> {
356 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_ADMINISTRATOR, crate::clusters::defs::CLUSTER_JOINT_FABRIC_ADMINISTRATOR_CMD_ID_ADDICAC, &encode_add_icac(icac_value)?).await?;
357 decode_icac_response(&tlv)
358}
359
360pub async fn open_joint_commissioning_window(conn: &crate::controller::Connection, endpoint: u16, commissioning_timeout: u16, pake_passcode_verifier: Vec<u8>, discriminator: u16, iterations: u32, salt: Vec<u8>) -> anyhow::Result<()> {
362 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_ADMINISTRATOR, crate::clusters::defs::CLUSTER_JOINT_FABRIC_ADMINISTRATOR_CMD_ID_OPENJOINTCOMMISSIONINGWINDOW, &encode_open_joint_commissioning_window(commissioning_timeout, pake_passcode_verifier, discriminator, iterations, salt)?).await?;
363 Ok(())
364}
365
366pub async fn transfer_anchor_request(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<TransferAnchorResponse> {
368 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_ADMINISTRATOR, crate::clusters::defs::CLUSTER_JOINT_FABRIC_ADMINISTRATOR_CMD_ID_TRANSFERANCHORREQUEST, &[]).await?;
369 decode_transfer_anchor_response(&tlv)
370}
371
372pub async fn transfer_anchor_complete(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
374 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_ADMINISTRATOR, crate::clusters::defs::CLUSTER_JOINT_FABRIC_ADMINISTRATOR_CMD_ID_TRANSFERANCHORCOMPLETE, &[]).await?;
375 Ok(())
376}
377
378pub async fn announce_joint_fabric_administrator(conn: &crate::controller::Connection, endpoint: u16, endpoint_id: u16) -> anyhow::Result<()> {
380 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_ADMINISTRATOR, crate::clusters::defs::CLUSTER_JOINT_FABRIC_ADMINISTRATOR_CMD_ID_ANNOUNCEJOINTFABRICADMINISTRATOR, &encode_announce_joint_fabric_administrator(endpoint_id)?).await?;
381 Ok(())
382}
383
384pub async fn read_administrator_fabric_index(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
386 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_ADMINISTRATOR, crate::clusters::defs::CLUSTER_JOINT_FABRIC_ADMINISTRATOR_ATTR_ID_ADMINISTRATORFABRICINDEX).await?;
387 decode_administrator_fabric_index(&tlv)
388}
389