Simple persistance via TLV
This commit is contained in:
parent
1392810a6c
commit
7437cf2c94
10 changed files with 262 additions and 646 deletions
|
@ -27,6 +27,7 @@ use matter::data_model::root_endpoint;
|
|||
use matter::data_model::sdm::dev_att::DevAttDataFetcher;
|
||||
use matter::data_model::system_model::descriptor;
|
||||
use matter::interaction_model::core::InteractionModel;
|
||||
use matter::persist;
|
||||
use matter::secure_channel::spake2p::VerifierData;
|
||||
use matter::transport::{
|
||||
mgr::RecvAction, mgr::TransportMgr, packet::MAX_RX_BUF_SIZE, packet::MAX_TX_BUF_SIZE,
|
||||
|
@ -56,6 +57,18 @@ fn main() {
|
|||
|
||||
let dev_att = dev_att::HardCodedDevAtt::new();
|
||||
|
||||
let psm = persist::FilePsm::new(std::env::temp_dir().join("matter-iot")).unwrap();
|
||||
|
||||
let mut buf = [0; 4096];
|
||||
|
||||
if let Some(data) = psm.load("fabrics", &mut buf).unwrap() {
|
||||
matter.load_fabrics(data).unwrap();
|
||||
}
|
||||
|
||||
if let Some(data) = psm.load("acls", &mut buf).unwrap() {
|
||||
matter.load_acls(data).unwrap();
|
||||
}
|
||||
|
||||
matter
|
||||
.start::<4096>(
|
||||
CommissioningData {
|
||||
|
@ -63,7 +76,7 @@ fn main() {
|
|||
verifier: VerifierData::new_with_pw(123456, *matter.borrow()),
|
||||
discriminator: 250,
|
||||
},
|
||||
&mut [0; 4096],
|
||||
&mut buf,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -114,6 +127,14 @@ fn main() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(data) = matter.store_fabrics(&mut buf).unwrap() {
|
||||
psm.store("fabrics", data).unwrap();
|
||||
}
|
||||
|
||||
if let Some(data) = matter.store_acls(&mut buf).unwrap() {
|
||||
psm.store("acls", data).unwrap();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ use crate::{
|
|||
error::Error,
|
||||
fabric,
|
||||
interaction_model::messages::GenericPath,
|
||||
persist::Psm,
|
||||
tlv::{FromTLV, TLVElement, TLVList, TLVWriter, TagType, ToTLV},
|
||||
transport::session::{Session, SessionMode, MAX_CAT_IDS_PER_NOC},
|
||||
utils::writebuf::WriteBuf,
|
||||
|
@ -390,10 +389,8 @@ impl AclEntry {
|
|||
}
|
||||
|
||||
const MAX_ACL_ENTRIES: usize = ENTRIES_PER_FABRIC * fabric::MAX_SUPPORTED_FABRICS;
|
||||
type AclEntries = [Option<AclEntry>; MAX_ACL_ENTRIES];
|
||||
|
||||
const ACL_KV_ENTRY: &str = "acl";
|
||||
const ACL_KV_MAX_SIZE: usize = 300;
|
||||
type AclEntries = [Option<AclEntry>; MAX_ACL_ENTRIES];
|
||||
|
||||
pub struct AclMgr {
|
||||
entries: AclEntries,
|
||||
|
@ -505,30 +502,8 @@ impl AclMgr {
|
|||
false
|
||||
}
|
||||
|
||||
pub fn store<T>(&mut self, mut psm: T) -> Result<(), Error>
|
||||
where
|
||||
T: Psm,
|
||||
{
|
||||
if self.changed {
|
||||
let mut buf = [0u8; ACL_KV_MAX_SIZE];
|
||||
let mut wb = WriteBuf::new(&mut buf);
|
||||
let mut tw = TLVWriter::new(&mut wb);
|
||||
self.entries.to_tlv(&mut tw, TagType::Anonymous)?;
|
||||
psm.set_kv_slice(ACL_KV_ENTRY, wb.as_slice())?;
|
||||
|
||||
self.changed = false;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load<T>(&mut self, psm: T) -> Result<(), Error>
|
||||
where
|
||||
T: Psm,
|
||||
{
|
||||
let mut buf = [0u8; ACL_KV_MAX_SIZE];
|
||||
let acl_tlvs = psm.get_kv_slice(ACL_KV_ENTRY, &mut buf)?;
|
||||
let root = TLVList::new(acl_tlvs).iter().next().ok_or(Error::Invalid)?;
|
||||
pub fn load(&mut self, data: &[u8]) -> Result<(), Error> {
|
||||
let root = TLVList::new(data).iter().next().ok_or(Error::Invalid)?;
|
||||
|
||||
self.entries = AclEntries::from_tlv(&root)?;
|
||||
self.changed = false;
|
||||
|
@ -536,37 +511,20 @@ impl AclMgr {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub async fn store_async<T>(&mut self, mut psm: T) -> Result<(), Error>
|
||||
where
|
||||
T: crate::persist::asynch::AsyncPsm,
|
||||
{
|
||||
pub fn store<'a>(&mut self, buf: &'a mut [u8]) -> Result<Option<&'a [u8]>, Error> {
|
||||
if self.changed {
|
||||
let mut buf = [0u8; ACL_KV_MAX_SIZE];
|
||||
let mut wb = WriteBuf::new(&mut buf);
|
||||
let mut wb = WriteBuf::new(buf);
|
||||
let mut tw = TLVWriter::new(&mut wb);
|
||||
self.entries.to_tlv(&mut tw, TagType::Anonymous)?;
|
||||
psm.set_kv_slice(ACL_KV_ENTRY, wb.as_slice()).await?;
|
||||
|
||||
self.changed = false;
|
||||
|
||||
let len = tw.get_tail();
|
||||
|
||||
Ok(Some(&buf[..len]))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub async fn load_async<T>(&mut self, psm: T) -> Result<(), Error>
|
||||
where
|
||||
T: crate::persist::asynch::AsyncPsm,
|
||||
{
|
||||
let mut buf = [0u8; ACL_KV_MAX_SIZE];
|
||||
let acl_tlvs = psm.get_kv_slice(ACL_KV_ENTRY, &mut buf).await?;
|
||||
let root = TLVList::new(acl_tlvs).iter().next().ok_or(Error::Invalid)?;
|
||||
|
||||
self.entries = AclEntries::from_tlv(&root)?;
|
||||
self.changed = false;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Traverse fabric specific entries to find the index
|
||||
|
|
|
@ -98,6 +98,24 @@ impl<'a> Matter<'a> {
|
|||
self.dev_det
|
||||
}
|
||||
|
||||
pub fn load_fabrics(&self, data: &[u8]) -> Result<(), Error> {
|
||||
self.fabric_mgr
|
||||
.borrow_mut()
|
||||
.load(data, &mut self.mdns_mgr.borrow_mut())
|
||||
}
|
||||
|
||||
pub fn load_acls(&self, data: &[u8]) -> Result<(), Error> {
|
||||
self.acl_mgr.borrow_mut().load(data)
|
||||
}
|
||||
|
||||
pub fn store_fabrics<'b>(&self, buf: &'b mut [u8]) -> Result<Option<&'b [u8]>, Error> {
|
||||
self.fabric_mgr.borrow_mut().store(buf)
|
||||
}
|
||||
|
||||
pub fn store_acls<'b>(&self, buf: &'b mut [u8]) -> Result<Option<&'b [u8]>, Error> {
|
||||
self.acl_mgr.borrow_mut().store(buf)
|
||||
}
|
||||
|
||||
pub fn start<const N: usize>(
|
||||
&self,
|
||||
dev_comm: CommissioningData,
|
||||
|
|
|
@ -68,8 +68,6 @@ impl KeyPair {
|
|||
}
|
||||
|
||||
pub fn new_from_components(_pub_key: &[u8], _priv_key: &[u8]) -> Result<Self, Error> {
|
||||
error!("This API should never get called");
|
||||
|
||||
Ok(Self {})
|
||||
}
|
||||
|
||||
|
@ -85,13 +83,11 @@ impl KeyPair {
|
|||
}
|
||||
|
||||
pub fn get_public_key(&self, _pub_key: &mut [u8]) -> Result<usize, Error> {
|
||||
error!("This API should never get called");
|
||||
Err(Error::Invalid)
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn get_private_key(&self, _pub_key: &mut [u8]) -> Result<usize, Error> {
|
||||
error!("This API should never get called");
|
||||
Err(Error::Invalid)
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn derive_secret(self, _peer_pub_key: &[u8], _secret: &mut [u8]) -> Result<usize, Error> {
|
||||
|
|
|
@ -70,8 +70,6 @@ impl KeyPair {
|
|||
}
|
||||
|
||||
pub fn new_from_components(_pub_key: &[u8], priv_key: &[u8]) -> Result<Self, Error> {
|
||||
error!("This API should never get called");
|
||||
|
||||
Ok(Self {})
|
||||
}
|
||||
|
||||
|
@ -87,8 +85,11 @@ impl KeyPair {
|
|||
}
|
||||
|
||||
pub fn get_public_key(&self, _pub_key: &mut [u8]) -> Result<usize, Error> {
|
||||
error!("This API should never get called");
|
||||
Err(Error::Invalid)
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn get_private_key(&self, priv_key: &mut [u8]) -> Result<usize, Error> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn derive_secret(self, _peer_pub_key: &[u8], _secret: &mut [u8]) -> Result<usize, Error> {
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
use crate::{
|
||||
error::Error,
|
||||
tlv::{FromTLV, TLVWriter, TagType, ToTLV},
|
||||
};
|
||||
|
||||
pub const SYMM_KEY_LEN_BITS: usize = 128;
|
||||
pub const SYMM_KEY_LEN_BYTES: usize = SYMM_KEY_LEN_BITS / 8;
|
||||
|
@ -68,6 +72,38 @@ pub mod crypto_dummy;
|
|||
)))]
|
||||
pub use self::crypto_dummy::*;
|
||||
|
||||
impl<'a> FromTLV<'a> for KeyPair {
|
||||
fn from_tlv(t: &crate::tlv::TLVElement<'a>) -> Result<Self, Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
t.confirm_array()?.enter();
|
||||
|
||||
if let Some(mut array) = t.enter() {
|
||||
let pub_key = array.next().ok_or(Error::Invalid)?.slice()?;
|
||||
let priv_key = array.next().ok_or(Error::Invalid)?.slice()?;
|
||||
|
||||
KeyPair::new_from_components(pub_key, priv_key)
|
||||
} else {
|
||||
Err(Error::Invalid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTLV for KeyPair {
|
||||
fn to_tlv(&self, tw: &mut TLVWriter, tag: TagType) -> Result<(), Error> {
|
||||
let mut buf = [0; 1024]; // TODO
|
||||
|
||||
tw.start_array(tag)?;
|
||||
|
||||
let size = self.get_public_key(&mut buf)?;
|
||||
tw.str16(TagType::Anonymous, &buf[..size])?;
|
||||
|
||||
let size = self.get_private_key(&mut buf)?;
|
||||
tw.str16(TagType::Anonymous, &buf[..size])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::error::Error;
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
use core::fmt::Write;
|
||||
|
||||
use byteorder::{BigEndian, ByteOrder, LittleEndian};
|
||||
use log::{error, info};
|
||||
use heapless::{String, Vec};
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
cert::{Cert, MAX_CERT_TLV_LEN},
|
||||
|
@ -26,32 +27,12 @@ use crate::{
|
|||
error::Error,
|
||||
group_keys::KeySet,
|
||||
mdns::{MdnsMgr, ServiceMode},
|
||||
persist::Psm,
|
||||
tlv::{OctetStr, TLVWriter, TagType, ToTLV, UtfStr},
|
||||
tlv::{FromTLV, OctetStr, TLVElement, TLVList, TLVWriter, TagType, ToTLV, UtfStr},
|
||||
utils::writebuf::WriteBuf,
|
||||
};
|
||||
|
||||
const COMPRESSED_FABRIC_ID_LEN: usize = 8;
|
||||
|
||||
macro_rules! fb_key {
|
||||
($index:ident, $key:ident, $buf:expr) => {{
|
||||
use core::fmt::Write;
|
||||
|
||||
$buf = "".into();
|
||||
write!(&mut $buf, "fb{}{}", $index, $key).unwrap();
|
||||
|
||||
&$buf
|
||||
}};
|
||||
}
|
||||
|
||||
const ST_VID: &str = "vid";
|
||||
const ST_RCA: &str = "rca";
|
||||
const ST_ICA: &str = "ica";
|
||||
const ST_NOC: &str = "noc";
|
||||
const ST_IPK: &str = "ipk";
|
||||
const ST_LBL: &str = "label";
|
||||
const ST_PBKEY: &str = "pubkey";
|
||||
const ST_PRKEY: &str = "privkey";
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, ToTLV)]
|
||||
#[tlvargs(lifetime = "'a", start = 1)]
|
||||
|
@ -66,18 +47,18 @@ pub struct FabricDescriptor<'a> {
|
|||
pub fab_idx: Option<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, ToTLV, FromTLV)]
|
||||
pub struct Fabric {
|
||||
node_id: u64,
|
||||
fabric_id: u64,
|
||||
vendor_id: u16,
|
||||
key_pair: KeyPair,
|
||||
pub root_ca: heapless::Vec<u8, { MAX_CERT_TLV_LEN }>,
|
||||
pub icac: Option<heapless::Vec<u8, { MAX_CERT_TLV_LEN }>>,
|
||||
pub noc: heapless::Vec<u8, { MAX_CERT_TLV_LEN }>,
|
||||
pub root_ca: Vec<u8, { MAX_CERT_TLV_LEN }>,
|
||||
pub icac: Option<Vec<u8, { MAX_CERT_TLV_LEN }>>,
|
||||
pub noc: Vec<u8, { MAX_CERT_TLV_LEN }>,
|
||||
pub ipk: KeySet,
|
||||
label: heapless::String<32>,
|
||||
mdns_service_name: heapless::String<33>,
|
||||
label: String<32>,
|
||||
mdns_service_name: String<33>,
|
||||
}
|
||||
|
||||
impl Fabric {
|
||||
|
@ -199,234 +180,14 @@ impl Fabric {
|
|||
|
||||
Ok(desc)
|
||||
}
|
||||
|
||||
fn store<T>(&self, index: usize, mut psm: T) -> Result<(), Error>
|
||||
where
|
||||
T: Psm,
|
||||
{
|
||||
let mut _kb = heapless::String::<32>::new();
|
||||
|
||||
psm.set_kv_slice(fb_key!(index, ST_RCA, _kb), &self.root_ca)?;
|
||||
psm.set_kv_slice(
|
||||
fb_key!(index, ST_ICA, _kb),
|
||||
self.icac.as_deref().unwrap_or(&[]),
|
||||
)?;
|
||||
|
||||
psm.set_kv_slice(fb_key!(index, ST_NOC, _kb), &self.noc)?;
|
||||
psm.set_kv_slice(fb_key!(index, ST_IPK, _kb), self.ipk.epoch_key())?;
|
||||
psm.set_kv_slice(fb_key!(index, ST_LBL, _kb), self.label.as_bytes())?;
|
||||
|
||||
let mut buf = [0_u8; crypto::EC_POINT_LEN_BYTES];
|
||||
let len = self.key_pair.get_public_key(&mut buf)?;
|
||||
let key = &buf[..len];
|
||||
psm.set_kv_slice(fb_key!(index, ST_PBKEY, _kb), key)?;
|
||||
|
||||
let mut buf = [0_u8; crypto::BIGNUM_LEN_BYTES];
|
||||
let len = self.key_pair.get_private_key(&mut buf)?;
|
||||
let key = &buf[..len];
|
||||
psm.set_kv_slice(fb_key!(index, ST_PRKEY, _kb), key)?;
|
||||
|
||||
psm.set_kv_u64(fb_key!(index, ST_VID, _kb), self.vendor_id.into())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn load<T>(index: usize, psm: T) -> Result<Self, Error>
|
||||
where
|
||||
T: Psm,
|
||||
{
|
||||
let mut _kb = heapless::String::<32>::new();
|
||||
|
||||
let mut buf = [0u8; MAX_CERT_TLV_LEN];
|
||||
|
||||
let root_ca =
|
||||
heapless::Vec::from_slice(psm.get_kv_slice(fb_key!(index, ST_RCA, _kb), &mut buf)?)
|
||||
.unwrap();
|
||||
|
||||
let icac = psm.get_kv_slice(fb_key!(index, ST_ICA, _kb), &mut buf)?;
|
||||
let icac = if !icac.is_empty() {
|
||||
Some(heapless::Vec::from_slice(icac).unwrap())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let noc =
|
||||
heapless::Vec::from_slice(psm.get_kv_slice(fb_key!(index, ST_NOC, _kb), &mut buf)?)
|
||||
.unwrap();
|
||||
|
||||
let label = psm.get_kv_slice(fb_key!(index, ST_LBL, _kb), &mut buf)?;
|
||||
let label: heapless::String<32> = core::str::from_utf8(label)
|
||||
.map_err(|_| {
|
||||
error!("Couldn't read label");
|
||||
Error::Invalid
|
||||
})?
|
||||
.into();
|
||||
|
||||
let ipk = psm.get_kv_slice(fb_key!(index, ST_IPK, _kb), &mut buf)?;
|
||||
|
||||
let mut buf = [0_u8; crypto::EC_POINT_LEN_BYTES];
|
||||
let pub_key = psm.get_kv_slice(fb_key!(index, ST_PBKEY, _kb), &mut buf)?;
|
||||
|
||||
let mut buf = [0_u8; crypto::BIGNUM_LEN_BYTES];
|
||||
let priv_key = psm.get_kv_slice(fb_key!(index, ST_PRKEY, _kb), &mut buf)?;
|
||||
let keypair = KeyPair::new_from_components(pub_key, priv_key)?;
|
||||
|
||||
let vendor_id = psm.get_kv_u64(fb_key!(index, ST_VID, _kb))?;
|
||||
|
||||
Fabric::new(keypair, root_ca, icac, noc, ipk, vendor_id as u16, &label)
|
||||
}
|
||||
|
||||
fn remove<T>(index: usize, mut psm: T) -> Result<(), Error>
|
||||
where
|
||||
T: Psm,
|
||||
{
|
||||
let mut _kb = heapless::String::<32>::new();
|
||||
|
||||
psm.remove(fb_key!(index, ST_RCA, _kb))?;
|
||||
psm.remove(fb_key!(index, ST_ICA, _kb))?;
|
||||
|
||||
psm.remove(fb_key!(index, ST_NOC, _kb))?;
|
||||
|
||||
psm.remove(fb_key!(index, ST_LBL, _kb))?;
|
||||
|
||||
psm.remove(fb_key!(index, ST_IPK, _kb))?;
|
||||
|
||||
psm.remove(fb_key!(index, ST_PBKEY, _kb))?;
|
||||
psm.remove(fb_key!(index, ST_PRKEY, _kb))?;
|
||||
|
||||
psm.remove(fb_key!(index, ST_VID, _kb))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
async fn store_async<T>(&self, index: usize, mut psm: T) -> Result<(), Error>
|
||||
where
|
||||
T: crate::persist::asynch::AsyncPsm,
|
||||
{
|
||||
let mut _kb = heapless::String::<32>::new();
|
||||
|
||||
psm.set_kv_slice(fb_key!(index, ST_RCA, _kb), &self.root_ca)
|
||||
.await?;
|
||||
|
||||
psm.set_kv_slice(
|
||||
fb_key!(index, ST_ICA, _kb),
|
||||
self.icac.as_deref().unwrap_or(&[]),
|
||||
)
|
||||
.await?;
|
||||
|
||||
psm.set_kv_slice(fb_key!(index, ST_NOC, _kb), &self.noc)
|
||||
.await?;
|
||||
psm.set_kv_slice(fb_key!(index, ST_IPK, _kb), self.ipk.epoch_key())
|
||||
.await?;
|
||||
psm.set_kv_slice(fb_key!(index, ST_LBL, _kb), self.label.as_bytes())
|
||||
.await?;
|
||||
|
||||
let mut buf = [0_u8; crypto::EC_POINT_LEN_BYTES];
|
||||
let len = self.key_pair.get_public_key(&mut buf)?;
|
||||
let key = &buf[..len];
|
||||
psm.set_kv_slice(fb_key!(index, ST_PBKEY, _kb), key).await?;
|
||||
|
||||
let mut buf = [0_u8; crypto::BIGNUM_LEN_BYTES];
|
||||
let len = self.key_pair.get_private_key(&mut buf)?;
|
||||
let key = &buf[..len];
|
||||
psm.set_kv_slice(fb_key!(index, ST_PRKEY, _kb), key).await?;
|
||||
|
||||
psm.set_kv_u64(fb_key!(index, ST_VID, _kb), self.vendor_id.into())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
async fn load_async<T>(index: usize, psm: T) -> Result<Self, Error>
|
||||
where
|
||||
T: crate::persist::asynch::AsyncPsm,
|
||||
{
|
||||
let mut _kb = heapless::String::<32>::new();
|
||||
|
||||
let mut buf = [0u8; MAX_CERT_TLV_LEN];
|
||||
|
||||
let root_ca = heapless::Vec::from_slice(
|
||||
psm.get_kv_slice(fb_key!(index, ST_RCA, _kb), &mut buf)
|
||||
.await?,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let icac = psm
|
||||
.get_kv_slice(fb_key!(index, ST_ICA, _kb), &mut buf)
|
||||
.await?;
|
||||
let icac = if !icac.is_empty() {
|
||||
Some(heapless::Vec::from_slice(icac).unwrap())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let noc = heapless::Vec::from_slice(
|
||||
psm.get_kv_slice(fb_key!(index, ST_NOC, _kb), &mut buf)
|
||||
.await?,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let label = psm
|
||||
.get_kv_slice(fb_key!(index, ST_LBL, _kb), &mut buf)
|
||||
.await?;
|
||||
let label: heapless::String<32> = core::str::from_utf8(label)
|
||||
.map_err(|_| {
|
||||
error!("Couldn't read label");
|
||||
Error::Invalid
|
||||
})?
|
||||
.into();
|
||||
|
||||
let ipk = psm
|
||||
.get_kv_slice(fb_key!(index, ST_IPK, _kb), &mut buf)
|
||||
.await?;
|
||||
|
||||
let mut buf = [0_u8; crypto::EC_POINT_LEN_BYTES];
|
||||
let pub_key = psm
|
||||
.get_kv_slice(fb_key!(index, ST_PBKEY, _kb), &mut buf)
|
||||
.await?;
|
||||
|
||||
let mut buf = [0_u8; crypto::BIGNUM_LEN_BYTES];
|
||||
let priv_key = psm
|
||||
.get_kv_slice(fb_key!(index, ST_PRKEY, _kb), &mut buf)
|
||||
.await?;
|
||||
let keypair = KeyPair::new_from_components(pub_key, priv_key)?;
|
||||
|
||||
let vendor_id = psm.get_kv_u64(fb_key!(index, ST_VID, _kb)).await?;
|
||||
|
||||
Fabric::new(keypair, root_ca, icac, noc, ipk, vendor_id as u16, &label)
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
async fn remove_async<T>(index: usize, mut psm: T) -> Result<(), Error>
|
||||
where
|
||||
T: crate::persist::asynch::AsyncPsm,
|
||||
{
|
||||
let mut _kb = heapless::String::<32>::new();
|
||||
|
||||
psm.remove(fb_key!(index, ST_RCA, _kb)).await?;
|
||||
psm.remove(fb_key!(index, ST_ICA, _kb)).await?;
|
||||
|
||||
psm.remove(fb_key!(index, ST_NOC, _kb)).await?;
|
||||
|
||||
psm.remove(fb_key!(index, ST_LBL, _kb)).await?;
|
||||
|
||||
psm.remove(fb_key!(index, ST_IPK, _kb)).await?;
|
||||
|
||||
psm.remove(fb_key!(index, ST_PBKEY, _kb)).await?;
|
||||
psm.remove(fb_key!(index, ST_PRKEY, _kb)).await?;
|
||||
|
||||
psm.remove(fb_key!(index, ST_VID, _kb)).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub const MAX_SUPPORTED_FABRICS: usize = 3;
|
||||
|
||||
type FabricEntries = [Option<Fabric>; MAX_SUPPORTED_FABRICS];
|
||||
|
||||
pub struct FabricMgr {
|
||||
// The outside world expects Fabric Index to be one more than the actual one
|
||||
// since 0 is not allowed. Need to handle this cleanly somehow
|
||||
fabrics: [Option<Fabric>; MAX_SUPPORTED_FABRICS],
|
||||
fabrics: FabricEntries,
|
||||
changed: bool,
|
||||
}
|
||||
|
||||
|
@ -440,41 +201,20 @@ impl FabricMgr {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn store<T>(&mut self, mut psm: T) -> Result<(), Error>
|
||||
where
|
||||
T: Psm,
|
||||
{
|
||||
if self.changed {
|
||||
for i in 1..MAX_SUPPORTED_FABRICS {
|
||||
if let Some(fabric) = self.fabrics[i].as_mut() {
|
||||
info!("Storing fabric at index {}", i);
|
||||
fabric.store(i, &mut psm)?;
|
||||
} else {
|
||||
let _ = Fabric::remove(i, &mut psm);
|
||||
}
|
||||
pub fn load(&mut self, data: &[u8], mdns_mgr: &mut MdnsMgr) -> Result<(), Error> {
|
||||
for fabric in &self.fabrics {
|
||||
if let Some(fabric) = fabric {
|
||||
mdns_mgr.unpublish_service(&fabric.mdns_service_name, ServiceMode::Commissioned)?;
|
||||
}
|
||||
|
||||
self.changed = false;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
let root = TLVList::new(data).iter().next().ok_or(Error::Invalid)?;
|
||||
|
||||
pub fn load<T>(&mut self, mut psm: T, mdns_mgr: &mut MdnsMgr) -> Result<(), Error>
|
||||
where
|
||||
T: Psm,
|
||||
{
|
||||
for i in 1..MAX_SUPPORTED_FABRICS {
|
||||
let result = Fabric::load(i, &mut psm);
|
||||
if let Ok(fabric) = result {
|
||||
info!("Adding new fabric at index {}", i);
|
||||
self.fabrics[i] = Some(fabric);
|
||||
mdns_mgr.publish_service(
|
||||
&self.fabrics[i].as_ref().unwrap().mdns_service_name,
|
||||
ServiceMode::Commissioned,
|
||||
)?;
|
||||
} else {
|
||||
self.fabrics[i] = None;
|
||||
self.fabrics = FabricEntries::from_tlv(&root)?;
|
||||
|
||||
for fabric in &self.fabrics {
|
||||
if let Some(fabric) = fabric {
|
||||
mdns_mgr.publish_service(&fabric.mdns_service_name, ServiceMode::Commissioned)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -483,67 +223,32 @@ impl FabricMgr {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub async fn store_async<T>(&mut self, mut psm: T) -> Result<(), Error>
|
||||
where
|
||||
T: crate::persist::asynch::AsyncPsm,
|
||||
{
|
||||
pub fn store<'a>(&mut self, buf: &'a mut [u8]) -> Result<Option<&'a [u8]>, Error> {
|
||||
if self.changed {
|
||||
for i in 1..MAX_SUPPORTED_FABRICS {
|
||||
if let Some(fabric) = self.fabrics[i].as_mut() {
|
||||
info!("Storing fabric at index {}", i);
|
||||
fabric.store_async(i, &mut psm).await?;
|
||||
} else {
|
||||
let _ = Fabric::remove_async(i, &mut psm).await;
|
||||
}
|
||||
}
|
||||
let mut wb = WriteBuf::new(buf);
|
||||
let mut tw = TLVWriter::new(&mut wb);
|
||||
self.fabrics.to_tlv(&mut tw, TagType::Anonymous)?;
|
||||
|
||||
self.changed = false;
|
||||
|
||||
let len = tw.get_tail();
|
||||
|
||||
Ok(Some(&buf[..len]))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub async fn load_async<T>(
|
||||
&mut self,
|
||||
mut psm: T,
|
||||
mdns_mgr: &mut MdnsMgr<'_>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: crate::persist::asynch::AsyncPsm,
|
||||
{
|
||||
for i in 1..MAX_SUPPORTED_FABRICS {
|
||||
let result = Fabric::load_async(i, &mut psm).await;
|
||||
if let Ok(fabric) = result {
|
||||
info!("Adding new fabric at index {}", i);
|
||||
self.fabrics[i] = Some(fabric);
|
||||
mdns_mgr.publish_service(
|
||||
&self.fabrics[i].as_ref().unwrap().mdns_service_name,
|
||||
ServiceMode::Commissioned,
|
||||
)?;
|
||||
} else {
|
||||
self.fabrics[i] = None;
|
||||
}
|
||||
}
|
||||
|
||||
self.changed = false;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add(&mut self, f: Fabric, mdns_mgr: &mut MdnsMgr) -> Result<u8, Error> {
|
||||
for i in 1..MAX_SUPPORTED_FABRICS {
|
||||
if self.fabrics[i].is_none() {
|
||||
self.fabrics[i] = Some(f);
|
||||
mdns_mgr.publish_service(
|
||||
&self.fabrics[i].as_ref().unwrap().mdns_service_name,
|
||||
ServiceMode::Commissioned,
|
||||
)?;
|
||||
for (index, fabric) in self.fabrics.iter_mut().enumerate() {
|
||||
if fabric.is_none() {
|
||||
mdns_mgr.publish_service(&f.mdns_service_name, ServiceMode::Commissioned)?;
|
||||
|
||||
*fabric = Some(f);
|
||||
|
||||
self.changed = true;
|
||||
|
||||
return Ok(i as u8);
|
||||
return Ok((index + 1) as u8);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -551,20 +256,24 @@ impl FabricMgr {
|
|||
}
|
||||
|
||||
pub fn remove(&mut self, fab_idx: u8, mdns_mgr: &mut MdnsMgr) -> Result<(), Error> {
|
||||
if let Some(f) = self.fabrics[fab_idx as usize].take() {
|
||||
mdns_mgr.unpublish_service(&f.mdns_service_name, ServiceMode::Commissioned)?;
|
||||
self.changed = true;
|
||||
Ok(())
|
||||
if fab_idx > 0 && fab_idx as usize <= self.fabrics.len() {
|
||||
if let Some(f) = self.fabrics[(fab_idx - 1) as usize].take() {
|
||||
mdns_mgr.unpublish_service(&f.mdns_service_name, ServiceMode::Commissioned)?;
|
||||
self.changed = true;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::NotFound)
|
||||
}
|
||||
} else {
|
||||
Err(Error::NotFound)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_dest_id(&self, random: &[u8], target: &[u8]) -> Result<usize, Error> {
|
||||
for i in 1..MAX_SUPPORTED_FABRICS {
|
||||
if let Some(fabric) = &self.fabrics[i] {
|
||||
for (index, fabric) in self.fabrics.iter().enumerate() {
|
||||
if let Some(fabric) = fabric {
|
||||
if fabric.match_dest_id(random, target).is_ok() {
|
||||
return Ok(i);
|
||||
return Ok(index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -572,26 +281,19 @@ impl FabricMgr {
|
|||
}
|
||||
|
||||
pub fn get_fabric(&self, idx: usize) -> Result<Option<&Fabric>, Error> {
|
||||
Ok(self.fabrics[idx].as_ref())
|
||||
if idx == 0 {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(self.fabrics[idx - 1].as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
for i in 1..MAX_SUPPORTED_FABRICS {
|
||||
if self.fabrics[i].is_some() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
!self.fabrics.iter().any(Option::is_some)
|
||||
}
|
||||
|
||||
pub fn used_count(&self) -> usize {
|
||||
let mut count = 0;
|
||||
for i in 1..MAX_SUPPORTED_FABRICS {
|
||||
if self.fabrics[i].is_some() {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
count
|
||||
self.fabrics.iter().filter(|f| f.is_some()).count()
|
||||
}
|
||||
|
||||
// Parameters to T are the Fabric and its Fabric Index
|
||||
|
@ -599,25 +301,27 @@ impl FabricMgr {
|
|||
where
|
||||
T: FnMut(&Fabric, u8) -> Result<(), Error>,
|
||||
{
|
||||
for i in 1..MAX_SUPPORTED_FABRICS {
|
||||
if let Some(fabric) = &self.fabrics[i] {
|
||||
f(fabric, i as u8)?;
|
||||
for (index, fabric) in self.fabrics.iter().enumerate() {
|
||||
if let Some(fabric) = fabric {
|
||||
f(fabric, (index + 1) as u8)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_label(&mut self, index: u8, label: &str) -> Result<(), Error> {
|
||||
let index = index as usize;
|
||||
if !label.is_empty() {
|
||||
for i in 1..MAX_SUPPORTED_FABRICS {
|
||||
if let Some(fabric) = &self.fabrics[i] {
|
||||
if fabric.label == label {
|
||||
return Err(Error::Invalid);
|
||||
}
|
||||
}
|
||||
if self
|
||||
.fabrics
|
||||
.iter()
|
||||
.filter_map(|f| f.as_ref())
|
||||
.any(|f| f.label == label)
|
||||
{
|
||||
return Err(Error::Invalid);
|
||||
}
|
||||
}
|
||||
|
||||
let index = (index - 1) as usize;
|
||||
if let Some(fabric) = &mut self.fabrics[index] {
|
||||
fabric.label = label.into();
|
||||
self.changed = true;
|
||||
|
|
|
@ -15,12 +15,18 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::{crypto, error::Error};
|
||||
use crate::{
|
||||
crypto::{self, SYMM_KEY_LEN_BYTES},
|
||||
error::Error,
|
||||
tlv::{FromTLV, TLVElement, TLVWriter, TagType, ToTLV},
|
||||
};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
type KeySetKey = [u8; SYMM_KEY_LEN_BYTES];
|
||||
|
||||
#[derive(Debug, Default, FromTLV, ToTLV)]
|
||||
pub struct KeySet {
|
||||
pub epoch_key: [u8; crypto::SYMM_KEY_LEN_BYTES],
|
||||
pub op_key: [u8; crypto::SYMM_KEY_LEN_BYTES],
|
||||
pub epoch_key: KeySetKey,
|
||||
pub op_key: KeySetKey,
|
||||
}
|
||||
|
||||
impl KeySet {
|
||||
|
|
|
@ -14,216 +14,63 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
pub trait Psm {
|
||||
fn set_kv_slice(&mut self, key: &str, val: &[u8]) -> Result<(), Error>;
|
||||
fn get_kv_slice<'a>(&self, key: &str, buf: &'a mut [u8]) -> Result<&'a [u8], Error>;
|
||||
|
||||
fn set_kv_u64(&mut self, key: &str, val: u64) -> Result<(), Error>;
|
||||
fn get_kv_u64(&self, key: &str) -> Result<u64, Error>;
|
||||
|
||||
fn remove(&mut self, key: &str) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
impl<T> Psm for &mut T
|
||||
where
|
||||
T: Psm,
|
||||
{
|
||||
fn set_kv_slice(&mut self, key: &str, val: &[u8]) -> Result<(), Error> {
|
||||
(**self).set_kv_slice(key, val)
|
||||
}
|
||||
|
||||
fn get_kv_slice<'a>(&self, key: &str, buf: &'a mut [u8]) -> Result<&'a [u8], Error> {
|
||||
(**self).get_kv_slice(key, buf)
|
||||
}
|
||||
|
||||
fn set_kv_u64(&mut self, key: &str, val: u64) -> Result<(), Error> {
|
||||
(**self).set_kv_u64(key, val)
|
||||
}
|
||||
|
||||
fn get_kv_u64(&self, key: &str) -> Result<u64, Error> {
|
||||
(**self).get_kv_u64(key)
|
||||
}
|
||||
|
||||
fn remove(&mut self, key: &str) -> Result<(), Error> {
|
||||
(**self).remove(key)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub mod asynch {
|
||||
use crate::error::Error;
|
||||
|
||||
use super::Psm;
|
||||
|
||||
pub trait AsyncPsm {
|
||||
async fn set_kv_slice<'a>(&'a mut self, key: &'a str, val: &'a [u8]) -> Result<(), Error>;
|
||||
async fn get_kv_slice<'a, 'b>(
|
||||
&'a self,
|
||||
key: &'a str,
|
||||
buf: &'b mut [u8],
|
||||
) -> Result<&'b [u8], Error>;
|
||||
|
||||
async fn set_kv_u64<'a>(&'a mut self, key: &'a str, val: u64) -> Result<(), Error>;
|
||||
async fn get_kv_u64<'a>(&'a self, key: &'a str) -> Result<u64, Error>;
|
||||
|
||||
async fn remove<'a>(&'a mut self, key: &'a str) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
impl<T> AsyncPsm for &mut T
|
||||
where
|
||||
T: AsyncPsm,
|
||||
{
|
||||
async fn set_kv_slice<'a>(&'a mut self, key: &'a str, val: &'a [u8]) -> Result<(), Error> {
|
||||
(**self).set_kv_slice(key, val).await
|
||||
}
|
||||
|
||||
async fn get_kv_slice<'a, 'b>(
|
||||
&'a self,
|
||||
key: &'a str,
|
||||
buf: &'b mut [u8],
|
||||
) -> Result<&'b [u8], Error> {
|
||||
(**self).get_kv_slice(key, buf).await
|
||||
}
|
||||
|
||||
async fn set_kv_u64<'a>(&'a mut self, key: &'a str, val: u64) -> Result<(), Error> {
|
||||
(**self).set_kv_u64(key, val).await
|
||||
}
|
||||
|
||||
async fn get_kv_u64<'a>(&'a self, key: &'a str) -> Result<u64, Error> {
|
||||
(**self).get_kv_u64(key).await
|
||||
}
|
||||
|
||||
async fn remove<'a>(&'a mut self, key: &'a str) -> Result<(), Error> {
|
||||
(**self).remove(key).await
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Asyncify<T>(pub T);
|
||||
|
||||
impl<T> AsyncPsm for Asyncify<T>
|
||||
where
|
||||
T: Psm,
|
||||
{
|
||||
async fn set_kv_slice<'a>(&'a mut self, key: &'a str, val: &'a [u8]) -> Result<(), Error> {
|
||||
self.0.set_kv_slice(key, val)
|
||||
}
|
||||
|
||||
async fn get_kv_slice<'a, 'b>(
|
||||
&'a self,
|
||||
key: &'a str,
|
||||
buf: &'b mut [u8],
|
||||
) -> Result<&'b [u8], Error> {
|
||||
self.0.get_kv_slice(key, buf)
|
||||
}
|
||||
|
||||
async fn set_kv_u64<'a>(&'a mut self, key: &'a str, val: u64) -> Result<(), Error> {
|
||||
self.0.set_kv_u64(key, val)
|
||||
}
|
||||
|
||||
async fn get_kv_u64<'a>(&'a self, key: &'a str) -> Result<u64, Error> {
|
||||
self.0.get_kv_u64(key)
|
||||
}
|
||||
|
||||
async fn remove<'a>(&'a mut self, key: &'a str) -> Result<(), Error> {
|
||||
self.0.remove(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "std")]
|
||||
pub use file_psm::*;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub mod std {
|
||||
use std::fs::{self, DirBuilder, File};
|
||||
mod file_psm {
|
||||
use std::fs;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
use super::Psm;
|
||||
|
||||
pub struct FilePsm {}
|
||||
|
||||
const PSM_DIR: &str = "/tmp/matter_psm";
|
||||
|
||||
macro_rules! psm_path {
|
||||
($key:ident) => {
|
||||
format!("{}/{}", PSM_DIR, $key)
|
||||
};
|
||||
pub struct FilePsm {
|
||||
dir: PathBuf,
|
||||
}
|
||||
|
||||
impl FilePsm {
|
||||
pub fn new() -> Result<Self, Error> {
|
||||
let result = DirBuilder::new().create(PSM_DIR);
|
||||
if let Err(e) = result {
|
||||
if e.kind() != std::io::ErrorKind::AlreadyExists {
|
||||
return Err(e.into());
|
||||
pub fn new(dir: PathBuf) -> Result<Self, Error> {
|
||||
fs::create_dir_all(&dir)?;
|
||||
|
||||
Ok(Self { dir })
|
||||
}
|
||||
|
||||
pub fn load<'a>(&self, key: &str, buf: &'a mut [u8]) -> Result<Option<&'a [u8]>, Error> {
|
||||
let path = self.dir.join(key);
|
||||
|
||||
match fs::File::open(path) {
|
||||
Ok(mut file) => {
|
||||
let mut offset = 0;
|
||||
|
||||
loop {
|
||||
if offset == buf.len() {
|
||||
return Err(Error::NoSpace);
|
||||
}
|
||||
|
||||
let len = file.read(&mut buf[offset..])?;
|
||||
|
||||
if len == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
offset += len;
|
||||
}
|
||||
|
||||
Ok(Some(&buf[..offset]))
|
||||
}
|
||||
Err(_) => Ok(None),
|
||||
}
|
||||
|
||||
Ok(Self {})
|
||||
}
|
||||
|
||||
pub fn set_kv_slice(&mut self, key: &str, val: &[u8]) -> Result<(), Error> {
|
||||
let mut f = File::create(psm_path!(key))?;
|
||||
f.write_all(val)?;
|
||||
pub fn store(&self, key: &str, data: &[u8]) -> Result<(), Error> {
|
||||
let path = self.dir.join(key);
|
||||
|
||||
let mut file = fs::File::create(path)?;
|
||||
|
||||
file.write_all(data)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_kv_slice<'a>(&self, key: &str, buf: &'a mut [u8]) -> Result<&'a [u8], Error> {
|
||||
let mut f = File::open(psm_path!(key))?;
|
||||
let mut offset = 0;
|
||||
|
||||
loop {
|
||||
let len = f.read(&mut buf[offset..])?;
|
||||
offset += len;
|
||||
|
||||
if len == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(&buf[..offset])
|
||||
}
|
||||
|
||||
pub fn set_kv_u64(&mut self, key: &str, val: u64) -> Result<(), Error> {
|
||||
let mut f = File::create(psm_path!(key))?;
|
||||
f.write_all(&val.to_be_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_kv_u64(&self, key: &str) -> Result<u64, Error> {
|
||||
let mut f = File::open(psm_path!(key))?;
|
||||
let mut buf = [0; 8];
|
||||
f.read_exact(&mut buf)?;
|
||||
Ok(u64::from_be_bytes(buf))
|
||||
}
|
||||
|
||||
pub fn remove(&self, key: &str) -> Result<(), Error> {
|
||||
fs::remove_file(psm_path!(key))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Psm for FilePsm {
|
||||
fn set_kv_slice(&mut self, key: &str, val: &[u8]) -> Result<(), Error> {
|
||||
FilePsm::set_kv_slice(self, key, val)
|
||||
}
|
||||
|
||||
fn get_kv_slice<'a>(&self, key: &str, buf: &'a mut [u8]) -> Result<&'a [u8], Error> {
|
||||
FilePsm::get_kv_slice(self, key, buf)
|
||||
}
|
||||
|
||||
fn set_kv_u64(&mut self, key: &str, val: u64) -> Result<(), Error> {
|
||||
FilePsm::set_kv_u64(self, key, val)
|
||||
}
|
||||
|
||||
fn get_kv_u64(&self, key: &str) -> Result<u64, Error> {
|
||||
FilePsm::get_kv_u64(self, key)
|
||||
}
|
||||
|
||||
fn remove(&mut self, key: &str) -> Result<(), Error> {
|
||||
FilePsm::remove(self, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,26 +35,21 @@ pub trait FromTLV<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Default + FromTLV<'a> + Copy, const N: usize> FromTLV<'a> for [T; N] {
|
||||
impl<'a, T: FromTLV<'a>, const N: usize> FromTLV<'a> for [T; N] {
|
||||
fn from_tlv(t: &TLVElement<'a>) -> Result<Self, Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
t.confirm_array()?;
|
||||
let mut a: [T; N] = [Default::default(); N];
|
||||
let mut index = 0;
|
||||
|
||||
let mut a = heapless::Vec::<T, N>::new();
|
||||
if let Some(tlv_iter) = t.enter() {
|
||||
for element in tlv_iter {
|
||||
if index < N {
|
||||
a[index] = T::from_tlv(&element)?;
|
||||
index += 1;
|
||||
} else {
|
||||
error!("Received TLV Array with elements larger than current size");
|
||||
break;
|
||||
}
|
||||
a.push(T::from_tlv(&element)?).map_err(|_| Error::NoSpace)?;
|
||||
}
|
||||
}
|
||||
Ok(a)
|
||||
|
||||
a.into_array().map_err(|_| Error::Invalid)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,6 +109,8 @@ totlv_for!(i8 u8 u16 u32 u64 bool);
|
|||
//
|
||||
// - UtfStr, OctetStr: These are versions that map to utfstr and ostr in the TLV spec
|
||||
// - These only have references into the original list
|
||||
// - heapless::String<N>, Vheapless::ec<u8, N>: Is the owned version of utfstr and ostr, data is cloned into this
|
||||
// - heapless::String is only partially implemented
|
||||
//
|
||||
// - TLVArray: Is an array of entries, with reference within the original list
|
||||
|
||||
|
@ -165,6 +162,38 @@ impl<'a> ToTLV for OctetStr<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Implements the Owned version of Octet String
|
||||
impl<const N: usize> FromTLV<'_> for heapless::Vec<u8, N> {
|
||||
fn from_tlv(t: &TLVElement) -> Result<heapless::Vec<u8, N>, Error> {
|
||||
heapless::Vec::from_slice(t.slice()?).map_err(|_| Error::NoSpace)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> ToTLV for heapless::Vec<u8, N> {
|
||||
fn to_tlv(&self, tw: &mut TLVWriter, tag: TagType) -> Result<(), Error> {
|
||||
tw.str16(tag, self.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements the Owned version of UTF String
|
||||
impl<const N: usize> FromTLV<'_> for heapless::String<N> {
|
||||
fn from_tlv(t: &TLVElement) -> Result<heapless::String<N>, Error> {
|
||||
let mut string = heapless::String::new();
|
||||
|
||||
string
|
||||
.push_str(core::str::from_utf8(t.slice()?)?)
|
||||
.map_err(|_| Error::NoSpace)?;
|
||||
|
||||
Ok(string)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> ToTLV for heapless::String<N> {
|
||||
fn to_tlv(&self, tw: &mut TLVWriter, tag: TagType) -> Result<(), Error> {
|
||||
tw.utf16(tag, self.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies to all the Option<> Processing
|
||||
impl<'a, T: FromTLV<'a>> FromTLV<'a> for Option<T> {
|
||||
fn from_tlv(t: &TLVElement<'a>) -> Result<Option<T>, Error> {
|
||||
|
@ -259,7 +288,7 @@ impl<'a, T: ToTLV> TLVArray<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ToTLV + FromTLV<'a> + Copy> TLVArray<'a, T> {
|
||||
impl<'a, T: ToTLV + FromTLV<'a> + Clone> TLVArray<'a, T> {
|
||||
pub fn get_index(&self, index: usize) -> T {
|
||||
for (curr, element) in self.iter().enumerate() {
|
||||
if curr == index {
|
||||
|
@ -270,12 +299,12 @@ impl<'a, T: ToTLV + FromTLV<'a> + Copy> TLVArray<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: FromTLV<'a> + Copy> Iterator for TLVArrayIter<'a, T> {
|
||||
impl<'a, T: FromTLV<'a> + Clone> Iterator for TLVArrayIter<'a, T> {
|
||||
type Item = T;
|
||||
/* Code for going to the next Element */
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self {
|
||||
Self::Slice(s_iter) => s_iter.next().copied(),
|
||||
Self::Slice(s_iter) => s_iter.next().cloned(),
|
||||
Self::Ptr(p_iter) => {
|
||||
if let Some(tlv_iter) = p_iter.as_mut() {
|
||||
let e = tlv_iter.next();
|
||||
|
@ -294,7 +323,7 @@ impl<'a, T: FromTLV<'a> + Copy> Iterator for TLVArrayIter<'a, T> {
|
|||
|
||||
impl<'a, T> PartialEq<&[T]> for TLVArray<'a, T>
|
||||
where
|
||||
T: ToTLV + FromTLV<'a> + Copy + PartialEq,
|
||||
T: ToTLV + FromTLV<'a> + Clone + PartialEq,
|
||||
{
|
||||
fn eq(&self, other: &&[T]) -> bool {
|
||||
let mut iter1 = self.iter();
|
||||
|
@ -313,7 +342,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: FromTLV<'a> + Copy + ToTLV> ToTLV for TLVArray<'a, T> {
|
||||
impl<'a, T: FromTLV<'a> + Clone + ToTLV> ToTLV for TLVArray<'a, T> {
|
||||
fn to_tlv(&self, tw: &mut TLVWriter, tag_type: TagType) -> Result<(), Error> {
|
||||
tw.start_array(tag_type)?;
|
||||
for a in self.iter() {
|
||||
|
@ -340,7 +369,7 @@ impl<'a, T> FromTLV<'a> for TLVArray<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Debug + ToTLV + FromTLV<'a> + Copy> Debug for TLVArray<'a, T> {
|
||||
impl<'a, T: Debug + ToTLV + FromTLV<'a> + Clone> Debug for TLVArray<'a, T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "TLVArray [")?;
|
||||
let mut first = true;
|
||||
|
|
Loading…
Add table
Reference in a new issue