1use std::collections::{HashMap, HashSet};
2use std::sync::Arc;
3use std::sync::atomic::AtomicU32;
4
5use anyhow::{Context, Result};
6
7use crate::fabric;
8
9use super::Device;
10use super::types::{AttributeOverride, DeviceConfig, FabricInfo, PersistedDeviceState, PersistedFabricState};
11
12static PERSISTED_ATTRIBUTES: &[(u16, u32, u32)] = &[];
13
14impl Device {
15 pub(crate) fn collect_attribute_overrides(&self) -> Vec<AttributeOverride> {
16 let mut overrides = Vec::new();
17 for &(endpoint, cluster, attribute) in PERSISTED_ATTRIBUTES.iter().chain(self.extra_persisted.iter()) {
18 if let Some(tlv) = self.attributes.get(&(endpoint, cluster, attribute)) {
19 overrides.push(AttributeOverride {
20 endpoint,
21 cluster,
22 attribute,
23 tlv_hex: hex::encode(tlv),
24 });
25 }
26 }
27 overrides
28 }
29
30 pub fn add_persisted_attribute(&mut self, endpoint: u16, cluster: u32, attribute: u32) {
32 let key = (endpoint, cluster, attribute);
33 if !self.extra_persisted.contains(&key) {
34 self.extra_persisted.push(key);
35 }
36 }
37
38 pub(crate) fn save_state(&self, state_dir: &str) -> Result<()> {
40 if self.fabrics.is_empty() {
41 let path = format!("{}/device_state.json", state_dir);
42 if std::path::Path::new(&path).exists() {
43 std::fs::remove_file(&path)?;
44 log::info!("All fabrics removed - deleted {}", path);
45 }
46 return Ok(());
47 }
48
49 let fabrics: Vec<PersistedFabricState> = self
50 .fabrics
51 .iter()
52 .map(|fi| PersistedFabricState {
53 fabric_index: fi.fabric_index,
54 trusted_root_cert: fi.trusted_root_cert.clone(),
55 noc: fi.noc.clone(),
56 icac: fi.icac.clone(),
57 ipk: fi.ipk.clone(),
58 controller_id: fi.controller_id,
59 vendor_id: fi.vendor_id,
60 device_matter_cert: fi.device_matter_cert.clone(),
61 label: fi.label.clone(),
62 })
63 .collect();
64
65 let state = PersistedDeviceState {
66 operational_key_hex: hex::encode(self.operational_key.to_bytes()),
67 next_fabric_index: self.next_fabric_index,
68 fabrics,
69 attribute_overrides: self.collect_attribute_overrides(),
70 };
71
72 std::fs::create_dir_all(state_dir)?;
73 let path = format!("{}/device_state.json", state_dir);
74 let json = serde_json::to_string_pretty(&state)?;
75 std::fs::write(&path, json)?;
76 log::info!("Device state saved to {}", path);
77 Ok(())
78 }
79
80 pub(crate) async fn register_operational_mdns(&self, fabric_idx: usize) -> Result<()> {
83 let fi = &self.fabrics[fabric_idx];
84 let nod_id = fi.device_node_id()?;
85 let ca_public_key = fi.ca_public_key()?;
86 let fabric_id = fi.fabric_id()?;
87 let ca_id = fi.ca_id()?;
88 let fabric = fabric::Fabric::new(fabric_id, ca_id, &ca_public_key, &fi.ipk);
89
90 let iname = format!(
91 "{}-{:016X}",
92 hex::encode_upper(fabric.compressed()?),
93 nod_id
94 );
95 let op_port: u16 = self
96 .config
97 .listen_address
98 .rsplit(':')
99 .next()
100 .and_then(|p| p.parse().ok())
101 .unwrap_or(5540);
102 let (adv_v4, adv_v6) = self.config.split_advertise_ips();
103 let svc = crate::mdns2::ServiceRegistration {
104 instance_name: iname,
105 service_type: "_matter._tcp.local".to_string(),
106 port: op_port,
107 txt_records: vec![
108 ("SII".to_string(), "500".to_string()),
109 ("SAI".to_string(), "300".to_string()),
110 ],
111 hostname: self.config.hostname.clone(),
112 ttl: 120,
113 subtypes: vec![],
114 ips_v4: adv_v4,
115 ips_v6: adv_v6,
116 };
117 self.mdns.register_service(svc).await;
118 Ok(())
119 }
120
121 pub async fn from_persisted_state(
126 config: DeviceConfig,
127 mdns: Arc<crate::mdns2::MdnsService>,
128 state_dir: &str,
129 ) -> Result<Self> {
130 let path = format!("{}/device_state.json", state_dir);
131 let json = std::fs::read_to_string(&path)
132 .with_context(|| format!("Cannot read persisted state from {}", path))?;
133 let state: PersistedDeviceState = serde_json::from_str(&json)?;
134
135 let key_bytes = hex::decode(&state.operational_key_hex)
137 .context("Invalid hex in operational_key_hex")?;
138 let operational_key = p256::SecretKey::from_slice(&key_bytes)
139 .context("Invalid P-256 scalar in persisted operational key")?;
140
141 let socket = tokio::net::UdpSocket::bind(&config.listen_address).await?;
142
143 let mut salt = vec![0u8; 32];
144 rand::RngCore::fill_bytes(&mut rand::thread_rng(), &mut salt);
145
146 let fabrics: Vec<FabricInfo> = state
147 .fabrics
148 .iter()
149 .map(|pf| FabricInfo {
150 fabric_index: pf.fabric_index,
151 ipk: pf.ipk.clone(),
152 fabric: None,
153 device_matter_cert: pf.device_matter_cert.clone(),
154 controller_id: pf.controller_id,
155 vendor_id: pf.vendor_id,
156 trusted_root_cert: pf.trusted_root_cert.clone(),
157 noc: pf.noc.clone(),
158 icac: pf.icac.clone(),
159 label: pf.label.clone(),
160 })
161 .collect();
162
163 let mut device = Self {
164 config,
165 socket,
166 salt,
167 pbkdf_iterations: 1000,
168 operational_key,
169 message_counter: AtomicU32::new(crate::util::cryptoutil::initial_message_counter()),
170 pase_state: None,
171 pase_session: None,
172 case_states: HashMap::new(),
173 case_sessions: Vec::new(),
174 subscribe_states: Vec::new(),
175 active_subscriptions: Vec::new(),
176 pending_chunks: Vec::new(),
177 fabrics,
178 next_fabric_index: state.next_fabric_index,
179 pending_root_cert: None,
180 unencrypted_reception: HashMap::new(),
181 endpoints: vec![0],
182 attributes: HashMap::new(),
183 dirty_attributes: HashSet::new(),
184 mdns,
185 extra_persisted: Vec::new(),
186 };
187
188 device.setup_default_attributes()?;
189
190 for ov in &state.attribute_overrides {
194 let tlv = hex::decode(&ov.tlv_hex)
195 .with_context(|| format!("Bad tlv_hex for ({},{},{})", ov.endpoint, ov.cluster, ov.attribute))?;
196 device.attributes.insert((ov.endpoint, ov.cluster, ov.attribute), tlv);
197 }
198
199 device.rebuild_fabrics_attribute()?;
201 device.dirty_attributes.clear();
202
203 for i in 0..device.fabrics.len() {
205 device.register_operational_mdns(i).await?;
206 }
207
208 log::info!(
209 "Device state restored from {} ({} fabric(s))",
210 path,
211 device.fabrics.len()
212 );
213 Ok(device)
214 }
215}