1use core::fmt::{self, Display};
19use core::future::Future;
20use core::num::NonZeroU8;
21use core::ops::{Deref, DerefMut};
22use core::pin::pin;
23
24use domain::base::name::ToLabelIter;
25
26use embassy_futures::select::{select, select3, select4, Either};
27use embassy_time::{Duration, Timer};
28
29use rand_core::RngCore;
30
31use crate::crypto::Crypto;
32use crate::dm::clusters::basic_info::BasicInfoConfig;
33use crate::dm::NodeId;
34use crate::error::{Error, ErrorCode};
35use crate::fabric::{MAX_FABRICS, MAX_GROUPS_PER_FABRIC};
36use crate::fmt::Bytes;
37use crate::sc::case::CaseInitiator;
38use crate::sc::pase::PaseInitiator;
39use crate::sc::{
40 sc_write, OpCode, SCStatusCodes, SessionParameters, StatusReport, PROTO_ID_SECURE_CHANNEL,
41};
42use crate::tlv::TLVElement;
43use crate::transport::network::mdns::{
44 commissionable_instance_id, score_ip_address, BrowseExclude, CommissionableFilter,
45 MdnsBrowseState, MdnsRemoteService, MdnsResolveState, ResolvedNode,
46};
47use crate::transport::network::{MatterRemoteService, NetworkMulticast};
48use crate::utils::init::{init, Init};
49use crate::utils::ipv6::compute_group_multicast_addr;
50use crate::utils::select::Coalesce;
51use crate::utils::storage::Vec;
52use crate::utils::storage::{pooled::Buffers, ParseBuf, WriteBuf};
53use crate::utils::sync::{IfMutex, IfMutexGuard, Notification, Signal};
54use crate::{Matter, MATTER_PORT};
55
56use exchange::{Exchange, ExchangeId, ExchangeState, MessageMeta, ResponderState, Role};
57use network::{Address, IpAddr, Ipv6Addr, NetworkReceive, NetworkSend, SocketAddr, SocketAddrV6};
58use packet::PacketHdr;
59use proto_hdr::ProtoHdr;
60use session::{Session, Sessions};
61
62mod dedup;
63
64pub mod exchange;
65pub mod mrp;
66pub mod network;
67pub mod packet;
68pub mod plain_hdr;
69pub mod proto_hdr;
70pub mod session;
71
72pub const MATTER_SOCKET_BIND_ADDR: SocketAddr =
73 SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, MATTER_PORT, 0, 0));
74
75const MAX_GROUP_ADDRS: usize = MAX_FABRICS * MAX_GROUPS_PER_FABRIC;
76
77const ACCEPT_TIMEOUT_MS: u64 = 1000;
78
79#[cfg(feature = "large-buffers")]
80pub(crate) const MAX_RX_BUF_SIZE: usize = network::MAX_RX_LARGE_PACKET_SIZE;
81#[cfg(feature = "large-buffers")]
82pub(crate) const MAX_TX_BUF_SIZE: usize = network::MAX_TX_LARGE_PACKET_SIZE;
83
84#[cfg(not(feature = "large-buffers"))]
85pub(crate) const MAX_RX_BUF_SIZE: usize = network::MAX_RX_PACKET_SIZE;
86#[cfg(not(feature = "large-buffers"))]
87pub(crate) const MAX_TX_BUF_SIZE: usize = network::MAX_TX_PACKET_SIZE;
88
89pub const MAX_RX_PAYLOAD_SIZE: usize =
92 MAX_RX_BUF_SIZE - PacketHdr::HDR_RESERVE - PacketHdr::TAIL_RESERVE;
93
94pub const MAX_TX_PAYLOAD_SIZE: usize =
97 MAX_TX_BUF_SIZE - PacketHdr::HDR_RESERVE - PacketHdr::TAIL_RESERVE;
98
99pub struct Transport {
101 rx: IfMutex<Packet<MAX_RX_BUF_SIZE>>,
104 tx: IfMutex<Packet<MAX_TX_BUF_SIZE>>,
107 group_addrs: IfMutex<Vec<Ipv6Addr, MAX_GROUP_ADDRS>>,
109 exchange_dropped: Notification,
111 mdns_changed: Notification,
113 mdns_resolve: Signal<MdnsResolveState>,
116 mdns_browse: Signal<MdnsBrowseState>,
119 session_removed: Notification,
121 groups_modified: Notification,
123 device_sai: Option<u32>,
125 device_sii: Option<u32>,
127}
128
129impl Transport {
130 #[inline(always)]
132 pub(crate) const fn new(dev_det: &BasicInfoConfig<'_>) -> Self {
133 Self {
134 rx: IfMutex::new(Packet::new()),
135 tx: IfMutex::new(Packet::new()),
136 group_addrs: IfMutex::new(Vec::new()),
137 exchange_dropped: Notification::new(),
138 mdns_changed: Notification::new(),
139 mdns_resolve: Signal::new(MdnsResolveState::Idle),
140 mdns_browse: Signal::new(MdnsBrowseState::Idle),
141 session_removed: Notification::new(),
142 groups_modified: Notification::new(),
143 device_sai: dev_det.sai,
144 device_sii: dev_det.sii,
145 }
146 }
147
148 pub(crate) fn init<'m>(dev_det: &'m BasicInfoConfig<'m>) -> impl Init<Self> + 'm {
150 init!(Self {
151 rx <- IfMutex::init(Packet::init()),
152 tx <- IfMutex::init(Packet::init()),
153 group_addrs <- IfMutex::init(Vec::new()),
154 exchange_dropped: Notification::new(),
155 mdns_changed: Notification::new(),
156 mdns_resolve: Signal::new(MdnsResolveState::Idle),
157 mdns_browse: Signal::new(MdnsBrowseState::Idle),
158 session_removed: Notification::new(),
159 groups_modified: Notification::new(),
160 device_sai: dev_det.sai,
161 device_sii: dev_det.sii,
162 })
163 }
164
165 pub fn reset(&self) -> Result<(), Error> {
168 self.rx
169 .try_lock()
170 .map_err(|_| ErrorCode::InvalidState)?
171 .buf
172 .clear();
173 self.tx
174 .try_lock()
175 .map_err(|_| ErrorCode::InvalidState)?
176 .buf
177 .clear();
178
179 Ok(())
180 }
181
182 pub fn rx_buffer(&self) -> PacketBufferExternalAccess<'_, MAX_RX_BUF_SIZE> {
187 PacketBufferExternalAccess(&self.rx)
188 }
189
190 pub fn tx_buffer(&self) -> PacketBufferExternalAccess<'_, MAX_TX_BUF_SIZE> {
195 PacketBufferExternalAccess(&self.tx)
196 }
197
198 pub(crate) fn notify_mdns_changed(&self) {
200 self.mdns_changed.notify();
201 }
202
203 pub fn wait_mdns(&self) -> impl Future<Output = ()> + '_ {
208 self.mdns_changed.wait()
209 }
210
211 pub(crate) fn notify_groups_changed(&self) {
214 self.groups_modified.notify();
215 }
216
217 fn wait_groups_changed(&self) -> impl Future<Output = ()> + '_ {
219 self.groups_modified.wait()
220 }
221
222 pub(crate) fn notify_session_removed(&self) {
224 self.session_removed.notify();
225 }
226
227 pub(crate) fn wait_session_removed(&self) -> impl Future<Output = ()> + '_ {
229 self.session_removed.wait()
230 }
231
232 async fn resolve(
246 &self,
247 service: MatterRemoteService,
248 timeout_ms: u32,
249 ) -> Result<ResolvedNode, Error> {
250 self.mdns_resolve
252 .wait(|state| {
253 if matches!(state, MdnsResolveState::Idle) {
254 *state = MdnsResolveState::Requested {
255 service: service.clone(),
256 };
257 Some(())
258 } else {
259 None
260 }
261 })
262 .await;
263
264 let mut guard = MdnsResolveGuard {
266 signal: &self.mdns_resolve,
267 armed: true,
268 };
269
270 let mut wait = pin!(self.mdns_resolve.wait(|state| match state {
272 MdnsResolveState::Resolved {
273 ip,
274 port,
275 scope_id,
276 sii,
277 sai,
278 sat,
279 } => {
280 let node = ResolvedNode {
281 addr: Self::scoped_socket_addr(*ip, *port, *scope_id),
282 sii: *sii,
283 sai: *sai,
284 sat: *sat,
285 };
286 *state = MdnsResolveState::Idle;
287 Some(node)
288 }
289 _ => None,
290 }));
291
292 let mut timer = pin!(Timer::after(Duration::from_millis(timeout_ms as u64)));
293
294 match select(&mut wait, &mut timer).await {
295 Either::First(node) => {
296 guard.armed = false;
298
299 Ok(node)
300 }
301 Either::Second(_) => Err(ErrorCode::NotFound.into()),
302 }
303 }
304
305 pub async fn wait_mdns_resolve_request(&self) -> MatterRemoteService {
313 self.mdns_resolve
314 .wait(|state| match state {
315 MdnsResolveState::Requested { service } => {
316 let service = service.clone();
317 *state = MdnsResolveState::InFlight {
318 service: service.clone(),
319 };
320 Some(service)
321 }
322 _ => None,
323 })
324 .await
325 }
326
327 #[allow(dead_code)]
332 pub fn mdns_resolve_in_flight(&self) -> bool {
333 self.mdns_resolve
334 .modify(|state| (false, matches!(state, MdnsResolveState::InFlight { .. })))
335 }
336
337 pub fn try_deposit_mdns_resolve<'a, I, A, T>(&self, answer: &MdnsRemoteService<I, A, T>)
347 where
348 I: ToLabelIter,
349 A: Iterator<Item = IpAddr> + Clone,
350 T: Iterator<Item = (&'a str, &'a str)> + Clone,
351 {
352 let Some(ip) = answer.addrs.clone().max_by_key(score_ip_address) else {
353 return;
354 };
355 let Some(port) = answer.port else {
356 return;
357 };
358 let scope_id = answer.scope_id;
359
360 let (sii, sai, sat) = answer.session_params();
361
362 self.mdns_resolve.modify(|state| match state {
363 MdnsResolveState::InFlight { service }
364 if service.matches_instance(&answer.instance_name) =>
365 {
366 *state = MdnsResolveState::Resolved {
367 ip,
368 port,
369 scope_id,
370 sii,
371 sai,
372 sat,
373 };
374 (true, ())
375 }
376 MdnsResolveState::Resolved {
387 ip: cur_ip,
388 sii: cur_sii,
389 sai: cur_sai,
390 sat: cur_sat,
391 ..
392 } if score_ip_address(&ip) > score_ip_address(cur_ip) => {
393 *state = MdnsResolveState::Resolved {
394 ip,
395 port,
396 scope_id,
397 sii: sii.or(*cur_sii),
398 sai: sai.or(*cur_sai),
399 sat: sat.or(*cur_sat),
400 };
401 (true, ())
402 }
403 _ => (false, ()),
404 });
405 }
406
407 pub async fn browse_commissionable(
434 &self,
435 filter: &CommissionableFilter,
436 exclude: &[u64],
437 timeout_ms: u32,
438 ) -> Result<(Address, u64), Error> {
439 let mut exclude_vec = BrowseExclude::new();
440 exclude_vec
441 .extend_from_slice(exclude)
442 .map_err(|_| ErrorCode::ResourceExhausted)?;
443
444 self.mdns_browse
446 .wait(|state| {
447 if matches!(state, MdnsBrowseState::Idle) {
448 *state = MdnsBrowseState::Requested {
449 filter: filter.clone(),
450 exclude: exclude_vec.clone(),
451 };
452 Some(())
453 } else {
454 None
455 }
456 })
457 .await;
458
459 let mut guard = MdnsBrowseGuard {
461 signal: &self.mdns_browse,
462 armed: true,
463 };
464
465 let mut wait = pin!(self.mdns_browse.wait(|state| match state {
467 MdnsBrowseState::Found {
468 ip,
469 port,
470 scope_id,
471 id,
472 } => {
473 let found = (
474 Address::Udp(Self::scoped_socket_addr(*ip, *port, *scope_id)),
475 *id,
476 );
477 *state = MdnsBrowseState::Idle;
478 Some(found)
479 }
480 _ => None,
481 }));
482
483 let mut timer = pin!(Timer::after(Duration::from_millis(timeout_ms as u64)));
484
485 match select(&mut wait, &mut timer).await {
486 Either::First(found) => {
487 guard.armed = false;
488
489 Ok(found)
490 }
491 Either::Second(_) => Err(ErrorCode::NotFound.into()),
492 }
493 }
494
495 pub async fn wait_mdns_browse_request(&self) -> CommissionableFilter {
504 self.mdns_browse
505 .wait(|state| match state {
506 MdnsBrowseState::Requested { filter, exclude } => {
507 let filter = filter.clone();
508 *state = MdnsBrowseState::InFlight {
509 filter: filter.clone(),
510 exclude: core::mem::take(exclude),
511 };
512
513 Some(filter)
514 }
515 _ => None,
516 })
517 .await
518 }
519
520 #[allow(dead_code)]
525 pub fn mdns_browse_in_flight(&self) -> bool {
526 self.mdns_browse
527 .modify(|state| (false, matches!(state, MdnsBrowseState::InFlight { .. })))
528 }
529
530 pub fn try_deposit_mdns_browse<'a, I, A, T>(&self, answer: &MdnsRemoteService<I, A, T>)
539 where
540 I: ToLabelIter,
541 A: Iterator<Item = IpAddr> + Clone,
542 T: Iterator<Item = (&'a str, &'a str)> + Clone,
543 {
544 let Some(id) = commissionable_instance_id(&answer.instance_name) else {
545 return;
546 };
547 let Some(ip) = answer.addrs.clone().max_by_key(score_ip_address) else {
548 return;
549 };
550 let Some(port) = answer.port else {
551 return;
552 };
553 let scope_id = answer.scope_id;
554
555 self.mdns_browse.modify(|state| match state {
556 MdnsBrowseState::InFlight { filter, exclude }
557 if !exclude.contains(&id) && filter.matches(answer) =>
558 {
559 *state = MdnsBrowseState::Found {
560 ip,
561 port,
562 scope_id,
563 id,
564 };
565 (true, ())
566 }
567 MdnsBrowseState::Found {
573 ip: cur_ip,
574 id: cur_id,
575 ..
576 } if *cur_id == id && score_ip_address(&ip) > score_ip_address(cur_ip) => {
577 *state = MdnsBrowseState::Found {
578 ip,
579 port,
580 scope_id,
581 id,
582 };
583 (true, ())
584 }
585 _ => (false, ()),
586 });
587 }
588
589 pub(crate) async fn accept_if<'a, F>(
590 &self,
591 matter: &'a Matter<'a>,
592 mut f: F,
593 ) -> Result<Exchange<'a>, Error>
594 where
595 F: FnMut(&Session, &ExchangeState, &Packet<MAX_RX_BUF_SIZE>) -> bool,
596 {
597 let exchange = self
598 .rx
599 .with(|packet| {
600 matter.with_state(|state| {
601 let session = state
602 .sessions
603 .get_for_rx(&packet.peer, &packet.header.plain)?;
604 let exch_index = session.get_exch_for_rx(&packet.header.proto)?;
605
606 let matches = {
607 let exch = unwrap!(session.exchanges[exch_index].as_ref());
610
611 matches!(exch.role, Role::Responder(ResponderState::AcceptPending))
612 && f(session, exch, packet)
613 };
614
615 if !matches {
616 return None;
617 }
618
619 let exch = unwrap!(session.exchanges[exch_index].as_mut());
622
623 exch.role = Role::Responder(ResponderState::Owned);
624
625 let id = ExchangeId::new(session.id, exch_index);
626
627 debug!("Exchange {}: Accepted", id.display(session));
628
629 let exchange = Exchange::new(id, matter);
630
631 Some(exchange)
632 })
633 })
634 .await;
635
636 Ok(exchange)
637 }
638
639 const RESOLVE_TIMEOUT_MS: u32 = 5_000;
643
644 pub(crate) async fn initiate<'a, C: Crypto>(
654 &self,
655 matter: &'a Matter<'a>,
656 crypto: C,
657 fabric_idx: NonZeroU8,
658 peer_node_id: NodeId,
659 ) -> Result<Exchange<'a>, Error> {
660 let existing = matter.with_state(|state| {
662 Ok::<_, Error>(
663 state
664 .sessions
665 .get_for_node(fabric_idx, peer_node_id)
666 .map(|s| s.id),
667 )
668 })?;
669
670 if let Some(session_id) = existing {
671 return self.initiate_for_session(matter, session_id);
672 }
673
674 let compressed_fabric_id = matter.with_state(|state| {
676 Ok::<_, Error>(state.fabrics.fabric(fabric_idx)?.compressed_fabric_id())
677 })?;
678
679 let service = MatterRemoteService::Operational {
680 compressed_fabric_id,
681 node_id: peer_node_id,
682 };
683
684 let resolved = self.resolve(service, Self::RESOLVE_TIMEOUT_MS).await?;
685
686 {
690 let mut exchange = self
691 .initiate_plaintext(matter, &crypto, Address::Udp(resolved.addr))
692 .await?;
693
694 CaseInitiator::initiate(&mut exchange, &crypto, fabric_idx, peer_node_id).await?;
695 }
696
697 let params = SessionParameters {
701 sii: resolved.sii,
702 sai: resolved.sai,
703 sat: resolved.sat,
704 ..Default::default()
705 };
706
707 let session_id = matter.with_state(|state| {
708 let session = state
709 .sessions
710 .get_for_node(fabric_idx, peer_node_id)
711 .ok_or(ErrorCode::NoSession)?;
712
713 session.set_peer_session_params(¶ms);
714
715 Ok::<_, Error>(session.id)
716 })?;
717
718 self.initiate_for_session(matter, session_id)
719 }
720
721 pub(crate) async fn initiate_pase<'a, C: Crypto>(
736 &self,
737 matter: &'a Matter<'a>,
738 crypto: C,
739 peer_addr: Address,
740 passcode: u32,
741 ) -> Result<Exchange<'a>, Error> {
742 let existing = matter.with_state(|state| {
744 Ok::<_, Error>(state.sessions.get_pase_for_addr(&peer_addr).map(|s| s.id))
745 })?;
746
747 if let Some(session_id) = existing {
748 return self.initiate_for_session(matter, session_id);
749 }
750
751 {
753 let mut handshake = self.initiate_plaintext(matter, &crypto, peer_addr).await?;
754 PaseInitiator::initiate(&mut handshake, &crypto, passcode).await?;
755 }
758
759 let session_id = matter.with_state(|state| {
760 state
761 .sessions
762 .get_pase_for_addr(&peer_addr)
763 .map(|s| s.id)
764 .ok_or_else(|| Error::from(ErrorCode::NoSession))
765 })?;
766
767 self.initiate_for_session(matter, session_id)
768 }
769
770 pub(crate) fn initiate_for_session<'a>(
771 &self,
772 matter: &'a Matter<'a>,
773 session_id: u32,
774 ) -> Result<Exchange<'a>, Error> {
775 matter.with_state(|state| {
776 state
777 .sessions
778 .get(session_id)
779 .filter(|sess| !sess.is_expired())
781 .ok_or(ErrorCode::NoSession)?;
782
783 let exch_id = state.sessions.get_next_exch_id();
784
785 let session = unwrap!(state.sessions.get(session_id));
789
790 let exch_index = session
791 .add_exch(exch_id, Role::Initiator(Default::default()))
792 .ok_or(ErrorCode::NoSpaceExchanges)?;
793
794 let id = ExchangeId::new(session.id, exch_index);
795
796 debug!("Exchange {}: Initiated", id.display(session));
797
798 Ok(Exchange::new(id, matter))
799 })
800 }
801
802 async fn initiate_plaintext<'a, C: Crypto>(
809 &self,
810 matter: &'a Matter<'a>,
811 crypto: C,
812 peer_addr: Address,
813 ) -> Result<Exchange<'a>, Error> {
814 match self.try_initiate_plaintext(matter, &crypto, peer_addr) {
815 Ok(exchange) => Ok(exchange),
816 Err(e) if e.code() == ErrorCode::NoSpaceSessions => {
817 matter
818 .transport_runner(&crypto)
819 .evict_some_session()
820 .await?;
821 self.try_initiate_plaintext(matter, &crypto, peer_addr)
822 }
823 Err(e) => Err(e),
824 }
825 }
826
827 fn try_initiate_plaintext<'a, C: Crypto>(
835 &self,
836 matter: &'a Matter<'a>,
837 crypto: C,
838 peer_addr: Address,
839 ) -> Result<Exchange<'a>, Error> {
840 let session_id = self.create_plaintext_session(matter, crypto, peer_addr)?;
841
842 self.initiate_for_session(matter, session_id)
843 }
844
845 fn create_plaintext_session<C: Crypto>(
853 &self,
854 matter: &Matter<'_>,
855 crypto: C,
856 peer_addr: Address,
857 ) -> Result<u32, Error> {
858 matter.with_state(|state| {
859 let mut rand = crypto.rand()?;
860
861 let session =
862 state
863 .sessions
864 .add(rand.next_u32(), false, peer_addr, None, matter.dev_det())?;
865
866 const MAX_OPERATIONAL_NODE_ID: u64 = 0xFFFF_FFEF_FFFF_FFFF;
871 let mut ephemeral_id = rand.next_u64();
872 while ephemeral_id == 0 || ephemeral_id > MAX_OPERATIONAL_NODE_ID {
873 ephemeral_id = rand.next_u64();
874 }
875 session.set_local_nodeid(ephemeral_id);
876
877 let session_id = session.id;
878
879 debug!(
880 "Unsecured session {} created for peer {}",
881 session_id, peer_addr
882 );
883
884 Ok(session_id)
885 })
886 }
887
888 pub(crate) async fn get_if_rx<F>(&self, f: F) -> PacketAccess<'_, MAX_RX_BUF_SIZE>
889 where
890 F: Fn(&Packet<MAX_RX_BUF_SIZE>) -> bool,
891 {
892 Self::get_if(&self.rx, f).await
893 }
894
895 pub(crate) async fn get_if_tx<F>(&self, f: F) -> PacketAccess<'_, MAX_TX_BUF_SIZE>
896 where
897 F: Fn(&Packet<MAX_TX_BUF_SIZE>) -> bool,
898 {
899 Self::get_if(&self.tx, f).await
900 }
901
902 async fn get_if<'b, F, const N: usize>(
903 packet_mutex: &'b IfMutex<Packet<N>>,
904 f: F,
905 ) -> PacketAccess<'b, N>
906 where
907 F: Fn(&Packet<N>) -> bool,
908 {
909 PacketAccess(packet_mutex.lock_if(f).await, false)
910 }
911
912 fn scoped_socket_addr(ip: IpAddr, port: u16, scope_id: u32) -> SocketAddr {
920 match ip {
921 IpAddr::V6(v6) if v6.is_unicast_link_local() => {
922 SocketAddr::V6(SocketAddrV6::new(v6, port, 0, scope_id))
923 }
924 _ => SocketAddr::new(ip, port),
925 }
926 }
927}
928
929struct MdnsResolveGuard<'a> {
934 signal: &'a Signal<MdnsResolveState>,
935 armed: bool,
936}
937
938impl Drop for MdnsResolveGuard<'_> {
939 fn drop(&mut self) {
940 if self.armed {
941 self.signal.modify(|state| {
942 if matches!(state, MdnsResolveState::Idle) {
943 (false, ())
944 } else {
945 *state = MdnsResolveState::Idle;
946 (true, ())
947 }
948 });
949 }
950 }
951}
952
953struct MdnsBrowseGuard<'a> {
956 signal: &'a Signal<MdnsBrowseState>,
957 armed: bool,
958}
959
960impl Drop for MdnsBrowseGuard<'_> {
961 fn drop(&mut self) {
962 if self.armed {
963 self.signal.modify(|state| {
964 if matches!(state, MdnsBrowseState::Idle) {
965 (false, ())
966 } else {
967 *state = MdnsBrowseState::Idle;
968 (true, ())
969 }
970 });
971 }
972 }
973}
974
975pub struct TransportRunner<'a, C> {
981 matter: &'a Matter<'a>,
982 crypto: C,
983}
984
985impl<'a, C: Crypto> TransportRunner<'a, C> {
986 pub const fn new(matter: &'a Matter<'a>, crypto: C) -> Self {
988 Self { matter, crypto }
989 }
990
991 pub async fn run<S, R, M>(&mut self, send: S, recv: R, multicast: M) -> Result<(), Error>
993 where
994 S: NetworkSend,
995 R: NetworkReceive,
996 M: NetworkMulticast,
997 {
998 info!("Running Matter transport");
999
1000 debug!("APP STATUS: Starting event loop");
1003
1004 let mut joined = self.transport().group_addrs.lock().await;
1005
1006 let send = IfMutex::new(send);
1007
1008 let mut rx = pin!(self.process_rx(recv, &send));
1009 let mut tx = pin!(self.process_tx(&send));
1010 let mut orphaned = pin!(self.process_orphaned());
1011 let mut groups = pin!(self.process_groups(multicast, &mut joined));
1012
1013 select4(&mut rx, &mut tx, &mut orphaned, &mut groups)
1014 .coalesce()
1015 .await
1016 }
1017
1018 async fn process_groups<M>(
1019 &self,
1020 mut multicast: M,
1021 joined: &mut Vec<Ipv6Addr, MAX_GROUP_ADDRS>,
1022 ) -> Result<(), Error>
1023 where
1024 M: NetworkMulticast,
1025 {
1026 joined.clear();
1027
1028 loop {
1029 let addr_op = self.matter.with_state(|state| {
1030 let group_addrs = || {
1031 state.fabrics.iter().flat_map(|fabric| {
1032 fabric.groups().iter().map(|group| {
1033 compute_group_multicast_addr(fabric.fabric_id(), group.group_id)
1034 })
1035 })
1036 };
1037
1038 if let Some(new_addr) = group_addrs().find(|addr| !joined.contains(addr)) {
1039 Some((new_addr, true))
1040 } else {
1041 joined
1042 .iter()
1043 .find(|addr| !group_addrs().any(|a| a == **addr))
1044 .map(|&removed_addr| (removed_addr, false))
1045 }
1046 });
1047
1048 match addr_op {
1049 Some((new_addr, true)) => {
1050 match multicast.join(new_addr.into()).await {
1051 Ok(_) => {
1052 debug!("Joined multicast group: {}", new_addr);
1053 unwrap!(joined.push(new_addr));
1056 }
1057 Err(e) => error!(
1058 "Joining multicast group {} failed with error: {}",
1059 new_addr, e
1060 ),
1061 }
1062 }
1063 Some((removed_addr, false)) => match multicast.leave(removed_addr.into()).await {
1064 Ok(_) => {
1065 debug!("Left multicast group: {}", removed_addr);
1066 let index = joined
1067 .iter()
1068 .position(|&addr| addr == removed_addr)
1069 .unwrap();
1070 joined.swap_remove(index);
1071 }
1072 Err(e) => error!(
1073 "Leaving multicast group {} failed with error: {}",
1074 removed_addr, e
1075 ),
1076 },
1077 None => {
1078 self.transport().wait_groups_changed().await;
1079 }
1080 }
1081 }
1082 }
1083
1084 async fn process_tx<S>(&self, send: &IfMutex<S>) -> Result<(), Error>
1085 where
1086 S: NetworkSend,
1087 {
1088 loop {
1089 trace!("Waiting for outgoing packet");
1090
1091 let mut tx = self
1092 .matter
1093 .transport
1094 .get_if_tx(|packet| !packet.buf.is_empty())
1095 .await;
1096 tx.clear_on_drop(true);
1097
1098 if let TxPayloadState::NotEncoded { session_id } = tx.tx_info.payload_state {
1099 let encoded = self.matter.with_state(|state| {
1100 if let Some(session) = state.sessions.get_for_tx(session_id) {
1101 self.encode_packet(&mut tx, Some(session))?;
1102
1103 Ok::<_, Error>(true)
1104 } else {
1105 error!(
1106 "TX packet has session ID {}, but no such session exists, dropping",
1107 session_id
1108 );
1109
1110 Ok(false)
1111 }
1112 })?;
1113
1114 if !encoded {
1115 continue;
1116 }
1117 }
1118
1119 Self::netw_send(send, tx.peer, &tx.buf[tx.payload_start..], false).await?;
1120 }
1121 }
1122
1123 async fn process_rx<R, S>(&self, mut recv: R, send: &IfMutex<S>) -> Result<(), Error>
1124 where
1125 R: NetworkReceive,
1126 S: NetworkSend,
1127 {
1128 loop {
1129 trace!("Waiting for incoming packet");
1130
1131 recv.wait_available().await?;
1132
1133 let mut rx = self
1134 .matter
1135 .transport
1136 .get_if_rx(|packet| packet.buf.is_empty())
1137 .await;
1138 rx.clear_on_drop(true); unwrap!(rx.buf.resize_default(MAX_RX_BUF_SIZE));
1143
1144 let (len, peer) = Self::netw_recv(&mut recv, &mut rx.buf).await?;
1145
1146 rx.peer = peer;
1147 rx.buf.truncate(len);
1148 rx.payload_start = 0;
1149
1150 match self.handle_rx_packet(&mut rx, send).await {
1151 Ok(true) => {
1152 rx.clear_on_drop(false);
1154 }
1155 Ok(false) => {
1156 }
1158 Err(e) => {
1159 error!("UNEXPECTED RX ERROR: {:?}", e);
1161 }
1162 }
1163 }
1164 }
1165
1166 async fn process_orphaned(&self) -> Result<(), Error> {
1167 let mut rx_accept_timeout = pin!(self.process_accept_timeout_rx());
1168 let mut rx_orphaned = pin!(self.process_orphaned_rx());
1169 let mut exch_dropped = pin!(self.process_dropped_exchanges());
1170
1171 select3(&mut rx_accept_timeout, &mut rx_orphaned, &mut exch_dropped)
1172 .coalesce()
1173 .await
1174 }
1175
1176 async fn process_accept_timeout_rx(&self) -> Result<(), Error> {
1177 loop {
1178 trace!("Waiting for accept timeout");
1179
1180 let mut accept_timeout = pin!(self
1181 .matter
1182 .transport
1183 .rx
1184 .with(|packet| { self.handle_accept_timeout_rx_packet(packet).then_some(()) }));
1185
1186 let mut timer = pin!(Timer::after(embassy_time::Duration::from_millis(50)));
1187
1188 select(&mut accept_timeout, &mut timer).await;
1189 }
1190 }
1191
1192 async fn process_orphaned_rx(&self) -> Result<(), Error> {
1193 loop {
1194 trace!("Waiting for orphaned RX packets");
1195
1196 self.transport()
1197 .rx
1198 .with(|packet| self.handle_orphaned_rx_packet(packet).then_some(()))
1199 .await;
1200 }
1201 }
1202
1203 async fn process_dropped_exchanges(&self) -> Result<(), Error> {
1204 loop {
1205 trace!("Waiting for dropped exchanges");
1206
1207 let mut tx = self
1208 .matter
1209 .transport
1210 .get_if_tx(|packet| packet.buf.is_empty())
1211 .await;
1212 tx.clear_on_drop(true); let wait = match self.handle_dropped_exchange(&mut tx) {
1215 Ok(wait) => {
1216 tx.clear_on_drop(false);
1217 wait
1218 }
1219 Err(e) => {
1220 error!("UNEXPECTED RX ERROR: {:?}", e);
1221 false
1222 }
1223 };
1224
1225 drop(tx);
1226
1227 if wait {
1228 let mut timeout = pin!(Timer::after(embassy_time::Duration::from_millis(100)));
1229 let mut wait = pin!(self.transport().exchange_dropped.wait());
1230
1231 select(&mut timeout, &mut wait).await;
1232 }
1233 }
1234 }
1235
1236 async fn handle_rx_packet<const N: usize, S>(
1237 &self,
1238 packet: &mut Packet<N>,
1239 send: &IfMutex<S>,
1240 ) -> Result<bool, Error>
1241 where
1242 S: NetworkSend,
1243 {
1244 let result = self.decode_packet(packet);
1245 match result {
1246 Err(e) if matches!(e.code(), ErrorCode::Duplicate) => {
1247 if packet.header.plain.is_group_session() {
1248 debug!(
1250 "\n>>RCV {}\n => Duplicate group message, discarding",
1251 packet
1252 );
1253 } else if !packet.peer.is_reliable()
1254 && !MessageMeta::from(&packet.header.proto).is_standalone_ack()
1255 {
1256 debug!("\n>>RCV {}\n => Duplicate, sending ACK", packet);
1257
1258 self.matter.with_state(|state| {
1259 let session = unwrap!(state
1265 .sessions
1266 .get_for_rx(&packet.peer, &packet.header.plain));
1267
1268 let ack = packet.header.plain.ctr;
1269
1270 packet.header.proto.toggle_initiator();
1271 packet.header.proto.set_ack(Some(ack));
1272
1273 self.write_packet(packet, Some(session), None, true, |_| {
1274 Ok(Some(OpCode::MRPStandAloneAck.into()))
1275 })
1276 })?;
1277
1278 Self::netw_send(send, packet.peer, &packet.buf[packet.payload_start..], true)
1279 .await?;
1280 } else {
1281 debug!("\n>>RCV {}\n => Duplicate, discarding", packet);
1282 }
1283 }
1284 Err(e) if matches!(e.code(), ErrorCode::NoSpaceSessions) => {
1285 if !packet.header.plain.is_encrypted()
1286 && MessageMeta::from(&packet.header.proto).is_new_session()
1287 {
1288 warn!(
1289 "\n>>RCV {}\n => No space for a new unencrypted session, sending Busy",
1290 packet
1291 );
1292
1293 let ack = packet.header.plain.ctr;
1294
1295 packet.header.proto.toggle_initiator();
1296 packet.header.proto.set_ack(Some(ack));
1297
1298 self.write_packet(packet, None, None, true, |wb| {
1299 sc_write(wb, SCStatusCodes::Busy, &[0xF4, 0x01])
1300 })?;
1301
1302 Self::netw_send(send, packet.peer, &packet.buf[packet.payload_start..], true)
1303 .await?;
1304
1305 if self.write_evict_some_session_packet(packet, true)? {
1306 Self::netw_send(
1307 send,
1308 packet.peer,
1309 &packet.buf[packet.payload_start..],
1310 true,
1311 )
1312 .await?;
1313 }
1314 } else {
1315 error!(
1316 "\n>>RCV {}\n => No space for a new encrypted session, dropping",
1317 packet
1318 );
1319 }
1320 }
1321 Err(e) if matches!(e.code(), ErrorCode::NoSpaceExchanges) => {
1322 error!(
1329 "\n>>RCV {}\n => No space for a new exchange, closing session",
1330 packet
1331 );
1332
1333 self.matter.with_state(|state| {
1334 let session_id = unwrap!(state
1340 .sessions
1341 .get_for_rx(&packet.peer, &packet.header.plain))
1342 .id;
1343
1344 packet.header.proto.exch_id = state.sessions.get_next_exch_id();
1345 packet.header.proto.set_initiator();
1346
1347 let mut session = unwrap!(state.sessions.remove(session_id));
1349 self.transport().notify_session_removed();
1350
1351 self.write_packet(packet, Some(&mut session), None, true, |wb| {
1352 sc_write(wb, SCStatusCodes::CloseSession, &[])
1353 })
1354 })?;
1355
1356 Self::netw_send(send, packet.peer, &packet.buf[packet.payload_start..], true)
1357 .await?;
1358 }
1359 Err(e) if matches!(e.code(), ErrorCode::NoExchange) => {
1360 warn!(
1361 "\n>>RCV {}\n => No valid exchange found, dropping",
1362 packet
1363 );
1364 }
1365 Err(e) if matches!(e.code(), ErrorCode::NoSession) => {
1366 warn!(
1375 "\n>>RCV {}\n => No valid session found, replying with SessionNotFound",
1376 packet
1377 );
1378
1379 packet.header.plain.sess_id = 0;
1387 packet.header.plain.set_src_nodeid(Some(0));
1388 packet.header.proto.unset_reliable();
1389 packet.header.proto.set_ack(None);
1390
1391 self.write_packet(packet, None, None, true, |wb| {
1392 sc_write(wb, SCStatusCodes::SessionNotFound, &[])
1393 })?;
1394
1395 Self::netw_send(send, packet.peer, &packet.buf[packet.payload_start..], true)
1396 .await?;
1397 }
1398 Err(e) => {
1399 error!("\n>>RCV {}\n => Error ({:?}), dropping", packet, e);
1400 }
1401 Ok(new_exchange) => {
1402 let meta = MessageMeta::from(&packet.header.proto);
1403
1404 if meta.is_standalone_ack() {
1405 debug!("\n>>RCV {}\n => Standalone Ack, dropping", packet);
1407 } else if meta.is_sc_status()
1408 && matches!(
1409 Self::is_close_session(&mut packet.buf[packet.payload_start..]),
1410 Ok(true)
1411 )
1412 {
1413 warn!(
1414 "\n>>RCV {}\n => Close session received, removing this session",
1415 packet
1416 );
1417
1418 self.matter.with_state(|state| {
1419 if let Some(session_id) = state
1420 .sessions
1421 .get_for_rx(&packet.peer, &packet.header.plain)
1422 .map(|sess| sess.id)
1423 {
1424 state.sessions.remove(session_id);
1425 self.transport().notify_session_removed();
1426 }
1427 });
1428 } else {
1429 debug!(
1430 "\n>>RCV {}\n => Processing{}",
1431 packet,
1432 if new_exchange { " (new exchange)" } else { "" }
1433 );
1434
1435 #[cfg(feature = "debug-tlv-payload")]
1436 debug!(
1437 "{}",
1438 Packet::<0>::display_payload(
1439 &packet.header.proto,
1440 &packet.buf[core::cmp::min(packet.payload_start, packet.buf.len())..]
1441 )
1442 );
1443
1444 #[cfg(not(feature = "debug-tlv-payload"))]
1445 trace!(
1446 "{}",
1447 Packet::<0>::display_payload(
1448 &packet.header.proto,
1449 &packet.buf[core::cmp::min(packet.payload_start, packet.buf.len())..]
1450 )
1451 );
1452
1453 return Ok(true);
1454 }
1455 }
1456 }
1457
1458 Ok(false)
1459 }
1460
1461 fn handle_accept_timeout_rx_packet<const N: usize>(&self, packet: &mut Packet<N>) -> bool {
1462 if packet.buf.is_empty() {
1463 return false;
1464 }
1465
1466 self.matter.with_state(|state| {
1467 let Some(session) = state
1468 .sessions
1469 .get_for_rx(&packet.peer, &packet.header.plain)
1470 else {
1471 return false;
1472 };
1473
1474 let Some(exch_index) = session.get_exch_for_rx(&packet.header.proto) else {
1475 return false;
1476 };
1477
1478 let exchange = unwrap!(session.exchanges[exch_index].as_mut());
1480
1481 if !matches!(
1482 exchange.role,
1483 Role::Responder(ResponderState::AcceptPending)
1484 ) || !exchange.mrp.has_rx_timed_out(ACCEPT_TIMEOUT_MS)
1485 {
1486 return false;
1487 }
1488
1489 warn!(
1490 "\n>>RCV {}\n => Accept timeout, marking exchange as dropped",
1491 packet
1492 );
1493
1494 exchange.role = Role::Responder(ResponderState::Dropped);
1495 packet.buf.clear();
1496 self.transport().exchange_dropped.notify();
1497
1498 true
1499 })
1500 }
1501
1502 fn handle_orphaned_rx_packet<const N: usize>(&self, packet: &mut Packet<N>) -> bool {
1503 if packet.buf.is_empty() {
1504 return false;
1505 }
1506
1507 self.matter.with_state(|state| {
1508 let Some(session) = state
1509 .sessions
1510 .get_for_rx(&packet.peer, &packet.header.plain)
1511 else {
1512 warn!("\n>>RCV {}\n => No session, dropping", packet);
1513
1514 packet.buf.clear();
1515 return true;
1516 };
1517
1518 let Some(exch_index) = session.get_exch_for_rx(&packet.header.proto) else {
1519 warn!("\n>>RCV {}\n => No exchange, dropping", packet);
1520
1521 packet.buf.clear();
1522 return true;
1523 };
1524
1525 let exchange = unwrap!(session.exchanges[exch_index].as_mut());
1527
1528 if exchange.role.is_dropped_state() {
1529 warn!(
1530 "\n>>RCV {}\n => Owned by orphaned dropped {}, dropping packet",
1531 packet,
1532 ExchangeId::new(session.id, exch_index)
1533 );
1534
1535 packet.buf.clear();
1536 return true;
1537 }
1538
1539 false
1540 })
1541 }
1542
1543 fn handle_dropped_exchange<const N: usize>(
1544 &self,
1545 packet: &mut Packet<N>,
1546 ) -> Result<bool, Error> {
1547 self.matter.with_state(|state| {
1548 let exch = state
1549 .sessions
1550 .get_exch(|_, exch| exch.role.is_dropped_state() && exch.mrp.is_retrans_pending())
1551 .map(|(sess, exch_index)| (sess.id, exch_index, true))
1552 .or_else(|| {
1553 state
1554 .sessions
1555 .get_exch(|_, exch| {
1556 exch.role.is_dropped_state() && !exch.mrp.is_retrans_pending()
1557 })
1558 .map(|(sess, exch_index)| (sess.id, exch_index, false))
1559 });
1560
1561 let Some((session_id, exch_index, close_session)) = exch else {
1562 return Ok(exch.is_none());
1563 };
1564
1565 let exchange_id = ExchangeId::new(session_id, exch_index);
1566
1567 if close_session {
1568 error!(
1572 "Dropped exchange {}: Closing session because the exchange cannot be closed cleanly",
1573 exchange_id.display(unwrap!(state.sessions.get(session_id))) );
1575
1576 self.write_evict_session_packet(packet, &mut state.sessions, session_id, false)?;
1577 } else {
1578 let session = unwrap!(state.sessions.get(session_id));
1583 let exchange = unwrap!(session.exchanges[exch_index].as_mut());
1585
1586 if exchange.mrp.is_ack_pending() {
1587 self.write_packet(
1588 packet,
1589 Some(session),
1590 Some(exch_index),
1591 false,
1592 |_| Ok(Some(OpCode::MRPStandAloneAck.into())),
1593 )?;
1594 }
1595
1596 warn!("Dropped exchange {}: Closed", exchange_id.display(session));
1597 session.exchanges[exch_index] = None;
1598 }
1599
1600 Ok(exch.is_none())
1601 })
1602 }
1603
1604 pub(crate) async fn evict_some_session(&self) -> Result<(), Error> {
1605 let mut tx = self
1606 .matter
1607 .transport
1608 .get_if_tx(|packet| packet.buf.is_empty())
1609 .await;
1610 tx.clear_on_drop(true); let evicted = self.write_evict_some_session_packet(&mut tx, true)?;
1613
1614 if evicted {
1615 tx.clear_on_drop(false);
1617
1618 Ok(())
1619 } else {
1620 Err(ErrorCode::NoSpaceSessions.into())
1621 }
1622 }
1623
1624 fn decode_packet<const N: usize>(&self, packet: &mut Packet<N>) -> Result<bool, Error> {
1625 self.matter.with_state(|state| {
1626 packet.header.reset();
1627
1628 let mut pb = ParseBuf::new(&mut packet.buf[packet.payload_start..]);
1629 packet.header.plain.decode(&mut pb)?;
1630
1631 let set_payload = |packet: &mut Packet<N>, (start, end)| {
1632 packet.payload_start = start;
1633 packet.buf.truncate(end);
1634 };
1635
1636 if let Some(session) = state
1637 .sessions
1638 .get_for_rx(&packet.peer, &packet.header.plain)
1639 {
1640 let payload_range =
1643 session.decode_remaining(&self.crypto, &mut packet.header, pb)?;
1644 set_payload(packet, payload_range);
1645
1646 return session.post_recv(&packet.header);
1647 }
1648
1649 if !packet.header.plain.is_encrypted() {
1652 packet
1655 .header
1656 .decode_remaining(&self.crypto, None, 0, &mut pb)?;
1657 packet.header.proto.adjust_reliability(true, &packet.peer);
1658
1659 let payload_range = pb.slice_range();
1660 set_payload(packet, payload_range);
1661
1662 if MessageMeta::from(&packet.header.proto).is_new_session() {
1663 let mut rand = self.crypto.rand()?;
1667
1668 let session = state.sessions.add(
1669 rand.next_u32(),
1670 false,
1671 packet.peer,
1672 packet.header.plain.get_src_nodeid(),
1673 self.matter.dev_det(),
1674 )?;
1675
1676 return session.post_recv(&packet.header);
1678 }
1679 } else if packet.header.plain.is_group_session() {
1680 let (session, payload_range) = state.sessions.get_or_create_for_group_rx(
1682 &self.crypto,
1683 &state.fabrics,
1684 packet,
1685 self.matter.dev_det(),
1686 )?;
1687 set_payload(packet, payload_range);
1688
1689 return session.post_recv(&packet.header);
1690 } else {
1691 set_payload(packet, (0, 0));
1693 }
1694
1695 Err(ErrorCode::NoSession.into())
1696 })
1697 }
1698
1699 fn encode_packet<const N: usize>(
1700 &self,
1701 packet: &mut Packet<N>,
1702 session: Option<&mut Session>,
1703 ) -> Result<(), Error> {
1704 assert!(matches!(
1705 packet.tx_info.payload_state,
1706 TxPayloadState::NotEncoded { .. }
1707 ));
1708
1709 let payload_end = packet.buf.len();
1710
1711 debug!(
1712 "\n<<SND {}\n => {}",
1713 Packet::<0>::display(&packet.peer, &packet.header),
1714 if packet.tx_info.retransmission {
1715 "Re-sending"
1716 } else {
1717 "Sending"
1718 }
1719 );
1720
1721 #[cfg(feature = "debug-tlv-payload")]
1722 debug!(
1723 "{}",
1724 Packet::<0>::display_payload(
1725 &packet.header.proto,
1726 &packet.buf[packet.payload_start..payload_end]
1727 )
1728 );
1729
1730 #[cfg(not(feature = "debug-tlv-payload"))]
1731 trace!(
1732 "{}",
1733 Packet::<0>::display_payload(
1734 &packet.header.proto,
1735 &packet.buf[packet.payload_start..payload_end]
1736 )
1737 );
1738
1739 unwrap!(packet.buf.resize_default(N));
1740
1741 let mut wb = WriteBuf::new_with(&mut packet.buf, packet.payload_start, payload_end);
1742 if let Some(session) = session {
1743 session.encode(&self.crypto, &packet.header, &mut wb)?;
1744 } else {
1745 packet.header.encode(&self.crypto, None, 0, &mut wb)?;
1746 }
1747
1748 let encoded_payload_start = wb.get_start();
1749 let encoded_payload_end = wb.get_tail();
1750
1751 packet.payload_start = encoded_payload_start;
1752 packet.tx_info.payload_state = TxPayloadState::Encoded;
1753 packet.buf.truncate(encoded_payload_end);
1754
1755 Ok(())
1756 }
1757
1758 fn write_packet<const N: usize, F>(
1759 &self,
1760 packet: &mut Packet<N>,
1761 mut session: Option<&mut Session>,
1762 exchange_index: Option<usize>,
1763 encode: bool,
1764 payload_writer: F,
1765 ) -> Result<(), Error>
1766 where
1767 F: FnOnce(&mut WriteBuf) -> Result<Option<MessageMeta>, Error>,
1768 {
1769 unwrap!(packet.buf.resize_default(N));
1773
1774 let mut wb = WriteBuf::new_with(
1775 &mut packet.buf,
1776 PacketHdr::HDR_RESERVE,
1777 PacketHdr::HDR_RESERVE,
1778 );
1779
1780 let Some(meta) = payload_writer(&mut wb)? else {
1781 packet.buf.clear();
1782 return Ok(());
1783 };
1784
1785 let (start, end) = (wb.get_start(), wb.get_tail());
1786
1787 packet.payload_start = start;
1788 packet.buf.truncate(end);
1789
1790 meta.set_into(&mut packet.header.proto);
1791
1792 if let Some(session) = &mut session {
1793 packet.header.plain = Default::default();
1794
1795 let (peer, retransmission) = session.pre_send(
1796 exchange_index,
1797 &mut packet.header,
1798 self.transport().device_sai,
1799 self.transport().device_sii,
1800 )?;
1801
1802 packet.peer = peer;
1803 packet.tx_info.retransmission = retransmission;
1804 packet.tx_info.payload_state = TxPayloadState::NotEncoded {
1805 session_id: session.id,
1806 };
1807 } else {
1808 if packet.header.plain.is_encrypted()
1809 || packet.header.plain.get_src_nodeid().is_none()
1810 || packet.header.proto.is_reliable()
1811 {
1812 Err(ErrorCode::NoSession)?;
1814 }
1815
1816 let src_nodeid = packet.header.plain.get_src_nodeid();
1817
1818 packet.header.plain = Default::default();
1819
1820 packet.header.plain.sess_id = 0;
1821 packet.header.plain.ctr = 1;
1822 packet.header.plain.set_src_nodeid(None);
1823 packet.header.plain.set_dst_unicast_nodeid(src_nodeid);
1824
1825 packet.header.proto.unset_initiator();
1826 packet.header.proto.adjust_reliability(false, &packet.peer);
1827
1828 packet.tx_info.retransmission = false;
1829 packet.tx_info.payload_state = TxPayloadState::NotEncoded { session_id: 0 };
1830 }
1831
1832 if encode {
1833 self.encode_packet(packet, session)?;
1834 }
1835
1836 Ok(())
1837 }
1838
1839 fn write_evict_some_session_packet<const N: usize>(
1840 &self,
1841 packet: &mut Packet<N>,
1842 encode: bool,
1843 ) -> Result<bool, Error> {
1844 self.matter.with_state(|state| {
1845 let id = state
1846 .sessions
1847 .get_session_for_eviction()
1848 .map(|sess| sess.id);
1849 if let Some(id) = id {
1850 self.write_evict_session_packet(packet, &mut state.sessions, id, encode)?;
1851
1852 Ok(true)
1853 } else {
1854 error!("All sessions have active exchanges, cannot evict any session");
1855
1856 Ok(false)
1857 }
1858 })
1859 }
1860
1861 fn write_evict_session_packet<const N: usize>(
1862 &self,
1863 packet: &mut Packet<N>,
1864 sessions: &mut Sessions,
1865 id: u32,
1866 encode: bool,
1867 ) -> Result<(), Error> {
1868 packet.header.proto.exch_id = sessions.get_next_exch_id();
1869 packet.header.proto.set_initiator();
1870
1871 let mut session = unwrap!(sessions.remove(id));
1873 self.transport().notify_session_removed();
1874
1875 debug!(
1876 "Evicting session {} [SID:{:x},RSID:{:x}]",
1877 session.id,
1878 session.get_local_sess_id(),
1879 session.get_peer_sess_id()
1880 );
1881
1882 self.write_packet(packet, Some(&mut session), None, encode, |wb| {
1883 sc_write(wb, SCStatusCodes::CloseSession, &[])
1884 })?;
1885
1886 Ok(())
1887 }
1888
1889 fn is_close_session(payload: &mut [u8]) -> Result<bool, Error> {
1890 let mut pb = ParseBuf::new(payload);
1891 let report = StatusReport::read(&mut pb)?;
1892
1893 let close_session = report.proto_id == PROTO_ID_SECURE_CHANNEL as u32
1894 && report.proto_code == SCStatusCodes::CloseSession as u16;
1895
1896 Ok(close_session)
1897 }
1898
1899 async fn netw_recv<R>(mut recv: R, buf: &mut [u8]) -> Result<(usize, Address), Error>
1900 where
1901 R: NetworkReceive,
1902 {
1903 match recv.recv_from(buf).await {
1904 Ok((len, addr)) => {
1905 trace!("\n>>RCV {} {}B:\n {}", addr, len, Bytes(&buf[..len]));
1906
1907 Ok((len, addr))
1908 }
1909 Err(e) => {
1910 error!("FAILED network recv: {:?}", e);
1911
1912 Err(e)
1913 }
1914 }
1915 }
1916
1917 async fn netw_send<S>(
1918 send: &IfMutex<S>,
1919 peer: Address,
1920 data: &[u8],
1921 system: bool,
1922 ) -> Result<(), Error>
1923 where
1924 S: NetworkSend,
1925 {
1926 match send.lock().await.send_to(data, peer).await {
1927 Ok(_) => {
1928 trace!(
1929 "\n<<SND {} {}B{}: {}",
1930 peer,
1931 data.len(),
1932 if system { " (system)" } else { "" },
1933 Bytes(data)
1934 );
1935
1936 Ok(())
1937 }
1938 Err(e) => {
1939 error!(
1940 "\n<<SND {} {}B{} !FAILED!: {:?}",
1941 peer,
1942 data.len(),
1943 if system { " (system)" } else { "" },
1944 e
1945 );
1946
1947 Ok(())
1951 }
1952 }
1953 }
1954
1955 #[inline(always)]
1956 const fn transport(&self) -> &Transport {
1957 self.matter.transport()
1958 }
1959}
1960
1961#[derive(Copy, Clone, Default, PartialEq, Eq, Debug, Hash)]
1962#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1963pub(crate) enum TxPayloadState {
1964 #[default]
1965 Encoded,
1966 NotEncoded {
1967 session_id: u32,
1968 },
1969}
1970
1971#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
1972#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1973pub(crate) struct TxInfo {
1974 pub(crate) retransmission: bool,
1975 pub(crate) payload_state: TxPayloadState,
1976}
1977
1978impl TxInfo {
1979 pub const fn new() -> Self {
1980 Self {
1981 retransmission: false,
1982 payload_state: TxPayloadState::Encoded,
1983 }
1984 }
1985}
1986
1987impl Default for TxInfo {
1988 fn default() -> Self {
1989 Self::new()
1990 }
1991}
1992
1993pub(crate) struct Packet<const N: usize> {
1998 pub(crate) peer: Address,
1999 pub(crate) header: PacketHdr,
2000 pub(crate) buf: PacketBuffer<N>,
2001 pub(crate) payload_start: usize,
2002 pub(crate) tx_info: TxInfo,
2003}
2004
2005impl<const N: usize> Packet<N> {
2006 #[inline(always)]
2007 pub(crate) const fn new() -> Self {
2008 Self {
2009 peer: Address::new(),
2010 header: PacketHdr::new(),
2011 buf: PacketBuffer::new(),
2012 payload_start: 0,
2013 tx_info: TxInfo::new(),
2014 }
2015 }
2016
2017 pub(crate) fn init() -> impl Init<Self> {
2018 init!(Self {
2019 peer: Address::new(),
2020 header: PacketHdr::new(),
2021 buf <- PacketBuffer::init(),
2022 payload_start: 0,
2023 tx_info: TxInfo::new(),
2024 })
2025 }
2026
2027 #[cfg(feature = "defmt")]
2028 pub fn display<'a>(
2029 peer: &'a Address,
2030 header: &'a PacketHdr,
2031 ) -> impl Display + defmt::Format + 'a {
2032 PacketInfo(peer, header)
2033 }
2034
2035 #[cfg(not(feature = "defmt"))]
2036 pub fn display<'a>(peer: &'a Address, header: &'a PacketHdr) -> impl Display + 'a {
2037 PacketInfo(peer, header)
2038 }
2039
2040 #[cfg(feature = "defmt")]
2041 pub fn display_payload<'a>(
2042 proto: &'a ProtoHdr,
2043 buf: &'a [u8],
2044 ) -> impl Display + defmt::Format + 'a {
2045 DetailedPacketInfo(proto, buf)
2046 }
2047
2048 #[cfg(not(feature = "defmt"))]
2049 pub fn display_payload<'a>(proto: &'a ProtoHdr, buf: &'a [u8]) -> impl Display + 'a {
2050 DetailedPacketInfo(proto, buf)
2051 }
2052
2053 fn fmt(f: &mut fmt::Formatter<'_>, peer: &Address, header: &PacketHdr) -> fmt::Result {
2054 write!(f, "{peer} {header}")?;
2055
2056 if header.proto.is_decoded() {
2057 let meta = MessageMeta::from(&header.proto);
2058
2059 write!(f, "\n {meta}")?;
2060 }
2061
2062 Ok(())
2063 }
2064
2065 #[cfg(feature = "defmt")]
2066 fn format(f: defmt::Formatter<'_>, peer: &Address, header: &PacketHdr) {
2067 defmt::write!(f, "{} {}", peer, header);
2068
2069 if header.proto.is_decoded() {
2070 let meta = MessageMeta::from(&header.proto);
2071
2072 defmt::write!(f, "\n {}", meta);
2073 }
2074 }
2075
2076 fn fmt_payload(f: &mut fmt::Formatter<'_>, proto: &ProtoHdr, buf: &[u8]) -> fmt::Result {
2077 let meta = MessageMeta::from(proto);
2078
2079 write!(f, "{meta}")?;
2080
2081 if meta.is_tlv() {
2082 write!(
2083 f,
2084 "; TLV:\n----------------\n{}\n----------------\n",
2085 TLVElement::new(buf)
2086 )?;
2087 } else {
2088 write!(
2089 f,
2090 "; Payload:\n----------------\n{:02x?}\n----------------\n",
2091 buf
2092 )?;
2093 }
2094
2095 Ok(())
2096 }
2097
2098 #[cfg(feature = "defmt")]
2099 fn format_payload(f: defmt::Formatter<'_>, proto: &ProtoHdr, buf: &[u8]) {
2100 let meta = MessageMeta::from(proto);
2101
2102 defmt::write!(f, "{}", meta);
2103
2104 if meta.is_tlv() {
2105 defmt::write!(
2106 f,
2107 "; TLV:\n----------------\n{}\n----------------\n",
2108 TLVElement::new(buf)
2109 );
2110 } else {
2111 defmt::write!(
2112 f,
2113 "; Payload:\n----------------\n{}\n----------------\n",
2114 crate::fmt::Bytes(buf)
2115 );
2116 }
2117 }
2118}
2119
2120impl<const N: usize> Display for Packet<N> {
2121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2122 Self::fmt(f, &self.peer, &self.header)
2123 }
2124}
2125
2126#[cfg(feature = "defmt")]
2127impl<const N: usize> defmt::Format for Packet<N> {
2128 fn format(&self, f: defmt::Formatter<'_>) {
2129 Self::format(f, &self.peer, &self.header)
2130 }
2131}
2132
2133struct PacketInfo<'a>(&'a Address, &'a PacketHdr);
2134
2135impl Display for PacketInfo<'_> {
2136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2137 Packet::<0>::fmt(f, self.0, self.1)
2138 }
2139}
2140
2141#[cfg(feature = "defmt")]
2142impl defmt::Format for PacketInfo<'_> {
2143 fn format(&self, f: defmt::Formatter<'_>) {
2144 Packet::<0>::format(f, self.0, self.1)
2145 }
2146}
2147
2148struct DetailedPacketInfo<'a>(&'a ProtoHdr, &'a [u8]);
2149
2150impl Display for DetailedPacketInfo<'_> {
2151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2152 Packet::<0>::fmt_payload(f, self.0, self.1)
2153 }
2154}
2155
2156#[cfg(feature = "defmt")]
2157impl defmt::Format for DetailedPacketInfo<'_> {
2158 fn format(&self, f: defmt::Formatter<'_>) {
2159 Packet::<0>::format_payload(f, self.0, self.1)
2160 }
2161}
2162
2163pub(crate) struct PacketBuffer<const N: usize> {
2173 buffer: crate::utils::storage::Vec<u8, N>,
2174}
2175
2176impl<const N: usize> PacketBuffer<N> {
2177 pub const fn new() -> Self {
2178 Self {
2179 buffer: crate::utils::storage::Vec::new(),
2180 }
2181 }
2182
2183 pub fn init() -> impl Init<Self> {
2184 init!(Self {
2185 buffer <- crate::utils::storage::Vec::init(),
2186 })
2187 }
2188
2189 pub fn buf_mut(&mut self) -> &mut crate::utils::storage::Vec<u8, N> {
2190 &mut self.buffer
2191 }
2192
2193 pub fn buf_ref(&self) -> &crate::utils::storage::Vec<u8, N> {
2194 &self.buffer
2195 }
2196}
2197
2198impl<const N: usize> Deref for PacketBuffer<N> {
2199 type Target = crate::utils::storage::Vec<u8, N>;
2200
2201 fn deref(&self) -> &Self::Target {
2202 self.buf_ref()
2203 }
2204}
2205
2206impl<const N: usize> DerefMut for PacketBuffer<N> {
2207 fn deref_mut(&mut self) -> &mut Self::Target {
2208 self.buf_mut()
2209 }
2210}
2211
2212pub(crate) struct PacketAccess<'a, const N: usize>(IfMutexGuard<'a, Packet<N>>, bool);
2220
2221impl<const N: usize> PacketAccess<'_, N> {
2222 pub fn clear_on_drop(&mut self, clear: bool) {
2223 self.1 = clear;
2224 }
2225}
2226
2227impl<const N: usize> Deref for PacketAccess<'_, N> {
2228 type Target = Packet<N>;
2229
2230 fn deref(&self) -> &Self::Target {
2231 &self.0
2232 }
2233}
2234
2235impl<const N: usize> DerefMut for PacketAccess<'_, N> {
2236 fn deref_mut(&mut self) -> &mut Self::Target {
2237 &mut self.0
2238 }
2239}
2240
2241impl<const N: usize> Drop for PacketAccess<'_, N> {
2242 fn drop(&mut self) {
2243 if self.1 {
2244 self.buf.clear();
2245 }
2246 }
2247}
2248
2249impl<const N: usize> Display for PacketAccess<'_, N> {
2250 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2251 self.0.fmt(f)
2252 }
2253}
2254
2255pub struct PacketBufferExternalAccess<'a, const N: usize>(pub(crate) &'a IfMutex<Packet<N>>);
2260
2261impl<const N: usize> Buffers<[u8]> for PacketBufferExternalAccess<'_, N> {
2262 type Buffer<'b>
2263 = ExternalPacketBuffer<'b, N>
2264 where
2265 Self: 'b;
2266
2267 async fn get(&self) -> Option<ExternalPacketBuffer<'_, N>> {
2268 let mut packet = self.0.lock_if(|packet| packet.buf.is_empty()).await;
2269
2270 unwrap!(packet.buf.resize_default(N));
2273
2274 Some(ExternalPacketBuffer(packet))
2275 }
2276
2277 fn get_immediate(&self) -> Option<Self::Buffer<'_>> {
2278 self.0
2279 .try_lock_if(|packet| packet.buf.is_empty())
2280 .ok()
2281 .map(|mut packet| {
2282 unwrap!(packet.buf.resize_default(N));
2285
2286 ExternalPacketBuffer(packet)
2287 })
2288 }
2289}
2290
2291pub struct ExternalPacketBuffer<'a, const N: usize>(IfMutexGuard<'a, Packet<N>>);
2293
2294impl<const N: usize> Deref for ExternalPacketBuffer<'_, N> {
2295 type Target = [u8];
2296
2297 fn deref(&self) -> &Self::Target {
2298 &self.0.buf
2299 }
2300}
2301
2302impl<const N: usize> DerefMut for ExternalPacketBuffer<'_, N> {
2303 fn deref_mut(&mut self) -> &mut Self::Target {
2304 &mut self.0.buf
2305 }
2306}
2307
2308impl<const N: usize> Drop for ExternalPacketBuffer<'_, N> {
2309 fn drop(&mut self) {
2310 self.0.buf.clear();
2311 }
2312}
2313
2314#[cfg(test)]
2315mod tests {
2316 use super::*;
2317 use crate::crypto::test_only_crypto;
2318 use crate::dm::devices::test::{TEST_DEV_ATT, TEST_DEV_COMM, TEST_DEV_DET};
2319
2320 fn test_matter() -> Matter<'static> {
2321 Matter::new(&TEST_DEV_DET, TEST_DEV_COMM, &TEST_DEV_ATT, 0)
2322 }
2323
2324 #[test]
2325 fn test_create_unsecured_session_creates_plaintext_session() {
2326 let matter = test_matter();
2327 let crypto = test_only_crypto();
2328 let peer = Address::new();
2329
2330 let session_id = matter
2331 .transport
2332 .create_plaintext_session(&matter, &crypto, peer)
2333 .unwrap();
2334
2335 matter.with_state(|state| {
2336 let session = state.sessions.get(session_id).unwrap();
2337
2338 assert_eq!(session.id, session_id);
2339 assert!(!session.is_encrypted());
2340 assert_eq!(session.get_peer_node_id(), None);
2341 assert_eq!(*session.get_session_mode(), session::SessionMode::PlainText);
2342 });
2343 }
2344
2345 #[test]
2346 fn test_initiate_unsecured_now_creates_initiator_exchange() {
2347 let matter = test_matter();
2348 let crypto = test_only_crypto();
2349 let peer = Address::new();
2350
2351 let exchange = matter
2352 .transport
2353 .try_initiate_plaintext(&matter, &crypto, peer)
2354 .unwrap();
2355
2356 exchange
2357 .with_state(|state| {
2358 let sess = exchange.id().session(&mut state.sessions);
2359 let exch = exchange.id().exch(sess);
2360
2361 assert!(matches!(exch.role, Role::Initiator(_)));
2362 assert_eq!(sess.id, exchange.id().session_id());
2363 Ok(())
2364 })
2365 .unwrap();
2366 }
2367}
2368
2369#[cfg(test)]
2370mod resolve_tests {
2371 use core::net::{IpAddr, Ipv4Addr, SocketAddr};
2372
2373 use futures_lite::future::{block_on, zip};
2374
2375 use crate::error::ErrorCode;
2376 use crate::test::test_matter;
2377 use crate::transport::network::mdns::{DottedName, MdnsRemoteService};
2378 use crate::transport::network::MatterRemoteService;
2379
2380 fn op_service() -> MatterRemoteService {
2381 MatterRemoteService::Operational {
2382 compressed_fabric_id: 0x1122,
2383 node_id: 0x3344,
2384 }
2385 }
2386
2387 #[test]
2391 fn resolve_rendezvous_delivers_answer() {
2392 let matter = test_matter();
2393 let service = op_service();
2394
2395 let resolved = block_on(async {
2396 let resolver = matter.transport().resolve(service.clone(), 5_000);
2397
2398 let responder = async {
2399 let picked = matter.transport().wait_mdns_resolve_request().await;
2400 assert_eq!(picked, service);
2401
2402 let mut name = heapless::String::<128>::new();
2403 service.instance_name(&mut name);
2404
2405 let answer = MdnsRemoteService {
2406 instance_name: DottedName(name.as_str()),
2407 port: Some(1234),
2408 addrs: [IpAddr::V4(Ipv4Addr::new(10, 0, 0, 5))].into_iter(),
2409 txt: [("SII", "300"), ("SAI", "4000"), ("SAT", "5000")].into_iter(),
2410 scope_id: 0,
2411 };
2412
2413 matter.transport().try_deposit_mdns_resolve(&answer);
2414 };
2415
2416 let (node, ()) = zip(resolver, responder).await;
2417 node
2418 })
2419 .unwrap();
2420
2421 assert_eq!(
2422 resolved.addr,
2423 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 5)), 1234)
2424 );
2425 assert_eq!(resolved.sii, Some(300));
2427 assert_eq!(resolved.sai, Some(4000));
2428 assert_eq!(resolved.sat, Some(5000));
2429 }
2430
2431 #[test]
2434 fn resolve_times_out_and_releases_slot() {
2435 let matter = test_matter();
2436
2437 let err = block_on(matter.transport().resolve(op_service(), 50)).unwrap_err();
2438 assert!(matches!(err.code(), ErrorCode::NotFound));
2439
2440 let err = block_on(matter.transport().resolve(op_service(), 50)).unwrap_err();
2441 assert!(matches!(err.code(), ErrorCode::NotFound));
2442 }
2443
2444 #[test]
2447 fn deposit_without_request_is_noop() {
2448 let matter = test_matter();
2449
2450 let mut name = heapless::String::<128>::new();
2451 op_service().instance_name(&mut name);
2452 let answer = MdnsRemoteService {
2453 instance_name: DottedName(name.as_str()),
2454 port: Some(1234),
2455 addrs: [IpAddr::V4(Ipv4Addr::new(10, 0, 0, 9))].into_iter(),
2456 txt: core::iter::empty::<(&str, &str)>(),
2457 scope_id: 0,
2458 };
2459 matter.transport().try_deposit_mdns_resolve(&answer);
2460
2461 let err = block_on(matter.transport().resolve(op_service(), 50)).unwrap_err();
2462 assert!(matches!(err.code(), ErrorCode::NotFound));
2463 }
2464}
2465
2466#[cfg(test)]
2467mod browse_tests {
2468 use core::net::{IpAddr, Ipv4Addr, SocketAddr};
2469
2470 use futures_lite::future::{block_on, zip};
2471
2472 use crate::error::ErrorCode;
2473 use crate::test::test_matter;
2474 use crate::transport::network::mdns::{CommissionableFilter, DottedName, MdnsRemoteService};
2475 use crate::transport::network::Address;
2476
2477 #[test]
2481 fn browse_rendezvous_delivers_first_match() {
2482 let matter = test_matter();
2483
2484 let filter = CommissionableFilter {
2485 discriminator: Some(0xA5A),
2486 vendor_id: Some(0xFFF1),
2487 ..Default::default()
2488 };
2489
2490 let found = block_on(async {
2491 let browser = matter
2492 .transport()
2493 .browse_commissionable(&filter, &[], 5_000);
2494
2495 let responder = async {
2496 let picked = matter.transport().wait_mdns_browse_request().await;
2497 assert_eq!(picked, filter);
2498
2499 let other = MdnsRemoteService {
2501 instance_name: DottedName("0000000000000001._matterc._udp.local"),
2502 port: Some(5540),
2503 addrs: [IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))].into_iter(),
2504 txt: [("D", "2650"), ("VP", "9999+1"), ("CM", "1")].into_iter(),
2505 scope_id: 0,
2506 };
2507 matter.transport().try_deposit_mdns_browse(&other);
2508
2509 let answer = MdnsRemoteService {
2511 instance_name: DottedName("00000000ABCD1234._matterc._udp.local"),
2512 port: Some(5541),
2513 addrs: [IpAddr::V4(Ipv4Addr::new(10, 0, 0, 7))].into_iter(),
2514 txt: [("D", "2650"), ("VP", "65521+42"), ("CM", "1")].into_iter(),
2515 scope_id: 0,
2516 };
2517 matter.transport().try_deposit_mdns_browse(&answer);
2518 };
2519
2520 let (found, ()) = zip(browser, responder).await;
2521 found
2522 })
2523 .unwrap();
2524
2525 assert_eq!(
2526 found,
2527 (
2528 Address::Udp(SocketAddr::new(
2529 IpAddr::V4(Ipv4Addr::new(10, 0, 0, 7)),
2530 5541
2531 )),
2532 0x00000000ABCD1234,
2533 )
2534 );
2535 }
2536
2537 #[test]
2539 fn browse_times_out_and_releases_slot() {
2540 let matter = test_matter();
2541 let filter = CommissionableFilter {
2542 short_discriminator: Some(0xA),
2543 ..Default::default()
2544 };
2545
2546 let err = block_on(matter.transport().browse_commissionable(&filter, &[], 50)).unwrap_err();
2547 assert!(matches!(err.code(), ErrorCode::NotFound));
2548
2549 let err = block_on(matter.transport().browse_commissionable(&filter, &[], 50)).unwrap_err();
2550 assert!(matches!(err.code(), ErrorCode::NotFound));
2551 }
2552
2553 #[test]
2556 fn browse_exclude_steps_to_next_match() {
2557 let matter = test_matter();
2558
2559 let filter = CommissionableFilter {
2561 short_discriminator: Some(0xA),
2562 ..Default::default()
2563 };
2564
2565 let found = block_on(async {
2567 let browser = matter
2568 .transport()
2569 .browse_commissionable(&filter, &[0x1111], 5_000);
2570
2571 let responder = async {
2572 matter.transport().wait_mdns_browse_request().await;
2573
2574 let node_a = MdnsRemoteService {
2575 instance_name: DottedName("0000000000001111._matterc._udp.local"),
2576 port: Some(5540),
2577 addrs: [IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))].into_iter(),
2578 txt: [("D", "2578"), ("CM", "1")].into_iter(), scope_id: 0,
2580 };
2581 matter.transport().try_deposit_mdns_browse(&node_a);
2583
2584 let node_b = MdnsRemoteService {
2585 instance_name: DottedName("0000000000002222._matterc._udp.local"),
2586 port: Some(5541),
2587 addrs: [IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2))].into_iter(),
2588 txt: [("D", "2815"), ("CM", "1")].into_iter(), scope_id: 0,
2590 };
2591 matter.transport().try_deposit_mdns_browse(&node_b);
2592 };
2593
2594 let (found, ()) = zip(browser, responder).await;
2595 found
2596 })
2597 .unwrap();
2598
2599 assert_eq!(
2600 found,
2601 (
2602 Address::Udp(SocketAddr::new(
2603 IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
2604 5541
2605 )),
2606 0x2222,
2607 )
2608 );
2609 }
2610}