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<u8>,
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<u8>,
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
111pub fn encode_key_set_write(group_key_set: GroupKeySet) -> anyhow::Result<Vec<u8>> {
115 let mut group_key_set_fields = Vec::new();
117 if let Some(x) = group_key_set.group_key_set_id { group_key_set_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
118 if let Some(x) = group_key_set.group_key_security_policy { group_key_set_fields.push((1, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
119 if let Some(x) = group_key_set.epoch_key0 { group_key_set_fields.push((2, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
120 if let Some(x) = group_key_set.epoch_start_time0 { group_key_set_fields.push((3, tlv::TlvItemValueEnc::UInt64(x)).into()); }
121 if let Some(x) = group_key_set.epoch_key1 { group_key_set_fields.push((4, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
122 if let Some(x) = group_key_set.epoch_start_time1 { group_key_set_fields.push((5, tlv::TlvItemValueEnc::UInt64(x)).into()); }
123 if let Some(x) = group_key_set.epoch_key2 { group_key_set_fields.push((6, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
124 if let Some(x) = group_key_set.epoch_start_time2 { group_key_set_fields.push((7, tlv::TlvItemValueEnc::UInt64(x)).into()); }
125 if let Some(x) = group_key_set.group_key_multicast_policy { group_key_set_fields.push((8, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
126 let tlv = tlv::TlvItemEnc {
127 tag: 0,
128 value: tlv::TlvItemValueEnc::StructInvisible(vec![
129 (0, tlv::TlvItemValueEnc::StructInvisible(group_key_set_fields)).into(),
130 ]),
131 };
132 Ok(tlv.encode()?)
133}
134
135pub fn encode_key_set_read(group_key_set_id: u16) -> anyhow::Result<Vec<u8>> {
137 let tlv = tlv::TlvItemEnc {
138 tag: 0,
139 value: tlv::TlvItemValueEnc::StructInvisible(vec![
140 (0, tlv::TlvItemValueEnc::UInt16(group_key_set_id)).into(),
141 ]),
142 };
143 Ok(tlv.encode()?)
144}
145
146pub fn encode_key_set_remove(group_key_set_id: u16) -> anyhow::Result<Vec<u8>> {
148 let tlv = tlv::TlvItemEnc {
149 tag: 0,
150 value: tlv::TlvItemValueEnc::StructInvisible(vec![
151 (0, tlv::TlvItemValueEnc::UInt16(group_key_set_id)).into(),
152 ]),
153 };
154 Ok(tlv.encode()?)
155}
156
157pub fn encode_key_set_read_all_indices(do_not_use: u8) -> anyhow::Result<Vec<u8>> {
159 let tlv = tlv::TlvItemEnc {
160 tag: 0,
161 value: tlv::TlvItemValueEnc::StructInvisible(vec![
162 (0, tlv::TlvItemValueEnc::UInt8(do_not_use)).into(),
163 ]),
164 };
165 Ok(tlv.encode()?)
166}
167
168pub fn decode_group_key_map(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<GroupKeyMap>> {
172 let mut res = Vec::new();
173 if let tlv::TlvItemValue::List(v) = inp {
174 for item in v {
175 res.push(GroupKeyMap {
176 group_id: item.get_int(&[1]).map(|v| v as u8),
177 group_key_set_id: item.get_int(&[2]).map(|v| v as u16),
178 });
179 }
180 }
181 Ok(res)
182}
183
184pub fn decode_group_table(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<GroupInfoMap>> {
186 let mut res = Vec::new();
187 if let tlv::TlvItemValue::List(v) = inp {
188 for item in v {
189 res.push(GroupInfoMap {
190 group_id: item.get_int(&[1]).map(|v| v as u8),
191 endpoints: {
192 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[2]) {
193 let items: Vec<u16> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u16) } else { None } }).collect();
194 Some(items)
195 } else {
196 None
197 }
198 },
199 group_name: item.get_string_owned(&[3]),
200 });
201 }
202 }
203 Ok(res)
204}
205
206pub fn decode_max_groups_per_fabric(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
208 if let tlv::TlvItemValue::Int(v) = inp {
209 Ok(*v as u16)
210 } else {
211 Err(anyhow::anyhow!("Expected UInt16"))
212 }
213}
214
215pub fn decode_max_group_keys_per_fabric(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
217 if let tlv::TlvItemValue::Int(v) = inp {
218 Ok(*v as u16)
219 } else {
220 Err(anyhow::anyhow!("Expected UInt16"))
221 }
222}
223
224
225pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
237 if cluster_id != 0x003F {
239 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x003F, got {}\"}}", cluster_id);
240 }
241
242 match attribute_id {
243 0x0000 => {
244 match decode_group_key_map(tlv_value) {
245 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
246 Err(e) => format!("{{\"error\": \"{}\"}}", e),
247 }
248 }
249 0x0001 => {
250 match decode_group_table(tlv_value) {
251 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
252 Err(e) => format!("{{\"error\": \"{}\"}}", e),
253 }
254 }
255 0x0002 => {
256 match decode_max_groups_per_fabric(tlv_value) {
257 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
258 Err(e) => format!("{{\"error\": \"{}\"}}", e),
259 }
260 }
261 0x0003 => {
262 match decode_max_group_keys_per_fabric(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 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
268 }
269}
270
271pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
276 vec![
277 (0x0000, "GroupKeyMap"),
278 (0x0001, "GroupTable"),
279 (0x0002, "MaxGroupsPerFabric"),
280 (0x0003, "MaxGroupKeysPerFabric"),
281 ]
282}
283
284pub fn get_command_list() -> Vec<(u32, &'static str)> {
287 vec![
288 (0x00, "KeySetWrite"),
289 (0x01, "KeySetRead"),
290 (0x03, "KeySetRemove"),
291 (0x04, "KeySetReadAllIndices"),
292 ]
293}
294
295pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
296 match cmd_id {
297 0x00 => Some("KeySetWrite"),
298 0x01 => Some("KeySetRead"),
299 0x03 => Some("KeySetRemove"),
300 0x04 => Some("KeySetReadAllIndices"),
301 _ => None,
302 }
303}
304
305pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
306 match cmd_id {
307 0x00 => Some(vec![
308 crate::clusters::codec::CommandField { tag: 0, name: "group_key_set", kind: crate::clusters::codec::FieldKind::Struct { name: "GroupKeySetStruct" }, optional: false, nullable: false },
309 ]),
310 0x01 => Some(vec![
311 crate::clusters::codec::CommandField { tag: 0, name: "group_key_set_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
312 ]),
313 0x03 => Some(vec![
314 crate::clusters::codec::CommandField { tag: 0, name: "group_key_set_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
315 ]),
316 0x04 => Some(vec![
317 crate::clusters::codec::CommandField { tag: 0, name: "do_not_use", kind: crate::clusters::codec::FieldKind::U8, optional: true, nullable: false },
318 ]),
319 _ => None,
320 }
321}
322
323pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
324 match cmd_id {
325 0x00 => Err(anyhow::anyhow!("command \"KeySetWrite\" has complex args: use raw mode")),
326 0x01 => {
327 let group_key_set_id = crate::clusters::codec::json_util::get_u16(args, "group_key_set_id")?;
328 encode_key_set_read(group_key_set_id)
329 }
330 0x03 => {
331 let group_key_set_id = crate::clusters::codec::json_util::get_u16(args, "group_key_set_id")?;
332 encode_key_set_remove(group_key_set_id)
333 }
334 0x04 => {
335 let do_not_use = crate::clusters::codec::json_util::get_u8(args, "do_not_use")?;
336 encode_key_set_read_all_indices(do_not_use)
337 }
338 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
339 }
340}
341
342#[derive(Debug, serde::Serialize)]
343pub struct KeySetReadResponse {
344 pub group_key_set: Option<GroupKeySet>,
345}
346
347#[derive(Debug, serde::Serialize)]
348pub struct KeySetReadAllIndicesResponse {
349 pub group_key_set_i_ds: Option<Vec<u16>>,
350}
351
352pub fn decode_key_set_read_response(inp: &tlv::TlvItemValue) -> anyhow::Result<KeySetReadResponse> {
356 if let tlv::TlvItemValue::List(_fields) = inp {
357 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
358 Ok(KeySetReadResponse {
359 group_key_set: {
360 if let Some(nested_tlv) = item.get(&[0]) {
361 if let tlv::TlvItemValue::List(_) = nested_tlv {
362 let nested_item = tlv::TlvItem { tag: 0, value: nested_tlv.clone() };
363 Some(GroupKeySet {
364 group_key_set_id: nested_item.get_int(&[0]).map(|v| v as u16),
365 group_key_security_policy: nested_item.get_int(&[1]).and_then(|v| GroupKeySecurityPolicy::from_u8(v as u8)),
366 epoch_key0: nested_item.get_octet_string_owned(&[2]),
367 epoch_start_time0: nested_item.get_int(&[3]),
368 epoch_key1: nested_item.get_octet_string_owned(&[4]),
369 epoch_start_time1: nested_item.get_int(&[5]),
370 epoch_key2: nested_item.get_octet_string_owned(&[6]),
371 epoch_start_time2: nested_item.get_int(&[7]),
372 group_key_multicast_policy: nested_item.get_int(&[8]).and_then(|v| GroupKeyMulticastPolicy::from_u8(v as u8)),
373 })
374 } else {
375 None
376 }
377 } else {
378 None
379 }
380 },
381 })
382 } else {
383 Err(anyhow::anyhow!("Expected struct fields"))
384 }
385}
386
387pub fn decode_key_set_read_all_indices_response(inp: &tlv::TlvItemValue) -> anyhow::Result<KeySetReadAllIndicesResponse> {
389 if let tlv::TlvItemValue::List(_fields) = inp {
390 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
391 Ok(KeySetReadAllIndicesResponse {
392 group_key_set_i_ds: {
393 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
394 let items: Vec<u16> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u16) } else { None } }).collect();
395 Some(items)
396 } else {
397 None
398 }
399 },
400 })
401 } else {
402 Err(anyhow::anyhow!("Expected struct fields"))
403 }
404}
405
406pub async fn key_set_write(conn: &crate::controller::Connection, endpoint: u16, group_key_set: GroupKeySet) -> anyhow::Result<()> {
410 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?;
411 Ok(())
412}
413
414pub async fn key_set_read(conn: &crate::controller::Connection, endpoint: u16, group_key_set_id: u16) -> anyhow::Result<KeySetReadResponse> {
416 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?;
417 decode_key_set_read_response(&tlv)
418}
419
420pub async fn key_set_remove(conn: &crate::controller::Connection, endpoint: u16, group_key_set_id: u16) -> anyhow::Result<()> {
422 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?;
423 Ok(())
424}
425
426pub async fn key_set_read_all_indices(conn: &crate::controller::Connection, endpoint: u16, do_not_use: u8) -> anyhow::Result<KeySetReadAllIndicesResponse> {
428 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?;
429 decode_key_set_read_all_indices_response(&tlv)
430}
431
432pub async fn read_group_key_map(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<GroupKeyMap>> {
434 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?;
435 decode_group_key_map(&tlv)
436}
437
438pub async fn read_group_table(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<GroupInfoMap>> {
440 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?;
441 decode_group_table(&tlv)
442}
443
444pub async fn read_max_groups_per_fabric(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
446 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?;
447 decode_max_groups_per_fabric(&tlv)
448}
449
450pub async fn read_max_group_keys_per_fabric(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
452 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?;
453 decode_max_group_keys_per_fabric(&tlv)
454}
455