diff --git a/matter/src/data_model/sdm/noc.rs b/matter/src/data_model/sdm/noc.rs index d03467e..68432dc 100644 --- a/matter/src/data_model/sdm/noc.rs +++ b/matter/src/data_model/sdm/noc.rs @@ -78,6 +78,16 @@ pub enum Commands { AddTrustedRootCert = 0x0b, } +#[derive(FromPrimitive)] +enum Attributes { + NOCs = 0, + Fabrics = 1, + SupportedFabrics = 2, + CommissionedFabrics = 3, + TrustedRootCerts = 4, + CurrentFabricIndex = 5, +} + pub struct NocCluster { base: Cluster, dev_att: Box, @@ -106,13 +116,16 @@ impl NocCluster { acl_mgr: Arc, failsafe: Arc, ) -> Result, Error> { - Ok(Box::new(Self { + let mut c = Box::new(Self { dev_att, fabric_mgr, acl_mgr, failsafe, base: Cluster::new(ID)?, - })) + }); + c.base.add_attribute(attr_currfabindex_new()?)?; + c.base.add_attribute(attr_fabrics_new()?)?; + Ok(c) } fn add_acl(&self, fab_idx: u8, admin_subject: u64) -> Result<(), Error> { @@ -155,6 +168,7 @@ impl NocCluster { icac_value, noc_value, r.ipk_value.0, + r.vendor_id, ) .map_err(|_| NocStatus::TableFull)?; let fab_idx = self @@ -347,6 +361,24 @@ impl NocCluster { } } +fn attr_currfabindex_new() -> Result { + Attribute::new( + Attributes::CurrentFabricIndex as u16, + AttrValue::Custom, + Access::RV, + Quality::NONE, + ) +} + +fn attr_fabrics_new() -> Result { + Attribute::new( + Attributes::Fabrics as u16, + AttrValue::Custom, + Access::RV | Access::FAB_SCOPED, + Quality::NONE, + ) +} + impl ClusterType for NocCluster { fn base(&self) -> &Cluster { &self.base @@ -372,6 +404,28 @@ impl ClusterType for NocCluster { _ => Err(IMStatusCode::UnsupportedCommand), } } + + fn read_custom_attribute(&self, encoder: &mut dyn Encoder, attr: &AttrDetails) { + match num::FromPrimitive::from_u16(attr.attr_id) { + Some(Attributes::CurrentFabricIndex) => { + encoder.encode(EncodeValue::Value(&attr.fab_idx)) + } + Some(Attributes::Fabrics) => encoder.encode(EncodeValue::Closure(&|tag, tw| { + let _ = tw.start_array(tag); + let _ = self.fabric_mgr.for_each(|entry, fab_idx| { + if !attr.fab_filter || attr.fab_idx == fab_idx { + let _ = entry + .get_fabric_desc(fab_idx) + .to_tlv(tw, TagType::Anonymous); + } + }); + let _ = tw.end_container(); + })), + _ => { + error!("Attribute not supported: this shouldn't happen"); + } + } + } } fn add_attestation_element( @@ -452,7 +506,7 @@ struct AddNocReq<'a> { icac_value: OctetStr<'a>, ipk_value: OctetStr<'a>, case_admin_subject: u64, - _vendor_id: u16, + vendor_id: u16, } #[derive(FromTLV)] diff --git a/matter/src/fabric.rs b/matter/src/fabric.rs index f868664..c39bb25 100644 --- a/matter/src/fabric.rs +++ b/matter/src/fabric.rs @@ -28,6 +28,7 @@ use crate::{ group_keys::KeySet, mdns::{self, Mdns}, sys::{Psm, SysMdnsService}, + tlv::{OctetStr, TLVWriter, TagType, ToTLV, UtfStr}, }; const MAX_CERT_TLV_LEN: usize = 300; @@ -39,6 +40,7 @@ macro_rules! fb_key { }; } +const ST_VID: &str = "vid"; const ST_RCA: &str = "rca"; const ST_ICA: &str = "ica"; const ST_NOC: &str = "noc"; @@ -50,6 +52,7 @@ const ST_PRKEY: &str = "privkey"; pub struct Fabric { node_id: u64, fabric_id: u64, + vendor_id: u16, key_pair: Box, pub root_ca: Cert, pub icac: Option, @@ -59,6 +62,19 @@ pub struct Fabric { mdns_service: Option, } +#[derive(ToTLV)] +#[tlvargs(lifetime = "'a", start = 1)] +pub struct FabricDescriptor<'a> { + root_public_key: OctetStr<'a>, + vendor_id: u16, + fabric_id: u64, + node_id: u64, + label: UtfStr<'a>, + // TODO: Instead of the direct value, we should consider GlobalElements::FabricIndex + #[tagval(0xFE)] + pub fab_idx: Option, +} + impl Fabric { pub fn new( key_pair: KeyPair, @@ -66,6 +82,7 @@ impl Fabric { icac: Option, noc: Cert, ipk: &[u8], + vendor_id: u16, ) -> Result { let node_id = noc.get_node_id()?; let fabric_id = noc.get_fabric_id()?; @@ -73,6 +90,7 @@ impl Fabric { let mut f = Self { node_id, fabric_id, + vendor_id, key_pair: Box::new(key_pair), root_ca, icac, @@ -105,6 +123,7 @@ impl Fabric { Ok(Self { node_id: 0, fabric_id: 0, + vendor_id: 0, key_pair: Box::new(KeyPairDummy::new()?), root_ca: Cert::default(), icac: Some(Cert::default()), @@ -161,6 +180,17 @@ impl Fabric { self.fabric_id } + pub fn get_fabric_desc(&self, fab_idx: u8) -> FabricDescriptor { + FabricDescriptor { + root_public_key: OctetStr::new(self.root_ca.get_pubkey()), + vendor_id: self.vendor_id, + fabric_id: self.fabric_id, + node_id: self.node_id, + label: UtfStr::new(b""), + fab_idx: Some(fab_idx), + } + } + fn store(&self, index: usize, psm: &MutexGuard) -> Result<(), Error> { let mut key = [0u8; MAX_CERT_TLV_LEN]; let len = self.root_ca.as_tlv(&mut key)?; @@ -187,6 +217,7 @@ impl Fabric { let key = &key[..len]; psm.set_kv_slice(fb_key!(index, ST_PRKEY), key)?; + psm.set_kv_u64(ST_VID, self.vendor_id.into())?; Ok(()) } @@ -216,7 +247,17 @@ impl Fabric { psm.get_kv_slice(fb_key!(index, ST_PRKEY), &mut priv_key)?; let keypair = KeyPair::new_from_components(pub_key.as_slice(), priv_key.as_slice())?; - Fabric::new(keypair, root_ca, icac, noc, ipk.as_slice()) + let mut vendor_id = 0; + psm.get_kv_u64(ST_VID, &mut vendor_id)?; + + Fabric::new( + keypair, + root_ca, + icac, + noc, + ipk.as_slice(), + vendor_id as u16, + ) } } @@ -306,4 +347,18 @@ impl FabricMgr { } true } + + // Parameters to T are the Fabric and its Fabric Index + pub fn for_each(&self, mut f: T) -> Result<(), Error> + where + T: FnMut(&Fabric, u8), + { + let mgr = self.inner.read().unwrap(); + for i in 1..MAX_SUPPORTED_FABRICS { + if let Some(fabric) = &mgr.fabrics[i] { + f(fabric, i as u8) + } + } + Ok(()) + } }