1use core::future::Future;
2
3use embassy_futures::select::select4;
4
5use rs_matter::crypto::{Crypto, RngCore};
6use rs_matter::dm::clusters::gen_comm::CommPolicy;
7use rs_matter::dm::clusters::gen_diag::{GenDiag, NetifDiag};
8use rs_matter::dm::clusters::net_comm::{DummyNetworks, NetworkType};
9use rs_matter::dm::clusters::sw_diag::SwDiag;
10use rs_matter::dm::endpoints::{eth_sys_handler, EthSysHandler, ROOT_ENDPOINT_ID};
11use rs_matter::dm::networks::wireless::NoopWirelessNetCtl;
12use rs_matter::dm::networks::NetChangeNotif;
13use rs_matter::dm::{ChainedHandler, DataModel, Endpoint, EpClMatcher};
14use rs_matter::error::Error;
15use rs_matter::pairing::DiscoveryCapabilities;
16use rs_matter::persist::{KvBlobStore, KvBlobStoreAccess};
17use rs_matter::root_endpoint;
18use rs_matter::transport::network::NoNetwork;
19use rs_matter::utils::init::{init, init_from_closure, Init};
20use rs_matter::utils::select::Coalesce;
21
22use crate::mdns::Mdns;
23use crate::nal::NetStack;
24use crate::network::{Embedding, Network};
25use crate::private::Sealed;
26use crate::{pin_alloc, DummyAttrNotifier, MatterStack, UserTask};
27
28pub struct Eth<E = ()> {
39 embedding: E,
40}
41
42impl<E> Sealed for Eth<E> {}
43
44impl<E> Network for Eth<E>
45where
46 E: Embedding,
47{
48 const INIT: Self = Self { embedding: E::INIT };
49
50 type Embedding<'a>
51 = E
52 where
53 E: 'a;
54
55 type Networks = DummyNetworks;
57
58 const NETWORKS: Self::Networks = DummyNetworks;
59
60 fn init() -> impl Init<Self> {
61 init!(Self {
62 embedding <- E::init(),
63 })
64 }
65
66 fn init_networks() -> impl Init<Self::Networks> {
67 unsafe {
68 init_from_closure(|slot: *mut DummyNetworks| {
69 slot.write(DummyNetworks);
70 Ok(())
71 })
72 }
73 }
74
75 fn discovery_capabilities(&self) -> DiscoveryCapabilities {
76 DiscoveryCapabilities::IP
77 }
78
79 fn embedding(&self) -> &Self::Embedding<'_> {
80 &self.embedding
81 }
82}
83
84pub type EthMatterStack<'a, const B: usize, E = ()> = MatterStack<'a, B, Eth<E>>;
86
87pub trait EthernetTask {
90 async fn run<S, N, M>(&mut self, net_stack: S, netif: N, mdns: M) -> Result<(), Error>
92 where
93 S: NetStack,
94 N: NetifDiag + NetChangeNotif,
95 M: Mdns;
96}
97
98impl<T> EthernetTask for &mut T
99where
100 T: EthernetTask,
101{
102 fn run<S, N, M>(
103 &mut self,
104 net_stack: S,
105 netif: N,
106 mdns: M,
107 ) -> impl Future<Output = Result<(), Error>>
108 where
109 S: NetStack,
110 N: NetifDiag + NetChangeNotif,
111 M: Mdns,
112 {
113 (*self).run(net_stack, netif, mdns)
114 }
115}
116
117pub trait Ethernet {
119 async fn run<T>(&mut self, task: T) -> Result<(), Error>
121 where
122 T: EthernetTask;
123}
124
125impl<T> Ethernet for &mut T
126where
127 T: Ethernet,
128{
129 fn run<A>(&mut self, task: A) -> impl Future<Output = Result<(), Error>>
130 where
131 A: EthernetTask,
132 {
133 (*self).run(task)
134 }
135}
136
137pub struct PreexistingEthernet<S, N, M> {
140 stack: S,
141 netif: N,
142 mdns: M,
143}
144
145impl<S, N, M> PreexistingEthernet<S, N, M> {
146 pub const fn new(stack: S, netif: N, mdns: M) -> Self {
148 Self { stack, netif, mdns }
149 }
150}
151
152impl<S, N, M> Ethernet for PreexistingEthernet<S, N, M>
153where
154 S: NetStack,
155 N: NetifDiag + NetChangeNotif,
156 M: Mdns,
157{
158 async fn run<T>(&mut self, mut task: T) -> Result<(), Error>
159 where
160 T: EthernetTask,
161 {
162 task.run(&self.stack, &self.netif, &mut self.mdns).await
163 }
164}
165
166impl<const B: usize, E> MatterStack<'_, B, Eth<E>>
168where
169 E: Embedding,
170{
171 pub const fn root_endpoint() -> Endpoint<'static> {
174 const ENDPOINT: Endpoint<'static> = root_endpoint!(eth);
175
176 ENDPOINT
177 }
178
179 fn root_handler<'a>(
182 &self,
183 comm_policy: &'a dyn CommPolicy,
184 gen_diag: &'a dyn GenDiag,
185 netif_diag: &'a dyn NetifDiag,
186 sw_diag: &'a dyn SwDiag,
187 rand: impl RngCore + Copy,
188 ) -> EthSysHandler<'a> {
189 eth_sys_handler(comm_policy, gen_diag, netif_diag, sw_diag, rand)
190 }
191
192 pub async fn reset<C, H, S>(&mut self, crypto: C, handler: H, store: S) -> Result<(), Error>
198 where
199 C: Crypto,
200 H: DataModel,
201 S: KvBlobStore,
202 {
203 let kv = self.matter.kv(store);
204
205 self.matter.factory_reset(&kv)?;
206
207 self.im(
211 crypto,
212 handler,
213 &kv,
214 NoopWirelessNetCtl::new(NetworkType::Ethernet),
215 )
216 .factory_reset()
217 .await
218 }
219
220 pub async fn startup<C, S>(&mut self, crypto: C, store: S) -> Result<(), Error>
231 where
232 C: Crypto,
233 S: KvBlobStore,
234 {
235 let kv = self.matter.kv(store);
236
237 self.matter.startup(&kv)?;
238
239 if !self.matter().has_fabrics() {
240 info!("Device is not commissioned yet, opening commissioning window...");
241
242 self.open_basic_comm_window(crypto, &DummyAttrNotifier)?;
243 } else {
244 info!("Device is already commissioned");
245 }
246
247 Ok(())
248 }
249
250 #[allow(clippy::too_many_arguments)]
261 pub fn run_preex<'t, U, N, M, C, H, K, X>(
262 &'t self,
263 net_stack: U,
264 netif: N,
265 mdns: M,
266 crypto: C,
267 handler: H,
268 kv: K,
269 user: X,
270 ) -> impl Future<Output = Result<(), Error>> + 't
271 where
272 U: NetStack + 't,
273 N: NetifDiag + NetChangeNotif + 't,
274 M: Mdns + 't,
275 C: Crypto + 't,
276 H: DataModel + 't,
277 K: KvBlobStoreAccess + 't,
278 X: UserTask + 't,
279 {
280 self.run(
281 PreexistingEthernet::new(net_stack, netif, mdns),
282 crypto,
283 handler,
284 kv,
285 user,
286 )
287 }
288
289 pub async fn run<N, C, H, K, X>(
298 &self,
299 mut ethernet: N,
300 crypto: C,
301 handler: H,
302 kv: K,
303 user: X,
304 ) -> Result<(), Error>
305 where
306 N: Ethernet,
307 C: Crypto,
308 H: DataModel,
309 K: KvBlobStoreAccess,
310 X: UserTask,
311 {
312 let _lock = self.run_lock.lock().await;
313
314 info!("Matter Stack memory: {}b", core::mem::size_of_val(self));
315
316 let _defer = scopeguard::guard((), |_| unsafe {
319 self.bump.reset();
320 });
321
322 self.matter().reset_transport()?;
323
324 let net_task = pin_alloc!(
325 self.bump,
326 self.run_ethernet(&mut ethernet, crypto, handler, &kv, user)
327 );
328
329 net_task.await
330 }
331
332 fn run_ethernet<'t, N, C, H, K, X>(
333 &'t self,
334 ethernet: &'t mut N,
335 crypto: C,
336 handler: H,
337 kv: K,
338 user: X,
339 ) -> impl Future<Output = Result<(), Error>> + 't
340 where
341 N: Ethernet + 't,
342 C: Crypto + 't,
343 H: DataModel + 't,
344 K: KvBlobStoreAccess + 't,
345 X: UserTask + 't,
346 {
347 Ethernet::run(
348 ethernet,
349 MatterStackEthernetTask {
350 stack: self,
351 crypto,
352 handler,
353 kv,
354 user_task: user,
355 },
356 )
357 }
358}
359
360struct MatterStackEthernetTask<'a, const B: usize, E, C, H, K, X>
361where
362 E: Embedding,
363 C: Crypto,
364 H: DataModel,
365 K: KvBlobStoreAccess,
366 X: UserTask,
367{
368 stack: &'a MatterStack<'a, B, Eth<E>>,
369 crypto: C,
370 handler: H,
371 kv: K,
372 user_task: X,
373}
374
375impl<const B: usize, E, C, H, K, X> EthernetTask for MatterStackEthernetTask<'_, B, E, C, H, K, X>
376where
377 E: Embedding,
378 C: Crypto,
379 H: DataModel,
380 K: KvBlobStoreAccess,
381 X: UserTask,
382{
383 async fn run<N, I, M>(&mut self, net_stack: N, netif: I, mut mdns: M) -> Result<(), Error>
384 where
385 N: NetStack,
386 I: NetifDiag + NetChangeNotif,
387 M: Mdns,
388 {
389 info!("Ethernet driver started");
390
391 let sys = self
397 .stack
398 .root_handler(&false, &(), &netif, &(), self.crypto.weak_rand()?);
399 let combined = ChainedHandler::new(
400 EpClMatcher::new(Some(ROOT_ENDPOINT_ID), None),
401 sys,
402 &self.handler,
403 );
404 let im = self.stack.im(
407 &self.crypto,
408 (&self.handler, combined),
409 &self.kv,
410 NoopWirelessNetCtl::new(NetworkType::Ethernet),
411 );
412
413 let mut net_task = pin_alloc!(
414 self.stack.bump,
415 self.stack.run_oper_net(
416 &self.crypto,
417 &net_stack,
418 0, core::future::pending(),
420 Option::<(NoNetwork, NoNetwork)>::None,
421 )
422 );
423
424 let mut mdns_task = pin_alloc!(
425 self.stack.bump,
426 self.stack
427 .run_oper_netif_mdns(&self.crypto, &net_stack, &netif, &mut mdns)
428 );
429
430 let mut im_task = pin_alloc!(self.stack.bump, self.stack.run_im_with_bump(&im));
431
432 let mut user_task = pin_alloc!(self.stack.bump, self.user_task.run(&net_stack, &netif));
433
434 select4(&mut net_task, &mut mdns_task, &mut im_task, &mut user_task)
435 .coalesce()
436 .await
437 }
438}