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 GroupKeyMulticastPolicy {
21 Pergroupid = 0,
23 Allnodes = 1,
25}
26
27impl GroupKeyMulticastPolicy {
28 pub fn from_u8(value: u8) -> Option<Self> {
30 match value {
31 0 => Some(GroupKeyMulticastPolicy::Pergroupid),
32 1 => Some(GroupKeyMulticastPolicy::Allnodes),
33 _ => None,
34 }
35 }
36
37 pub fn to_u8(self) -> u8 {
39 self as u8
40 }
41}
42
43impl From<GroupKeyMulticastPolicy> for u8 {
44 fn from(val: GroupKeyMulticastPolicy) -> Self {
45 val as u8
46 }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
50#[repr(u8)]
51pub enum GroupKeySecurityPolicy {
52 Trustfirst = 0,
54 Cacheandsync = 1,
56}
57
58impl GroupKeySecurityPolicy {
59 pub fn from_u8(value: u8) -> Option<Self> {
61 match value {
62 0 => Some(GroupKeySecurityPolicy::Trustfirst),
63 1 => Some(GroupKeySecurityPolicy::Cacheandsync),
64 _ => None,
65 }
66 }
67
68 pub fn to_u8(self) -> u8 {
70 self as u8
71 }
72}
73
74impl From<GroupKeySecurityPolicy> for u8 {
75 fn from(val: GroupKeySecurityPolicy) -> Self {
76 val as u8
77 }
78}
79
80#[derive(Debug, serde::Serialize)]
83pub struct GroupInfoMap {
84 pub group_id: Option<u16>,
85 pub endpoints: Option<Vec<u16>>,
86 pub group_name: Option<String>,
87}
88
89#[derive(Debug, serde::Serialize)]
90pub struct GroupKeyMap {
91 pub group_id: Option<u16>,
92 pub group_key_set_id: Option<u16>,
93}
94
95#[derive(Debug, serde::Serialize)]
96pub struct GroupKeySet {
97 pub group_key_set_id: Option<u16>,
98 pub group_key_security_policy: Option<GroupKeySecurityPolicy>,
99 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
100 pub epoch_key0: Option<Vec<u8>>,
101 pub epoch_start_time0: Option<u64>,
102 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
103 pub epoch_key1: Option<Vec<u8>>,
104 pub epoch_start_time1: Option<u64>,
105 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
106 pub epoch_key2: Option<Vec<u8>>,
107 pub epoch_start_time2: Option<u64>,
108 pub group_key_multicast_policy: Option<GroupKeyMulticastPolicy>,
109}
110
111#[derive(Debug, serde::Serialize)]
112pub struct GroupcastAdoption {
113 pub groupcast_adopted: Option<bool>,
114}
115
116pub fn encode_key_set_write(group_key_set: GroupKeySet) -> anyhow::Result<Vec<u8>> {
120 let mut group_key_set_fields = Vec::new();
122 if let Some(x) = group_key_set.group_key_set_id { group_key_set_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
123 if let Some(x) = group_key_set.group_key_security_policy { group_key_set_fields.push((1, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
124 if let Some(x) = group_key_set.epoch_key0 { group_key_set_fields.push((2, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
125 if let Some(x) = group_key_set.epoch_start_time0 { group_key_set_fields.push((3, tlv::TlvItemValueEnc::UInt64(x)).into()); }
126 if let Some(x) = group_key_set.epoch_key1 { group_key_set_fields.push((4, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
127 if let Some(x) = group_key_set.epoch_start_time1 { group_key_set_fields.push((5, tlv::TlvItemValueEnc::UInt64(x)).into()); }
128 if let Some(x) = group_key_set.epoch_key2 { group_key_set_fields.push((6, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
129 if let Some(x) = group_key_set.epoch_start_time2 { group_key_set_fields.push((7, tlv::TlvItemValueEnc::UInt64(x)).into()); }
130 if let Some(x) = group_key_set.group_key_multicast_policy { group_key_set_fields.push((8, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
131 let tlv = tlv::TlvItemEnc {
132 tag: 0,
133 value: tlv::TlvItemValueEnc::StructInvisible(vec![
134 (0, tlv::TlvItemValueEnc::StructInvisible(group_key_set_fields)).into(),
135 ]),
136 };
137 Ok(tlv.encode()?)
138}
139
140pub fn encode_key_set_read(group_key_set_id: u16) -> anyhow::Result<Vec<u8>> {
142 let tlv = tlv::TlvItemEnc {
143 tag: 0,
144 value: tlv::TlvItemValueEnc::StructInvisible(vec![
145 (0, tlv::TlvItemValueEnc::UInt16(group_key_set_id)).into(),
146 ]),
147 };
148 Ok(tlv.encode()?)
149}
150
151pub fn encode_key_set_remove(group_key_set_id: u16) -> anyhow::Result<Vec<u8>> {
153 let tlv = tlv::TlvItemEnc {
154 tag: 0,
155 value: tlv::TlvItemValueEnc::StructInvisible(vec![
156 (0, tlv::TlvItemValueEnc::UInt16(group_key_set_id)).into(),
157 ]),
158 };
159 Ok(tlv.encode()?)
160}
161
162pub fn encode_key_set_read_all_indices(do_not_use: Option<u8>) -> anyhow::Result<Vec<u8>> {
164 let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
165 if let Some(x) = do_not_use { tlv_fields.push((0, tlv::TlvItemValueEnc::UInt8(x)).into()); }
166 let tlv = tlv::TlvItemEnc {
167 tag: 0,
168 value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
169 };
170 Ok(tlv.encode()?)
171}
172
173pub fn decode_group_key_map(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<GroupKeyMap>> {
177 let mut res = Vec::new();
178 if let tlv::TlvItemValue::List(v) = inp {
179 for item in v {
180 res.push(GroupKeyMap {
181 group_id: item.get_int(&[1]).map(|v| v as u16),
182 group_key_set_id: item.get_int(&[2]).map(|v| v as u16),
183 });
184 }
185 }
186 Ok(res)
187}
188
189pub fn decode_group_table(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<GroupInfoMap>> {
191 let mut res = Vec::new();
192 if let tlv::TlvItemValue::List(v) = inp {
193 for item in v {
194 res.push(GroupInfoMap {
195 group_id: item.get_int(&[1]).map(|v| v as u16),
196 endpoints: {
197 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[2]) {
198 let items: Vec<u16> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u16) } else { None } }).collect();
199 Some(items)
200 } else {
201 None
202 }
203 },
204 group_name: item.get_string_owned(&[3]),
205 });
206 }
207 }
208 Ok(res)
209}
210
211pub fn decode_max_groups_per_fabric(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
213 if let tlv::TlvItemValue::Int(v) = inp {
214 Ok(*v as u16)
215 } else {
216 Err(anyhow::anyhow!("Expected UInt16"))
217 }
218}
219
220pub fn decode_max_group_keys_per_fabric(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
222 if let tlv::TlvItemValue::Int(v) = inp {
223 Ok(*v as u16)
224 } else {
225 Err(anyhow::anyhow!("Expected UInt16"))
226 }
227}
228
229pub fn decode_groupcast_adoption(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<GroupcastAdoption>> {
231 let mut res = Vec::new();
232 if let tlv::TlvItemValue::List(v) = inp {
233 for item in v {
234 res.push(GroupcastAdoption {
235 groupcast_adopted: item.get_bool(&[0]),
236 });
237 }
238 }
239 Ok(res)
240}
241
242
243pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
255 if cluster_id != 0x003F {
257 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x003F, got {}\"}}", cluster_id);
258 }
259
260 match attribute_id {
261 0x0000 => {
262 match decode_group_key_map(tlv_value) {
263 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
264 Err(e) => format!("{{\"error\": \"{}\"}}", e),
265 }
266 }
267 0x0001 => {
268 match decode_group_table(tlv_value) {
269 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
270 Err(e) => format!("{{\"error\": \"{}\"}}", e),
271 }
272 }
273 0x0002 => {
274 match decode_max_groups_per_fabric(tlv_value) {
275 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
276 Err(e) => format!("{{\"error\": \"{}\"}}", e),
277 }
278 }
279 0x0003 => {
280 match decode_max_group_keys_per_fabric(tlv_value) {
281 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
282 Err(e) => format!("{{\"error\": \"{}\"}}", e),
283 }
284 }
285 0x0004 => {
286 match decode_groupcast_adoption(tlv_value) {
287 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
288 Err(e) => format!("{{\"error\": \"{}\"}}", e),
289 }
290 }
291 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
292 }
293}
294
295pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
300 vec![
301 (0x0000, "GroupKeyMap"),
302 (0x0001, "GroupTable"),
303 (0x0002, "MaxGroupsPerFabric"),
304 (0x0003, "MaxGroupKeysPerFabric"),
305 (0x0004, "GroupcastAdoption"),
306 ]
307}
308
309pub fn get_command_list() -> Vec<(u32, &'static str)> {
312 vec![
313 (0x00, "KeySetWrite"),
314 (0x01, "KeySetRead"),
315 (0x03, "KeySetRemove"),
316 (0x04, "KeySetReadAllIndices"),
317 ]
318}
319
320pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
321 match cmd_id {
322 0x00 => Some("KeySetWrite"),
323 0x01 => Some("KeySetRead"),
324 0x03 => Some("KeySetRemove"),
325 0x04 => Some("KeySetReadAllIndices"),
326 _ => None,
327 }
328}
329
330pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
331 match cmd_id {
332 0x00 => Some(vec![
333 crate::clusters::codec::CommandField { tag: 0, name: "group_key_set", kind: crate::clusters::codec::FieldKind::Struct { name: "GroupKeySetStruct" }, optional: false, nullable: false },
334 ]),
335 0x01 => Some(vec![
336 crate::clusters::codec::CommandField { tag: 0, name: "group_key_set_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
337 ]),
338 0x03 => Some(vec![
339 crate::clusters::codec::CommandField { tag: 0, name: "group_key_set_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
340 ]),
341 0x04 => Some(vec![
342 crate::clusters::codec::CommandField { tag: 0, name: "do_not_use", kind: crate::clusters::codec::FieldKind::U8, optional: true, nullable: false },
343 ]),
344 _ => None,
345 }
346}
347
348pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
349 match cmd_id {
350 0x00 => Err(anyhow::anyhow!("command \"KeySetWrite\" has complex args: use raw mode")),
351 0x01 => {
352 let group_key_set_id = crate::clusters::codec::json_util::get_u16(args, "group_key_set_id")?;
353 encode_key_set_read(group_key_set_id)
354 }
355 0x03 => {
356 let group_key_set_id = crate::clusters::codec::json_util::get_u16(args, "group_key_set_id")?;
357 encode_key_set_remove(group_key_set_id)
358 }
359 0x04 => {
360 let do_not_use = crate::clusters::codec::json_util::get_opt_u8(args, "do_not_use")?;
361 encode_key_set_read_all_indices(do_not_use)
362 }
363 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
364 }
365}
366
367#[derive(Debug, serde::Serialize)]
368pub struct KeySetReadResponse {
369 pub group_key_set: Option<GroupKeySet>,
370}
371
372#[derive(Debug, serde::Serialize)]
373pub struct KeySetReadAllIndicesResponse {
374 pub group_key_set_i_ds: Option<Vec<u16>>,
375}
376
377pub fn decode_key_set_read_response(inp: &tlv::TlvItemValue) -> anyhow::Result<KeySetReadResponse> {
381 if let tlv::TlvItemValue::List(_fields) = inp {
382 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
383 Ok(KeySetReadResponse {
384 group_key_set: {
385 if let Some(nested_tlv) = item.get(&[0]) {
386 if let tlv::TlvItemValue::List(_) = nested_tlv {
387 let nested_item = tlv::TlvItem { tag: 0, value: nested_tlv.clone() };
388 Some(GroupKeySet {
389 group_key_set_id: nested_item.get_int(&[0]).map(|v| v as u16),
390 group_key_security_policy: nested_item.get_int(&[1]).and_then(|v| GroupKeySecurityPolicy::from_u8(v as u8)),
391 epoch_key0: nested_item.get_octet_string_owned(&[2]),
392 epoch_start_time0: nested_item.get_int(&[3]),
393 epoch_key1: nested_item.get_octet_string_owned(&[4]),
394 epoch_start_time1: nested_item.get_int(&[5]),
395 epoch_key2: nested_item.get_octet_string_owned(&[6]),
396 epoch_start_time2: nested_item.get_int(&[7]),
397 group_key_multicast_policy: nested_item.get_int(&[8]).and_then(|v| GroupKeyMulticastPolicy::from_u8(v as u8)),
398 })
399 } else {
400 None
401 }
402 } else {
403 None
404 }
405 },
406 })
407 } else {
408 Err(anyhow::anyhow!("Expected struct fields"))
409 }
410}
411
412pub fn decode_key_set_read_all_indices_response(inp: &tlv::TlvItemValue) -> anyhow::Result<KeySetReadAllIndicesResponse> {
414 if let tlv::TlvItemValue::List(_fields) = inp {
415 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
416 Ok(KeySetReadAllIndicesResponse {
417 group_key_set_i_ds: {
418 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
419 let items: Vec<u16> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u16) } else { None } }).collect();
420 Some(items)
421 } else {
422 None
423 }
424 },
425 })
426 } else {
427 Err(anyhow::anyhow!("Expected struct fields"))
428 }
429}
430
431pub async fn key_set_write(conn: &crate::controller::Connection, endpoint: u16, group_key_set: GroupKeySet) -> anyhow::Result<()> {
435 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_CMD_ID_KEYSETWRITE, &encode_key_set_write(group_key_set)?).await?;
436 Ok(())
437}
438
439pub async fn key_set_read(conn: &crate::controller::Connection, endpoint: u16, group_key_set_id: u16) -> anyhow::Result<KeySetReadResponse> {
441 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_CMD_ID_KEYSETREAD, &encode_key_set_read(group_key_set_id)?).await?;
442 decode_key_set_read_response(&tlv)
443}
444
445pub async fn key_set_remove(conn: &crate::controller::Connection, endpoint: u16, group_key_set_id: u16) -> anyhow::Result<()> {
447 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_CMD_ID_KEYSETREMOVE, &encode_key_set_remove(group_key_set_id)?).await?;
448 Ok(())
449}
450
451pub async fn key_set_read_all_indices(conn: &crate::controller::Connection, endpoint: u16, do_not_use: Option<u8>) -> anyhow::Result<KeySetReadAllIndicesResponse> {
453 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_CMD_ID_KEYSETREADALLINDICES, &encode_key_set_read_all_indices(do_not_use)?).await?;
454 decode_key_set_read_all_indices_response(&tlv)
455}
456
457pub async fn read_group_key_map(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<GroupKeyMap>> {
459 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_ATTR_ID_GROUPKEYMAP).await?;
460 decode_group_key_map(&tlv)
461}
462
463pub async fn read_group_table(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<GroupInfoMap>> {
465 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_ATTR_ID_GROUPTABLE).await?;
466 decode_group_table(&tlv)
467}
468
469pub async fn read_max_groups_per_fabric(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
471 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_ATTR_ID_MAXGROUPSPERFABRIC).await?;
472 decode_max_groups_per_fabric(&tlv)
473}
474
475pub async fn read_max_group_keys_per_fabric(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
477 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_ATTR_ID_MAXGROUPKEYSPERFABRIC).await?;
478 decode_max_group_keys_per_fabric(&tlv)
479}
480
481pub async fn read_groupcast_adoption(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<GroupcastAdoption>> {
483 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GROUP_KEY_MANAGEMENT, crate::clusters::defs::CLUSTER_GROUP_KEY_MANAGEMENT_ATTR_ID_GROUPCASTADOPTION).await?;
484 decode_groupcast_adoption(&tlv)
485}
486