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
26#[cfg(feature = "groups")]
27use embassy_futures::select::select4;
28use embassy_futures::select::{select, select3, Either};
29use embassy_time::{Duration, Timer};
30
31use rand_core::RngCore;
32
33use crate::crypto::Crypto;
34use crate::dm::clusters::basic_info::BasicInfoConfig;
35use crate::dm::NodeId;
36use crate::error::{Error, ErrorCode};
37#[cfg(feature = "groups")]
38use crate::fabric::{MAX_FABRICS, MAX_GROUPS_PER_FABRIC};
39use crate::fmt::Bytes;
40use crate::im::PROTO_ID_INTERACTION_MODEL;
41#[cfg(not(feature = "case-responder-only"))]
42use crate::sc::case::CaseInitiator;
43use crate::sc::pase::PaseInitiator;
44#[cfg(not(feature = "case-responder-only"))]
45use crate::sc::SessionParameters;
46use crate::sc::{sc_write, OpCode, SCStatusCodes, StatusReport, PROTO_ID_SECURE_CHANNEL};
47use crate::tlv::TLVElement;
48use crate::transport::network::mdns::{
49 commissionable_instance_id, score_ip_address, BrowseExclude, CommissionableFilter,
50 MdnsBrowseState, MdnsRemoteService, MdnsResolveState, ResolvedNode,
51};
52use crate::transport::network::{MatterRemoteService, NetworkMulticast};
53use crate::utils::cell::RefCell;
54use crate::utils::init::{init, Init};
55#[cfg(feature = "groups")]
56use crate::utils::ipv6::compute_group_multicast_addr;
57use crate::utils::select::Coalesce;
58use crate::utils::storage::Vec;
59use crate::utils::storage::{pooled::Buffers, ParseBuf, WriteBuf};
60
61use crate::utils::sync::blocking::Mutex;
62use crate::utils::sync::{IfMutex, IfMutexGuard, Notification, Signal};
63use crate::{Matter, MATTER_PORT};
64
65use exchange::{Exchange, ExchangeId, ExchangeState, MessageMeta, ResponderState, Role};
66use network::{Address, IpAddr, Ipv6Addr, NetworkReceive, NetworkSend, SocketAddr, SocketAddrV6};
67use packet::PacketHdr;
68use proto_hdr::ProtoHdr;
69use session::{Session, Sessions};
70
71use self::mrp::mrp_log;
72
73mod dedup;
74
75pub mod exchange;
76pub mod mrp;
77pub mod network;
78pub mod packet;
79pub mod plain_hdr;
80pub mod proto_hdr;
81pub mod session;
82
83pub const MATTER_SOCKET_BIND_ADDR: SocketAddr =
84 SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, MATTER_PORT, 0, 0));
85
86#[cfg(feature = "groups")]
87const MAX_GROUP_ADDRS: usize = MAX_FABRICS * MAX_GROUPS_PER_FABRIC + 1; #[cfg(not(feature = "groups"))]
93const MAX_GROUP_ADDRS: usize = 0;
94
95const ACCEPT_TIMEOUT_MS: u64 = 1000;
96
97#[cfg(feature = "large-buffers")]
98pub(crate) const MAX_RX_BUF_SIZE: usize = network::MAX_RX_LARGE_PACKET_SIZE;
99#[cfg(feature = "large-buffers")]
100pub(crate) const MAX_TX_BUF_SIZE: usize = network::MAX_TX_LARGE_PACKET_SIZE;
101
102#[cfg(not(feature = "large-buffers"))]
103pub(crate) const MAX_RX_BUF_SIZE: usize = network::MAX_RX_PACKET_SIZE;
104#[cfg(not(feature = "large-buffers"))]
105pub(crate) const MAX_TX_BUF_SIZE: usize = network::MAX_TX_PACKET_SIZE;
106
107pub const MAX_RX_PAYLOAD_SIZE: usize =
110 MAX_RX_BUF_SIZE - PacketHdr::HDR_RESERVE - PacketHdr::TAIL_RESERVE;
111
112pub const MAX_TX_PAYLOAD_SIZE: usize =
115 MAX_TX_BUF_SIZE - PacketHdr::HDR_RESERVE - PacketHdr::TAIL_RESERVE;
116
117pub struct Transport {
119 rx: IfMutex<Packet<MAX_RX_BUF_SIZE>>,
122 tx: IfMutex<Packet<MAX_TX_BUF_SIZE>>,
125 group_addrs: IfMutex<Vec<Ipv6Addr, MAX_GROUP_ADDRS>>,
128 exchange_dropped: Notification,
130 mdns_changed: Notification,
132 mdns_resolve: Signal<MdnsResolveState>,
135 mdns_browse: Signal<MdnsBrowseState>,
138 session_removed: Notification,
140 #[cfg_attr(not(feature = "groups"), allow(dead_code))]
144 groups_modified: Notification,
145 #[cfg_attr(not(feature = "case-resumption"), allow(dead_code))]
153 resumption_dirty: Notification,
154 counters: Mutex<RefCell<MessageCounters>>,
156 device_sai: Option<u32>,
158 device_sii: Option<u32>,
160}
161
162impl Transport {
163 #[inline(always)]
165 pub(crate) const fn new(dev_det: &BasicInfoConfig<'_>) -> Self {
166 Self {
167 rx: IfMutex::new(Packet::new()),
168 tx: IfMutex::new(Packet::new()),
169 group_addrs: IfMutex::new(Vec::new()),
170 exchange_dropped: Notification::new(),
171 mdns_changed: Notification::new(),
172 mdns_resolve: Signal::new(MdnsResolveState::Idle),
173 mdns_browse: Signal::new(MdnsBrowseState::Idle),
174 session_removed: Notification::new(),
175 groups_modified: Notification::new(),
176 resumption_dirty: Notification::new(),
177 counters: Mutex::new(RefCell::new(MessageCounters::new())),
178 device_sai: dev_det.sai,
179 device_sii: dev_det.sii,
180 }
181 }
182
183 pub(crate) fn init<'m>(dev_det: &'m BasicInfoConfig<'m>) -> impl Init<Self> + 'm {
185 init!(Self {
186 rx <- IfMutex::init(Packet::init()),
187 tx <- IfMutex::init(Packet::init()),
188 group_addrs <- IfMutex::init(Vec::init()),
189 exchange_dropped <- Notification::init(),
190 mdns_changed <- Notification::init(),
191 mdns_resolve <- Signal::init(MdnsResolveState::Idle),
192 mdns_browse <- Signal::init(MdnsBrowseState::Idle),
193 session_removed <- Notification::init(),
194 groups_modified <- Notification::init(),
195 resumption_dirty <- Notification::init(),
196 counters <- Mutex::init(RefCell::init(MessageCounters::new())),
197 device_sai: dev_det.sai,
198 device_sii: dev_det.sii,
199 })
200 }
201
202 pub fn reset(&self) -> Result<(), Error> {
205 self.rx
206 .try_lock()
207 .map_err(|_| ErrorCode::InvalidState)?
208 .buf
209 .clear();
210 self.tx
211 .try_lock()
212 .map_err(|_| ErrorCode::InvalidState)?
213 .buf
214 .clear();
215
216 Ok(())
217 }
218
219 pub fn rx_buffer(&self) -> PacketBufferExternalAccess<'_, MAX_RX_BUF_SIZE> {
224 PacketBufferExternalAccess(&self.rx)
225 }
226
227 pub fn tx_buffer(&self) -> PacketBufferExternalAccess<'_, MAX_TX_BUF_SIZE> {
232 PacketBufferExternalAccess(&self.tx)
233 }
234
235 pub(crate) fn notify_mdns_changed(&self) {
237 self.mdns_changed.notify();
238 }
239
240 pub fn wait_mdns(&self) -> impl Future<Output = ()> + '_ {
245 self.mdns_changed.wait()
246 }
247
248 #[cfg(feature = "groups")]
251 pub(crate) fn notify_groups_changed(&self) {
252 self.groups_modified.notify();
253 }
254
255 #[cfg(feature = "groups")]
257 fn wait_groups_changed(&self) -> impl Future<Output = ()> + '_ {
258 self.groups_modified.wait()
259 }
260
261 pub fn counters(&self) -> MessageCounters {
263 self.counters.lock(|counters| counters.borrow().clone())
264 }
265
266 pub(crate) fn notify_session_removed(&self) {
268 self.session_removed.notify();
269 }
270
271 pub(crate) fn wait_session_removed(&self) -> impl Future<Output = ()> + '_ {
273 self.session_removed.wait()
274 }
275
276 #[cfg(feature = "case-resumption")]
280 pub(crate) fn notify_resumption_dirty(&self) {
281 self.resumption_dirty.notify();
282 }
283
284 #[cfg(feature = "case-resumption")]
289 pub(crate) fn wait_resumption_dirty(&self) -> impl Future<Output = ()> + '_ {
290 self.resumption_dirty.wait()
291 }
292
293 async fn resolve(
307 &self,
308 service: MatterRemoteService,
309 timeout_ms: u32,
310 ) -> Result<ResolvedNode, Error> {
311 self.mdns_resolve
313 .wait(|state| {
314 if matches!(state, MdnsResolveState::Idle) {
315 *state = MdnsResolveState::Requested {
316 service: service.clone(),
317 };
318 Some(())
319 } else {
320 None
321 }
322 })
323 .await;
324
325 let mut guard = MdnsResolveGuard {
327 signal: &self.mdns_resolve,
328 armed: true,
329 };
330
331 let mut wait = pin!(self.mdns_resolve.wait(|state| match state {
333 MdnsResolveState::Resolved {
334 ip,
335 port,
336 scope_id,
337 sii,
338 sai,
339 sat,
340 } => {
341 let node = ResolvedNode {
342 addr: Self::scoped_socket_addr(*ip, *port, *scope_id),
343 sii: *sii,
344 sai: *sai,
345 sat: *sat,
346 };
347 *state = MdnsResolveState::Idle;
348 Some(node)
349 }
350 _ => None,
351 }));
352
353 let mut timer = pin!(Timer::after(Duration::from_millis(timeout_ms as u64)));
354
355 match select(&mut wait, &mut timer).await {
356 Either::First(node) => {
357 guard.armed = false;
359
360 Ok(node)
361 }
362 Either::Second(_) => Err(ErrorCode::NotFound.into()),
363 }
364 }
365
366 pub async fn wait_mdns_resolve_request(&self) -> MatterRemoteService {
374 self.mdns_resolve
375 .wait(|state| match state {
376 MdnsResolveState::Requested { service } => {
377 let service = service.clone();
378 *state = MdnsResolveState::InFlight {
379 service: service.clone(),
380 };
381 Some(service)
382 }
383 _ => None,
384 })
385 .await
386 }
387
388 #[allow(dead_code)]
393 pub fn mdns_resolve_in_flight(&self) -> bool {
394 self.mdns_resolve
395 .modify(|state| (false, matches!(state, MdnsResolveState::InFlight { .. })))
396 }
397
398 pub fn try_deposit_mdns_resolve<'a, I, A, T>(&self, answer: &MdnsRemoteService<I, A, T>)
408 where
409 I: ToLabelIter,
410 A: Iterator<Item = IpAddr> + Clone,
411 T: Iterator<Item = (&'a str, &'a str)> + Clone,
412 {
413 let Some(ip) = answer.addrs.clone().max_by_key(score_ip_address) else {
414 return;
415 };
416 let Some(port) = answer.port else {
417 return;
418 };
419 let scope_id = answer.scope_id;
420
421 let (sii, sai, sat) = answer.session_params();
422
423 self.mdns_resolve.modify(|state| match state {
424 MdnsResolveState::InFlight { service }
425 if service.matches_instance(&answer.instance_name) =>
426 {
427 *state = MdnsResolveState::Resolved {
428 ip,
429 port,
430 scope_id,
431 sii,
432 sai,
433 sat,
434 };
435 (true, ())
436 }
437 MdnsResolveState::Resolved {
448 ip: cur_ip,
449 sii: cur_sii,
450 sai: cur_sai,
451 sat: cur_sat,
452 ..
453 } if score_ip_address(&ip) > score_ip_address(cur_ip) => {
454 *state = MdnsResolveState::Resolved {
455 ip,
456 port,
457 scope_id,
458 sii: sii.or(*cur_sii),
459 sai: sai.or(*cur_sai),
460 sat: sat.or(*cur_sat),
461 };
462 (true, ())
463 }
464 _ => (false, ()),
465 });
466 }
467
468 pub async fn browse_commissionable(
495 &self,
496 filter: &CommissionableFilter,
497 exclude: &[u64],
498 timeout_ms: u32,
499 ) -> Result<(Address, u64), Error> {
500 let mut exclude_vec = BrowseExclude::new();
501 exclude_vec
502 .extend_from_slice(exclude)
503 .map_err(|_| ErrorCode::ResourceExhausted)?;
504
505 self.mdns_browse
507 .wait(|state| {
508 if matches!(state, MdnsBrowseState::Idle) {
509 *state = MdnsBrowseState::Requested {
510 filter: filter.clone(),
511 exclude: exclude_vec.clone(),
512 };
513 Some(())
514 } else {
515 None
516 }
517 })
518 .await;
519
520 let mut guard = MdnsBrowseGuard {
522 signal: &self.mdns_browse,
523 armed: true,
524 };
525
526 let mut wait = pin!(self.mdns_browse.wait(|state| match state {
528 MdnsBrowseState::Found {
529 ip,
530 port,
531 scope_id,
532 id,
533 } => {
534 let found = (
535 Address::Udp(Self::scoped_socket_addr(*ip, *port, *scope_id)),
536 *id,
537 );
538 *state = MdnsBrowseState::Idle;
539 Some(found)
540 }
541 _ => None,
542 }));
543
544 let mut timer = pin!(Timer::after(Duration::from_millis(timeout_ms as u64)));
545
546 match select(&mut wait, &mut timer).await {
547 Either::First(found) => {
548 guard.armed = false;
549
550 Ok(found)
551 }
552 Either::Second(_) => Err(ErrorCode::NotFound.into()),
553 }
554 }
555
556 pub async fn wait_mdns_browse_request(&self) -> CommissionableFilter {
565 self.mdns_browse
566 .wait(|state| match state {
567 MdnsBrowseState::Requested { filter, exclude } => {
568 let filter = filter.clone();
569 *state = MdnsBrowseState::InFlight {
570 filter: filter.clone(),
571 exclude: core::mem::take(exclude),
572 };
573
574 Some(filter)
575 }
576 _ => None,
577 })
578 .await
579 }
580
581 #[allow(dead_code)]
586 pub fn mdns_browse_in_flight(&self) -> bool {
587 self.mdns_browse
588 .modify(|state| (false, matches!(state, MdnsBrowseState::InFlight { .. })))
589 }
590
591 pub fn try_deposit_mdns_browse<'a, I, A, T>(&self, answer: &MdnsRemoteService<I, A, T>)
600 where
601 I: ToLabelIter,
602 A: Iterator<Item = IpAddr> + Clone,
603 T: Iterator<Item = (&'a str, &'a str)> + Clone,
604 {
605 let Some(id) = commissionable_instance_id(&answer.instance_name) else {
606 return;
607 };
608 let Some(ip) = answer.addrs.clone().max_by_key(score_ip_address) else {
609 return;
610 };
611 let Some(port) = answer.port else {
612 return;
613 };
614 let scope_id = answer.scope_id;
615
616 self.mdns_browse.modify(|state| match state {
617 MdnsBrowseState::InFlight { filter, exclude }
618 if !exclude.contains(&id) && filter.matches(answer) =>
619 {
620 *state = MdnsBrowseState::Found {
621 ip,
622 port,
623 scope_id,
624 id,
625 };
626 (true, ())
627 }
628 MdnsBrowseState::Found {
634 ip: cur_ip,
635 id: cur_id,
636 ..
637 } if *cur_id == id && score_ip_address(&ip) > score_ip_address(cur_ip) => {
638 *state = MdnsBrowseState::Found {
639 ip,
640 port,
641 scope_id,
642 id,
643 };
644 (true, ())
645 }
646 _ => (false, ()),
647 });
648 }
649
650 pub(crate) async fn accept_if<'a, F>(
651 &self,
652 matter: &'a Matter<'a>,
653 mut f: F,
654 ) -> Result<Exchange<'a>, Error>
655 where
656 F: FnMut(&Session, &ExchangeState, &Packet<MAX_RX_BUF_SIZE>) -> bool,
657 {
658 let exchange = self
659 .rx
660 .with(|packet| {
661 matter.with_state(|state| {
662 let session = state
663 .sessions
664 .get_for_rx(&packet.peer, &packet.header.plain)?;
665 let exch_index = session.get_exch_for_rx(&packet.header.proto)?;
666
667 let matches = {
668 let exch = unwrap!(session.exchanges[exch_index].as_ref());
671
672 matches!(exch.role, Role::Responder(ResponderState::AcceptPending))
673 && f(session, exch, packet)
674 };
675
676 if !matches {
677 return None;
678 }
679
680 let exch = unwrap!(session.exchanges[exch_index].as_mut());
683
684 exch.role = Role::Responder(ResponderState::Owned);
685
686 let id = ExchangeId::new(session.id, exch_index);
687
688 debug!("Exchange {}: Accepted", id.display(session));
689
690 let exchange = Exchange::new(id, matter);
691
692 Some(exchange)
693 })
694 })
695 .await;
696
697 Ok(exchange)
698 }
699
700 const RESOLVE_TIMEOUT_MS: u32 = 5_000;
704
705 pub(crate) async fn initiate<'a, C: Crypto>(
715 &self,
716 matter: &'a Matter<'a>,
717 crypto: C,
718 fabric_idx: NonZeroU8,
719 peer_node_id: NodeId,
720 ) -> Result<Exchange<'a>, Error> {
721 let existing = matter.with_state(|state| {
723 Ok::<_, Error>(
724 state
725 .sessions
726 .get_for_node(fabric_idx, peer_node_id)
727 .map(|s| s.id),
728 )
729 })?;
730
731 if let Some(session_id) = existing {
732 return self.initiate_for_session(matter, crypto, session_id);
733 }
734
735 self.initiate_new_case(matter, crypto, fabric_idx, peer_node_id)
736 .await
737 }
738
739 #[cfg(not(feature = "case-responder-only"))]
748 async fn initiate_new_case<'a, C: Crypto>(
749 &self,
750 matter: &'a Matter<'a>,
751 crypto: C,
752 fabric_idx: NonZeroU8,
753 peer_node_id: NodeId,
754 ) -> Result<Exchange<'a>, Error> {
755 let compressed_fabric_id = matter.with_state(|state| {
757 Ok::<_, Error>(state.fabrics.fabric(fabric_idx)?.compressed_fabric_id())
758 })?;
759
760 let service = MatterRemoteService::Operational {
761 compressed_fabric_id,
762 node_id: peer_node_id,
763 };
764
765 let resolved = self.resolve(service, Self::RESOLVE_TIMEOUT_MS).await?;
766
767 let exchange = self
771 .initiate_plaintext(matter, &crypto, Address::Udp(resolved.addr))
772 .await?;
773
774 CaseInitiator::perform(exchange, &crypto, fabric_idx, peer_node_id).await?;
775
776 let params = SessionParameters {
780 sii: resolved.sii,
781 sai: resolved.sai,
782 sat: resolved.sat,
783 ..Default::default()
784 };
785
786 let session_id = matter.with_state(|state| {
787 let session = state
788 .sessions
789 .get_for_node(fabric_idx, peer_node_id)
790 .ok_or(ErrorCode::NoSession)?;
791
792 session.set_peer_session_params(¶ms);
793
794 Ok::<_, Error>(session.id)
795 })?;
796
797 self.initiate_for_session(matter, crypto, session_id)
798 }
799
800 #[cfg(feature = "case-responder-only")]
807 async fn initiate_new_case<'a, C: Crypto>(
808 &self,
809 _matter: &'a Matter<'a>,
810 _crypto: C,
811 _fabric_idx: NonZeroU8,
812 _peer_node_id: NodeId,
813 ) -> Result<Exchange<'a>, Error> {
814 Err(ErrorCode::NoSession.into())
815 }
816
817 pub(crate) async fn initiate_plaintext_operational<'a, C: Crypto>(
827 &self,
828 matter: &'a Matter<'a>,
829 crypto: C,
830 fabric_idx: NonZeroU8,
831 peer_node_id: NodeId,
832 ) -> Result<Exchange<'a>, Error> {
833 let compressed_fabric_id = matter.with_state(|state| {
834 Ok::<_, Error>(state.fabrics.fabric(fabric_idx)?.compressed_fabric_id())
835 })?;
836
837 let service = MatterRemoteService::Operational {
838 compressed_fabric_id,
839 node_id: peer_node_id,
840 };
841
842 let resolved = self.resolve(service, Self::RESOLVE_TIMEOUT_MS).await?;
843
844 self.initiate_plaintext(matter, crypto, Address::Udp(resolved.addr))
845 .await
846 }
847
848 pub(crate) async fn initiate_pase<'a, C: Crypto>(
863 &self,
864 matter: &'a Matter<'a>,
865 crypto: C,
866 peer_addr: Address,
867 passcode: u32,
868 ) -> Result<Exchange<'a>, Error> {
869 let existing = matter.with_state(|state| {
871 Ok::<_, Error>(state.sessions.get_pase_for_addr(&peer_addr).map(|s| s.id))
872 })?;
873
874 if let Some(session_id) = existing {
875 return self.initiate_for_session(matter, crypto, session_id);
876 }
877
878 let exchange = self.initiate_plaintext(matter, &crypto, peer_addr).await?;
880 PaseInitiator::perform(exchange, &crypto, passcode).await?;
881
882 let session_id = matter.with_state(|state| {
883 state
884 .sessions
885 .get_pase_for_addr(&peer_addr)
886 .map(|s| s.id)
887 .ok_or_else(|| Error::from(ErrorCode::NoSession))
888 })?;
889
890 self.initiate_for_session(matter, crypto, session_id)
891 }
892
893 pub(crate) fn initiate_for_session<'a, C: Crypto>(
894 &self,
895 matter: &'a Matter<'a>,
896 crypto: C,
897 session_id: u32,
898 ) -> Result<Exchange<'a>, Error> {
899 matter.with_state(|state| {
900 state
901 .sessions
902 .get(session_id)
903 .filter(|sess| !sess.is_expired())
905 .ok_or(ErrorCode::NoSession)?;
906
907 let exch_id = state.sessions.get_next_exch_id(crypto)?;
908
909 let session = unwrap!(state.sessions.get(session_id));
913
914 let exch_index = session
915 .add_exch(exch_id, Role::Initiator(Default::default()))
916 .ok_or(ErrorCode::NoSpaceExchanges)?;
917
918 let id = ExchangeId::new(session.id, exch_index);
919
920 debug!("Exchange {}: Initiated", id.display(session));
921
922 Ok(Exchange::new(id, matter))
923 })
924 }
925
926 async fn initiate_plaintext<'a, C: Crypto>(
933 &self,
934 matter: &'a Matter<'a>,
935 crypto: C,
936 peer_addr: Address,
937 ) -> Result<Exchange<'a>, Error> {
938 match self.try_initiate_plaintext(matter, &crypto, peer_addr) {
939 Ok(exchange) => Ok(exchange),
940 Err(e) if e.code() == ErrorCode::NoSpaceSessions => {
941 matter
942 .transport_runner(&crypto)
943 .evict_some_session()
944 .await?;
945 self.try_initiate_plaintext(matter, &crypto, peer_addr)
946 }
947 Err(e) => Err(e),
948 }
949 }
950
951 fn try_initiate_plaintext<'a, C: Crypto>(
959 &self,
960 matter: &'a Matter<'a>,
961 crypto: C,
962 peer_addr: Address,
963 ) -> Result<Exchange<'a>, Error> {
964 let session_id = self.create_plaintext_session(matter, &crypto, peer_addr)?;
965
966 self.initiate_for_session(matter, crypto, session_id)
967 }
968
969 fn create_plaintext_session<C: Crypto>(
977 &self,
978 matter: &Matter<'_>,
979 crypto: C,
980 peer_addr: Address,
981 ) -> Result<u32, Error> {
982 matter.with_state(|state| {
983 let mut rand = crypto.rand()?;
984
985 let session =
986 state
987 .sessions
988 .add(rand.next_u32(), false, peer_addr, None, matter.dev_det())?;
989
990 const MAX_OPERATIONAL_NODE_ID: u64 = 0xFFFF_FFEF_FFFF_FFFF;
995 let mut ephemeral_id = rand.next_u64();
996 while ephemeral_id == 0 || ephemeral_id > MAX_OPERATIONAL_NODE_ID {
997 ephemeral_id = rand.next_u64();
998 }
999 session.set_local_nodeid(ephemeral_id);
1000
1001 let session_id = session.id;
1002
1003 debug!(
1004 "Unsecured session {} created for peer {}",
1005 session_id, peer_addr
1006 );
1007
1008 Ok(session_id)
1009 })
1010 }
1011
1012 pub(crate) async fn get_if_rx<F>(&self, f: F) -> PacketAccess<'_, MAX_RX_BUF_SIZE>
1013 where
1014 F: Fn(&Packet<MAX_RX_BUF_SIZE>) -> bool,
1015 {
1016 Self::get_if(&self.rx, f).await
1017 }
1018
1019 pub(crate) async fn get_if_tx<F>(&self, f: F) -> PacketAccess<'_, MAX_TX_BUF_SIZE>
1020 where
1021 F: Fn(&Packet<MAX_TX_BUF_SIZE>) -> bool,
1022 {
1023 Self::get_if(&self.tx, f).await
1024 }
1025
1026 async fn get_if<'b, F, const N: usize>(
1027 packet_mutex: &'b IfMutex<Packet<N>>,
1028 f: F,
1029 ) -> PacketAccess<'b, N>
1030 where
1031 F: Fn(&Packet<N>) -> bool,
1032 {
1033 PacketAccess(packet_mutex.lock_if(f).await, false)
1034 }
1035
1036 fn scoped_socket_addr(ip: IpAddr, port: u16, scope_id: u32) -> SocketAddr {
1044 match ip {
1045 IpAddr::V6(v6) if v6.is_unicast_link_local() => {
1046 SocketAddr::V6(SocketAddrV6::new(v6, port, 0, scope_id))
1047 }
1048 _ => SocketAddr::new(ip, port),
1049 }
1050 }
1051}
1052
1053struct MdnsResolveGuard<'a> {
1058 signal: &'a Signal<MdnsResolveState>,
1059 armed: bool,
1060}
1061
1062impl Drop for MdnsResolveGuard<'_> {
1063 fn drop(&mut self) {
1064 if self.armed {
1065 self.signal.modify(|state| {
1066 if matches!(state, MdnsResolveState::Idle) {
1067 (false, ())
1068 } else {
1069 *state = MdnsResolveState::Idle;
1070 (true, ())
1071 }
1072 });
1073 }
1074 }
1075}
1076
1077struct MdnsBrowseGuard<'a> {
1080 signal: &'a Signal<MdnsBrowseState>,
1081 armed: bool,
1082}
1083
1084impl Drop for MdnsBrowseGuard<'_> {
1085 fn drop(&mut self) {
1086 if self.armed {
1087 self.signal.modify(|state| {
1088 if matches!(state, MdnsBrowseState::Idle) {
1089 (false, ())
1090 } else {
1091 *state = MdnsBrowseState::Idle;
1092 (true, ())
1093 }
1094 });
1095 }
1096 }
1097}
1098
1099pub struct TransportRunner<'a, C> {
1105 matter: &'a Matter<'a>,
1106 crypto: C,
1107}
1108
1109impl<'a, C: Crypto> TransportRunner<'a, C> {
1110 pub const fn new(matter: &'a Matter<'a>, crypto: C) -> Self {
1112 Self { matter, crypto }
1113 }
1114
1115 pub async fn run<S, R, M>(
1120 &mut self,
1121 send: S,
1122 recv: R,
1123 #[cfg_attr(not(feature = "groups"), allow(unused_variables))] multicast: M,
1124 ) -> Result<(), Error>
1125 where
1126 S: NetworkSend,
1127 R: NetworkReceive,
1128 M: NetworkMulticast,
1129 {
1130 info!("Running Matter transport");
1131
1132 debug!("APP STATUS: Starting event loop");
1135
1136 let send = IfMutex::new(send);
1137
1138 let mut rx = pin!(self.process_rx(recv, &send));
1139 let mut tx = pin!(self.process_tx(&send));
1140 let mut orphaned = pin!(self.process_orphaned());
1141
1142 #[cfg(feature = "groups")]
1143 {
1144 let mut joined = self.transport().group_addrs.lock().await;
1145 let mut groups = pin!(self.process_groups(multicast, &mut joined));
1146
1147 select4(&mut rx, &mut tx, &mut orphaned, &mut groups)
1148 .coalesce()
1149 .await
1150 }
1151
1152 #[cfg(not(feature = "groups"))]
1153 {
1154 select3(&mut rx, &mut tx, &mut orphaned).coalesce().await
1155 }
1156 }
1157
1158 #[cfg(feature = "groups")]
1163 fn observe_group_rx_failure<const N: usize>(
1164 &self,
1165 packet: &Packet<N>,
1166 fabrics: &crate::fabric::Fabrics,
1167 e: &Error,
1168 ) {
1169 use crate::dm::clusters::groupcast;
1170
1171 let Some(group_id) = packet.header.plain.get_dst_groupcast_nodeid() else {
1174 return;
1175 };
1176
1177 let Some(mode) = self
1178 .matter
1179 .groupcast_testing()
1180 .armed(groupcast::GroupcastTestingEnum::EnableListenerTesting)
1181 else {
1182 return;
1183 };
1184
1185 let (result, authenticated) = match e.code() {
1186 ErrorCode::NoSession => (groupcast::GroupcastTestResultEnum::NoAvailableKey, false),
1188 ErrorCode::InvalidSignature => (groupcast::GroupcastTestResultEnum::FailedAuth, false),
1190 ErrorCode::Duplicate => (groupcast::GroupcastTestResultEnum::MessageReplay, true),
1192 _ => (groupcast::GroupcastTestResultEnum::GeneralError, false),
1193 };
1194
1195 self.matter
1196 .groupcast_testing()
1197 .observe(groupcast::TestingObservation {
1198 src_ip: groupcast::TestingObservation::addr_ip(&packet.peer),
1199 dst_ip: Some(groupcast::TestingObservation::group_dst_ip(
1200 fabrics,
1201 mode.fab_idx,
1202 group_id,
1203 )),
1204 group_id: authenticated.then_some(group_id),
1208 endpoint_id: None,
1209 cluster_id: None,
1210 element_id: None,
1211 access_allowed: None,
1212 result,
1213 });
1214 }
1215
1216 #[cfg(feature = "groups")]
1217 async fn process_groups<M>(
1218 &self,
1219 mut multicast: M,
1220 joined: &mut Vec<Ipv6Addr, MAX_GROUP_ADDRS>,
1221 ) -> Result<(), Error>
1222 where
1223 M: NetworkMulticast,
1224 {
1225 joined.clear();
1226
1227 loop {
1228 let addr_op = self.matter.with_state(|state| {
1229 let group_addrs = || {
1230 state.fabrics.iter().flat_map(|fabric| {
1231 fabric.groups().iter().map(|group| {
1232 use crate::dm::clusters::decl::groupcast::MulticastAddrPolicyEnum;
1240
1241 match group.effective_mcast_policy() {
1242 MulticastAddrPolicyEnum::IanaAddr => {
1243 crate::utils::ipv6::IANA_GROUPCAST_MULTICAST_ADDR
1244 }
1245 MulticastAddrPolicyEnum::PerGroup => {
1246 compute_group_multicast_addr(fabric.fabric_id(), group.group_id)
1247 }
1248 }
1249 })
1250 })
1251 };
1252
1253 if let Some(new_addr) = group_addrs().find(|addr| !joined.contains(addr)) {
1254 Some((new_addr, true))
1255 } else {
1256 joined
1257 .iter()
1258 .find(|addr| !group_addrs().any(|a| a == **addr))
1259 .map(|&removed_addr| (removed_addr, false))
1260 }
1261 });
1262
1263 match addr_op {
1264 Some((new_addr, true)) => {
1265 match multicast.join(new_addr.into()).await {
1266 Ok(_) => {
1267 debug!("Joined multicast group: {}", new_addr);
1268 unwrap!(joined.push(new_addr));
1271 }
1272 Err(e) => error!(
1273 "Joining multicast group {} failed with error: {}",
1274 new_addr, e
1275 ),
1276 }
1277 }
1278 Some((removed_addr, false)) => match multicast.leave(removed_addr.into()).await {
1279 Ok(_) => {
1280 debug!("Left multicast group: {}", removed_addr);
1281 let index = joined
1282 .iter()
1283 .position(|&addr| addr == removed_addr)
1284 .unwrap();
1285 joined.swap_remove(index);
1286 }
1287 Err(e) => error!(
1288 "Leaving multicast group {} failed with error: {}",
1289 removed_addr, e
1290 ),
1291 },
1292 None => {
1293 self.transport().wait_groups_changed().await;
1294 }
1295 }
1296 }
1297 }
1298
1299 async fn process_tx<S>(&self, send: &IfMutex<S>) -> Result<(), Error>
1300 where
1301 S: NetworkSend,
1302 {
1303 loop {
1304 trace!("Waiting for outgoing packet");
1305
1306 let mut tx = self
1307 .matter
1308 .transport
1309 .get_if_tx(|packet| !packet.buf.is_empty())
1310 .await;
1311 tx.clear_on_drop(true);
1312
1313 if let TxPayloadState::NotEncoded { session_id } = tx.tx_info.payload_state {
1314 let encoded = self.matter.with_state(|state| {
1315 if let Some(session) = state.sessions.get_for_tx(session_id) {
1316 self.encode_packet(&mut tx, Some(session))?;
1317
1318 Ok::<_, Error>(true)
1319 } else {
1320 error!(
1321 "TX packet has session ID {}, but no such session exists, dropping",
1322 session_id
1323 );
1324
1325 Ok(false)
1326 }
1327 })?;
1328
1329 if !encoded {
1330 continue;
1331 }
1332 }
1333
1334 Self::netw_send(send, tx.peer, &tx.buf[tx.payload_start..], false).await?;
1335
1336 if !tx.tx_info.retransmission {
1337 self.transport()
1338 .counters
1339 .lock(|counters| counters.borrow_mut().record_sent(&tx.header.proto));
1340 }
1341 }
1342 }
1343
1344 async fn process_rx<R, S>(&self, mut recv: R, send: &IfMutex<S>) -> Result<(), Error>
1345 where
1346 R: NetworkReceive,
1347 S: NetworkSend,
1348 {
1349 loop {
1350 trace!("Waiting for incoming packet");
1351
1352 recv.wait_available().await?;
1353
1354 let mut rx = self
1355 .matter
1356 .transport
1357 .get_if_rx(|packet| packet.buf.is_empty())
1358 .await;
1359 rx.clear_on_drop(true); unwrap!(rx.buf.resize_default(MAX_RX_BUF_SIZE));
1364
1365 let (len, peer) = Self::netw_recv(&mut recv, &mut rx.buf).await?;
1366
1367 rx.peer = peer;
1368 rx.buf.truncate(len);
1369 rx.payload_start = 0;
1370
1371 match self.handle_rx_packet(&mut rx, send).await {
1372 Ok(true) => {
1373 rx.clear_on_drop(false);
1375 }
1376 Ok(false) => {
1377 }
1379 Err(e) => {
1380 error!("UNEXPECTED RX ERROR: {:?}", e);
1382 }
1383 }
1384 }
1385 }
1386
1387 async fn process_orphaned(&self) -> Result<(), Error> {
1388 let mut rx_accept_timeout = pin!(self.process_accept_timeout_rx());
1389 let mut rx_orphaned = pin!(self.process_orphaned_rx());
1390 let mut exch_dropped = pin!(self.process_dropped_exchanges());
1391
1392 select3(&mut rx_accept_timeout, &mut rx_orphaned, &mut exch_dropped)
1393 .coalesce()
1394 .await
1395 }
1396
1397 async fn process_accept_timeout_rx(&self) -> Result<(), Error> {
1398 loop {
1399 trace!("Waiting for accept timeout");
1400
1401 let mut accept_timeout = pin!(self
1402 .matter
1403 .transport
1404 .rx
1405 .with(|packet| { self.handle_accept_timeout_rx_packet(packet).then_some(()) }));
1406
1407 let mut timer = pin!(Timer::after(embassy_time::Duration::from_millis(50)));
1408
1409 select(&mut accept_timeout, &mut timer).await;
1410 }
1411 }
1412
1413 async fn process_orphaned_rx(&self) -> Result<(), Error> {
1414 loop {
1415 trace!("Waiting for orphaned RX packets");
1416
1417 self.transport()
1418 .rx
1419 .with(|packet| self.handle_orphaned_rx_packet(packet).then_some(()))
1420 .await;
1421 }
1422 }
1423
1424 async fn process_dropped_exchanges(&self) -> Result<(), Error> {
1425 loop {
1426 trace!("Waiting for dropped exchanges");
1427
1428 let mut tx = self
1429 .matter
1430 .transport
1431 .get_if_tx(|packet| packet.buf.is_empty())
1432 .await;
1433 tx.clear_on_drop(true); let wait = match self.handle_dropped_exchange(&mut tx) {
1436 Ok(wait) => {
1437 tx.clear_on_drop(false);
1438 wait
1439 }
1440 Err(e) => {
1441 error!("UNEXPECTED RX ERROR: {:?}", e);
1442 false
1443 }
1444 };
1445
1446 drop(tx);
1447
1448 if wait {
1449 let mut timeout = pin!(Timer::after(embassy_time::Duration::from_millis(100)));
1450 let mut wait = pin!(self.transport().exchange_dropped.wait());
1451
1452 select(&mut timeout, &mut wait).await;
1453 }
1454 }
1455 }
1456
1457 async fn handle_rx_packet<const N: usize, S>(
1458 &self,
1459 packet: &mut Packet<N>,
1460 send: &IfMutex<S>,
1461 ) -> Result<bool, Error>
1462 where
1463 S: NetworkSend,
1464 {
1465 let result = self.decode_packet(packet);
1466 match result {
1467 Err(e) if matches!(e.code(), ErrorCode::Duplicate) => {
1468 if packet.header.plain.is_group_session() {
1469 mrp_log!(
1471 "\n>>RCV {}\n => Duplicate group message, discarding",
1472 packet
1473 );
1474 } else if !packet.peer.is_reliable()
1475 && !MessageMeta::from(&packet.header.proto).is_standalone_ack()
1476 {
1477 mrp_log!("\n>>RCV {}\n => Duplicate, sending ACK", packet);
1478
1479 self.matter.with_state(|state| {
1480 let session = unwrap!(state
1486 .sessions
1487 .get_for_rx(&packet.peer, &packet.header.plain));
1488
1489 let ack = packet.header.plain.ctr;
1490
1491 packet.header.proto.toggle_initiator();
1492 packet.header.proto.set_ack(Some(ack));
1493
1494 self.write_packet(packet, Some(session), None, true, |_| {
1495 Ok(Some(OpCode::MRPStandAloneAck.into()))
1496 })
1497 })?;
1498
1499 Self::netw_send(send, packet.peer, &packet.buf[packet.payload_start..], true)
1500 .await?;
1501 } else {
1502 mrp_log!("\n>>RCV {}\n => Duplicate, discarding", packet);
1503 }
1504 }
1505 Err(e) if matches!(e.code(), ErrorCode::NoSpaceSessions) => {
1506 if !packet.header.plain.is_encrypted()
1507 && MessageMeta::from(&packet.header.proto).is_new_session()
1508 {
1509 warn!(
1510 "\n>>RCV {}\n => No space for a new unencrypted session, sending Busy",
1511 packet
1512 );
1513
1514 let ack = packet.header.plain.ctr;
1515
1516 packet.header.proto.toggle_initiator();
1517 packet.header.proto.set_ack(Some(ack));
1518
1519 self.write_packet(packet, None, None, true, |wb| {
1520 sc_write(wb, SCStatusCodes::Busy, &[0xF4, 0x01])
1521 })?;
1522
1523 Self::netw_send(send, packet.peer, &packet.buf[packet.payload_start..], true)
1524 .await?;
1525
1526 if self.write_evict_some_session_packet(packet, true)? {
1527 Self::netw_send(
1528 send,
1529 packet.peer,
1530 &packet.buf[packet.payload_start..],
1531 true,
1532 )
1533 .await?;
1534 }
1535 } else {
1536 error!(
1537 "\n>>RCV {}\n => No space for a new encrypted session, dropping",
1538 packet
1539 );
1540 }
1541 }
1542 Err(e) if matches!(e.code(), ErrorCode::NoSpaceExchanges) => {
1543 error!(
1550 "\n>>RCV {}\n => No space for a new exchange, closing session",
1551 packet
1552 );
1553
1554 self.matter.with_state(|state| {
1555 let session_id = unwrap!(state
1561 .sessions
1562 .get_for_rx(&packet.peer, &packet.header.plain))
1563 .id;
1564
1565 packet.header.proto.exch_id = state.sessions.get_next_exch_id(&self.crypto)?;
1566 packet.header.proto.set_initiator();
1567
1568 let mut session = unwrap!(state.sessions.remove(session_id));
1570 self.transport().notify_session_removed();
1571
1572 self.write_packet(packet, Some(&mut session), None, true, |wb| {
1573 sc_write(wb, SCStatusCodes::CloseSession, &[])
1574 })
1575 })?;
1576
1577 Self::netw_send(send, packet.peer, &packet.buf[packet.payload_start..], true)
1578 .await?;
1579 }
1580 Err(e) if matches!(e.code(), ErrorCode::NoExchange) => {
1581 mrp_log!(
1582 "\n>>RCV {}\n => No valid exchange found, dropping",
1583 packet
1584 );
1585 }
1586 Err(e) if matches!(e.code(), ErrorCode::NoSession) => {
1587 warn!(
1596 "\n>>RCV {}\n => No valid session found, replying with SessionNotFound",
1597 packet
1598 );
1599
1600 packet.header.plain.sess_id = 0;
1608 packet.header.plain.set_src_nodeid(Some(0));
1609 packet.header.proto.unset_reliable();
1610 packet.header.proto.set_ack(None);
1611
1612 self.write_packet(packet, None, None, true, |wb| {
1613 sc_write(wb, SCStatusCodes::SessionNotFound, &[])
1614 })?;
1615
1616 Self::netw_send(send, packet.peer, &packet.buf[packet.payload_start..], true)
1617 .await?;
1618 }
1619 Err(e) => {
1620 error!("\n>>RCV {}\n => Error ({:?}), dropping", packet, e);
1621 }
1622 Ok(new_exchange) => {
1623 let meta = MessageMeta::from(&packet.header.proto);
1624
1625 if meta.is_standalone_ack() {
1626 debug!("\n>>RCV {}\n => Standalone Ack, dropping", packet);
1628 } else if meta.is_sc_status()
1629 && matches!(
1630 Self::is_close_session(&mut packet.buf[packet.payload_start..]),
1631 Ok(true)
1632 )
1633 {
1634 warn!(
1635 "\n>>RCV {}\n => Close session received, removing this session",
1636 packet
1637 );
1638
1639 self.matter.with_state(|state| {
1640 if let Some(session_id) = state
1641 .sessions
1642 .get_for_rx(&packet.peer, &packet.header.plain)
1643 .map(|sess| sess.id)
1644 {
1645 state.sessions.remove(session_id);
1646 self.transport().notify_session_removed();
1647 }
1648 });
1649 } else {
1650 self.transport()
1651 .counters
1652 .lock(|counters| counters.borrow_mut().record_recv(&packet.header.proto));
1653
1654 debug!(
1655 "\n>>RCV {}\n => Processing{}",
1656 packet,
1657 if new_exchange { " (new exchange)" } else { "" }
1658 );
1659
1660 #[cfg(feature = "log-tlv-payload")]
1661 debug!(
1662 "{}",
1663 Packet::<0>::display_payload(
1664 &packet.header.proto,
1665 &packet.buf[core::cmp::min(packet.payload_start, packet.buf.len())..]
1666 )
1667 );
1668
1669 #[cfg(not(feature = "log-tlv-payload"))]
1670 trace!(
1671 "{}",
1672 Packet::<0>::display_payload(
1673 &packet.header.proto,
1674 &packet.buf[core::cmp::min(packet.payload_start, packet.buf.len())..]
1675 )
1676 );
1677
1678 return Ok(true);
1679 }
1680 }
1681 }
1682
1683 Ok(false)
1684 }
1685
1686 fn handle_accept_timeout_rx_packet<const N: usize>(&self, packet: &mut Packet<N>) -> bool {
1687 if packet.buf.is_empty() {
1688 return false;
1689 }
1690
1691 self.matter.with_state(|state| {
1692 let Some(session) = state
1693 .sessions
1694 .get_for_rx(&packet.peer, &packet.header.plain)
1695 else {
1696 return false;
1697 };
1698
1699 let Some(exch_index) = session.get_exch_for_rx(&packet.header.proto) else {
1700 return false;
1701 };
1702
1703 let exchange = unwrap!(session.exchanges[exch_index].as_mut());
1705
1706 if !matches!(
1707 exchange.role,
1708 Role::Responder(ResponderState::AcceptPending)
1709 ) || !exchange.mrp.has_rx_timed_out(ACCEPT_TIMEOUT_MS)
1710 {
1711 return false;
1712 }
1713
1714 mrp_log!(
1715 "\n>>RCV {}\n => Accept timeout, marking exchange as dropped",
1716 packet
1717 );
1718
1719 exchange.role = Role::Responder(ResponderState::Dropped);
1720 packet.buf.clear();
1721 self.transport().exchange_dropped.notify();
1722
1723 true
1724 })
1725 }
1726
1727 fn handle_orphaned_rx_packet<const N: usize>(&self, packet: &mut Packet<N>) -> bool {
1728 if packet.buf.is_empty() {
1729 return false;
1730 }
1731
1732 self.matter.with_state(|state| {
1733 let Some(session) = state
1734 .sessions
1735 .get_for_rx(&packet.peer, &packet.header.plain)
1736 else {
1737 mrp_log!("\n>>RCV {}\n => No session, dropping", packet);
1738
1739 packet.buf.clear();
1740 return true;
1741 };
1742
1743 let Some(exch_index) = session.get_exch_for_rx(&packet.header.proto) else {
1744 mrp_log!("\n>>RCV {}\n => No exchange, dropping", packet);
1745
1746 packet.buf.clear();
1747 return true;
1748 };
1749
1750 let exchange = unwrap!(session.exchanges[exch_index].as_mut());
1752
1753 if exchange.role.is_dropped_state() {
1754 mrp_log!(
1755 "\n>>RCV {}\n => Owned by orphaned dropped {}, dropping packet",
1756 packet,
1757 ExchangeId::new(session.id, exch_index)
1758 );
1759
1760 packet.buf.clear();
1761 return true;
1762 }
1763
1764 false
1765 })
1766 }
1767
1768 fn handle_dropped_exchange<const N: usize>(
1769 &self,
1770 packet: &mut Packet<N>,
1771 ) -> Result<bool, Error> {
1772 self.matter.with_state(|state| {
1773 let exch = state
1774 .sessions
1775 .get_exch(|_, exch| exch.role.is_dropped_state() && exch.mrp.is_retrans_pending())
1776 .map(|(sess, exch_index)| (sess.id, exch_index, true))
1777 .or_else(|| {
1778 state
1779 .sessions
1780 .get_exch(|_, exch| {
1781 exch.role.is_dropped_state() && !exch.mrp.is_retrans_pending()
1782 })
1783 .map(|(sess, exch_index)| (sess.id, exch_index, false))
1784 });
1785
1786 let Some((session_id, exch_index, close_session)) = exch else {
1787 return Ok(exch.is_none());
1788 };
1789
1790 let exchange_id = ExchangeId::new(session_id, exch_index);
1791
1792 if close_session {
1793 error!(
1797 "Dropped exchange {}: Closing session because the exchange cannot be closed cleanly",
1798 exchange_id.display(unwrap!(state.sessions.get(session_id))) );
1800
1801 self.write_evict_session_packet(packet, &mut state.sessions, session_id, false)?;
1802 } else {
1803 let session = unwrap!(state.sessions.get(session_id));
1808 let exchange = unwrap!(session.exchanges[exch_index].as_mut());
1810
1811 if exchange.mrp.is_ack_pending() {
1812 self.write_packet(
1813 packet,
1814 Some(session),
1815 Some(exch_index),
1816 false,
1817 |_| Ok(Some(OpCode::MRPStandAloneAck.into())),
1818 )?;
1819 }
1820
1821 warn!("Dropped exchange {}: Closed", exchange_id.display(session));
1822 session.exchanges[exch_index] = None;
1823 }
1824
1825 Ok(exch.is_none())
1826 })
1827 }
1828
1829 pub(crate) async fn evict_some_session(&self) -> Result<(), Error> {
1830 let mut tx = self
1831 .matter
1832 .transport
1833 .get_if_tx(|packet| packet.buf.is_empty())
1834 .await;
1835 tx.clear_on_drop(true); let evicted = self.write_evict_some_session_packet(&mut tx, true)?;
1838
1839 if evicted {
1840 tx.clear_on_drop(false);
1842
1843 Ok(())
1844 } else {
1845 Err(ErrorCode::NoSpaceSessions.into())
1846 }
1847 }
1848
1849 fn decode_packet<const N: usize>(&self, packet: &mut Packet<N>) -> Result<bool, Error> {
1850 self.matter.with_state(|state| {
1851 packet.header.reset();
1852
1853 let mut pb = ParseBuf::new(&mut packet.buf[packet.payload_start..]);
1854 packet.header.plain.decode(&mut pb)?;
1855
1856 let set_payload = |packet: &mut Packet<N>, (start, end)| {
1857 packet.payload_start = start;
1858 packet.buf.truncate(end);
1859 };
1860
1861 if let Some(session) = state
1862 .sessions
1863 .get_for_rx(&packet.peer, &packet.header.plain)
1864 {
1865 let payload_range =
1868 session.decode_remaining(&self.crypto, &mut packet.header, pb)?;
1869 set_payload(packet, payload_range);
1870
1871 return session.post_recv(&packet.header);
1872 }
1873
1874 if !packet.header.plain.is_encrypted() {
1877 packet
1880 .header
1881 .decode_remaining(&self.crypto, None, 0, &mut pb)?;
1882 packet.header.proto.adjust_reliability(true, &packet.peer);
1883
1884 let payload_range = pb.slice_range();
1885 set_payload(packet, payload_range);
1886
1887 if MessageMeta::from(&packet.header.proto).is_new_session() {
1888 let mut rand = self.crypto.rand()?;
1892
1893 let session = state.sessions.add(
1894 rand.next_u32(),
1895 false,
1896 packet.peer,
1897 packet.header.plain.get_src_nodeid(),
1898 self.matter.dev_det(),
1899 )?;
1900
1901 return session.post_recv(&packet.header);
1903 }
1904 } else {
1905 #[cfg(feature = "groups")]
1906 if packet.header.plain.is_group_session() {
1907 let result = state.sessions.get_or_create_for_group_rx(
1909 &self.crypto,
1910 &state.fabrics,
1911 packet,
1912 self.matter.dev_det(),
1913 );
1914
1915 let (session, payload_range) = match result {
1916 Ok(ok) => ok,
1917 Err(e) => {
1918 self.observe_group_rx_failure(packet, &state.fabrics, &e);
1923
1924 return Err(e);
1925 }
1926 };
1927
1928 set_payload(packet, payload_range);
1929
1930 return session.post_recv(&packet.header);
1931 }
1932
1933 set_payload(packet, (0, 0));
1935 }
1936
1937 Err(ErrorCode::NoSession.into())
1938 })
1939 }
1940
1941 fn encode_packet<const N: usize>(
1942 &self,
1943 packet: &mut Packet<N>,
1944 session: Option<&mut Session>,
1945 ) -> Result<(), Error> {
1946 assert!(matches!(
1947 packet.tx_info.payload_state,
1948 TxPayloadState::NotEncoded { .. }
1949 ));
1950
1951 let payload_end = packet.buf.len();
1952
1953 if packet.tx_info.retransmission {
1954 mrp_log!(
1955 "\n<<SND {}\n => Re-sending",
1956 Packet::<0>::display(&packet.peer, &packet.header),
1957 );
1958 } else {
1959 debug!(
1960 "\n<<SND {}\n => Sending",
1961 Packet::<0>::display(&packet.peer, &packet.header),
1962 );
1963 }
1964
1965 #[cfg(feature = "log-tlv-payload")]
1966 debug!(
1967 "{}",
1968 Packet::<0>::display_payload(
1969 &packet.header.proto,
1970 &packet.buf[packet.payload_start..payload_end]
1971 )
1972 );
1973
1974 #[cfg(not(feature = "log-tlv-payload"))]
1975 trace!(
1976 "{}",
1977 Packet::<0>::display_payload(
1978 &packet.header.proto,
1979 &packet.buf[packet.payload_start..payload_end]
1980 )
1981 );
1982
1983 unwrap!(packet.buf.resize_default(N));
1984
1985 let mut wb = WriteBuf::new_with(&mut packet.buf, packet.payload_start, payload_end);
1986 if let Some(session) = session {
1987 session.encode(&self.crypto, &packet.header, &mut wb)?;
1988 } else {
1989 packet.header.encode(&self.crypto, None, 0, &mut wb)?;
1990 }
1991
1992 let encoded_payload_start = wb.get_start();
1993 let encoded_payload_end = wb.get_tail();
1994
1995 packet.payload_start = encoded_payload_start;
1996 packet.tx_info.payload_state = TxPayloadState::Encoded;
1997 packet.buf.truncate(encoded_payload_end);
1998
1999 Ok(())
2000 }
2001
2002 fn write_packet<const N: usize, F>(
2003 &self,
2004 packet: &mut Packet<N>,
2005 mut session: Option<&mut Session>,
2006 exchange_index: Option<usize>,
2007 encode: bool,
2008 payload_writer: F,
2009 ) -> Result<(), Error>
2010 where
2011 F: FnOnce(&mut WriteBuf) -> Result<Option<MessageMeta>, Error>,
2012 {
2013 unwrap!(packet.buf.resize_default(N));
2017
2018 let mut wb = WriteBuf::new_with(
2019 &mut packet.buf,
2020 PacketHdr::HDR_RESERVE,
2021 PacketHdr::HDR_RESERVE,
2022 );
2023
2024 let Some(meta) = payload_writer(&mut wb)? else {
2025 packet.buf.clear();
2026 return Ok(());
2027 };
2028
2029 let (start, end) = (wb.get_start(), wb.get_tail());
2030
2031 packet.payload_start = start;
2032 packet.buf.truncate(end);
2033
2034 meta.set_into(&mut packet.header.proto);
2035
2036 if let Some(session) = &mut session {
2037 packet.header.plain = Default::default();
2038
2039 let (peer, retransmission) = session.pre_send(
2040 exchange_index,
2041 &mut packet.header,
2042 self.transport().device_sai,
2043 self.transport().device_sii,
2044 )?;
2045
2046 packet.peer = peer;
2047 packet.tx_info.retransmission = retransmission;
2048 packet.tx_info.payload_state = TxPayloadState::NotEncoded {
2049 session_id: session.id,
2050 };
2051 } else {
2052 if packet.header.plain.is_encrypted()
2053 || packet.header.plain.get_src_nodeid().is_none()
2054 || packet.header.proto.is_reliable()
2055 {
2056 Err(ErrorCode::NoSession)?;
2058 }
2059
2060 let src_nodeid = packet.header.plain.get_src_nodeid();
2061
2062 packet.header.plain = Default::default();
2063
2064 packet.header.plain.sess_id = 0;
2065 packet.header.plain.ctr = 1;
2066 packet.header.plain.set_src_nodeid(None);
2067 packet.header.plain.set_dst_unicast_nodeid(src_nodeid);
2068
2069 packet.header.proto.unset_initiator();
2070 packet.header.proto.adjust_reliability(false, &packet.peer);
2071
2072 packet.tx_info.retransmission = false;
2073 packet.tx_info.payload_state = TxPayloadState::NotEncoded { session_id: 0 };
2074 }
2075
2076 if encode {
2077 self.encode_packet(packet, session)?;
2078 }
2079
2080 Ok(())
2081 }
2082
2083 fn write_evict_some_session_packet<const N: usize>(
2084 &self,
2085 packet: &mut Packet<N>,
2086 encode: bool,
2087 ) -> Result<bool, Error> {
2088 self.matter.with_state(|state| {
2089 let id = state
2090 .sessions
2091 .get_session_for_eviction()
2092 .map(|sess| sess.id);
2093 if let Some(id) = id {
2094 self.write_evict_session_packet(packet, &mut state.sessions, id, encode)?;
2095
2096 Ok(true)
2097 } else {
2098 error!("All sessions have active exchanges, cannot evict any session");
2099
2100 Ok(false)
2101 }
2102 })
2103 }
2104
2105 fn write_evict_session_packet<const N: usize>(
2106 &self,
2107 packet: &mut Packet<N>,
2108 sessions: &mut Sessions,
2109 id: u32,
2110 encode: bool,
2111 ) -> Result<(), Error> {
2112 packet.header.proto.exch_id = sessions.get_next_exch_id(&self.crypto)?;
2113 packet.header.proto.set_initiator();
2114
2115 let mut session = unwrap!(sessions.remove(id));
2117 self.transport().notify_session_removed();
2118
2119 debug!(
2120 "Evicting session {} [SID:{:x},RSID:{:x}]",
2121 session.id,
2122 session.get_local_sess_id(),
2123 session.get_peer_sess_id()
2124 );
2125
2126 self.write_packet(packet, Some(&mut session), None, encode, |wb| {
2127 sc_write(wb, SCStatusCodes::CloseSession, &[])
2128 })?;
2129
2130 Ok(())
2131 }
2132
2133 fn is_close_session(payload: &mut [u8]) -> Result<bool, Error> {
2134 let mut pb = ParseBuf::new(payload);
2135 let report = StatusReport::read(&mut pb)?;
2136
2137 let close_session = report.proto_id == PROTO_ID_SECURE_CHANNEL as u32
2138 && report.proto_code == SCStatusCodes::CloseSession as u16;
2139
2140 Ok(close_session)
2141 }
2142
2143 async fn netw_recv<R>(mut recv: R, buf: &mut [u8]) -> Result<(usize, Address), Error>
2144 where
2145 R: NetworkReceive,
2146 {
2147 match recv.recv_from(buf).await {
2148 Ok((len, addr)) => {
2149 trace!("\n>>RCV {} {}B:\n {}", addr, len, Bytes(&buf[..len]));
2150
2151 Ok((len, addr))
2152 }
2153 Err(e) => {
2154 error!("FAILED network recv: {:?}", e);
2155
2156 Err(e)
2157 }
2158 }
2159 }
2160
2161 async fn netw_send<S>(
2162 send: &IfMutex<S>,
2163 peer: Address,
2164 data: &[u8],
2165 system: bool,
2166 ) -> Result<(), Error>
2167 where
2168 S: NetworkSend,
2169 {
2170 match send.lock().await.send_to(data, peer).await {
2171 Ok(_) => {
2172 trace!(
2173 "\n<<SND {} {}B{}: {}",
2174 peer,
2175 data.len(),
2176 if system { " (system)" } else { "" },
2177 Bytes(data)
2178 );
2179
2180 Ok(())
2181 }
2182 Err(e) => {
2183 error!(
2184 "\n<<SND {} {}B{} !FAILED!: {:?}",
2185 peer,
2186 data.len(),
2187 if system { " (system)" } else { "" },
2188 e
2189 );
2190
2191 Ok(())
2195 }
2196 }
2197 }
2198
2199 #[inline(always)]
2200 const fn transport(&self) -> &Transport {
2201 self.matter.transport()
2202 }
2203}
2204
2205#[derive(Copy, Clone, Default, PartialEq, Eq, Debug, Hash)]
2206#[cfg_attr(feature = "defmt", derive(defmt::Format))]
2207pub(crate) enum TxPayloadState {
2208 #[default]
2209 Encoded,
2210 NotEncoded {
2211 session_id: u32,
2212 },
2213}
2214
2215#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
2216#[cfg_attr(feature = "defmt", derive(defmt::Format))]
2217pub(crate) struct TxInfo {
2218 pub(crate) retransmission: bool,
2219 pub(crate) payload_state: TxPayloadState,
2220}
2221
2222impl TxInfo {
2223 pub const fn new() -> Self {
2224 Self {
2225 retransmission: false,
2226 payload_state: TxPayloadState::Encoded,
2227 }
2228 }
2229}
2230
2231impl Default for TxInfo {
2232 fn default() -> Self {
2233 Self::new()
2234 }
2235}
2236
2237pub(crate) struct Packet<const N: usize> {
2242 pub(crate) peer: Address,
2243 pub(crate) header: PacketHdr,
2244 pub(crate) buf: PacketBuffer<N>,
2245 pub(crate) payload_start: usize,
2246 pub(crate) tx_info: TxInfo,
2247}
2248
2249impl<const N: usize> Packet<N> {
2250 #[inline(always)]
2251 pub(crate) const fn new() -> Self {
2252 Self {
2253 peer: Address::new(),
2254 header: PacketHdr::new(),
2255 buf: PacketBuffer::new(),
2256 payload_start: 0,
2257 tx_info: TxInfo::new(),
2258 }
2259 }
2260
2261 pub(crate) fn init() -> impl Init<Self> {
2262 init!(Self {
2263 peer: Address::new(),
2264 header: PacketHdr::new(),
2265 buf <- PacketBuffer::init(),
2266 payload_start: 0,
2267 tx_info: TxInfo::new(),
2268 })
2269 }
2270
2271 #[cfg(feature = "defmt")]
2272 pub fn display<'a>(
2273 peer: &'a Address,
2274 header: &'a PacketHdr,
2275 ) -> impl Display + defmt::Format + 'a {
2276 PacketInfo(peer, header)
2277 }
2278
2279 #[cfg(not(feature = "defmt"))]
2280 pub fn display<'a>(peer: &'a Address, header: &'a PacketHdr) -> impl Display + 'a {
2281 PacketInfo(peer, header)
2282 }
2283
2284 #[cfg(feature = "defmt")]
2285 pub fn display_payload<'a>(
2286 proto: &'a ProtoHdr,
2287 buf: &'a [u8],
2288 ) -> impl Display + defmt::Format + 'a {
2289 DetailedPacketInfo(proto, buf)
2290 }
2291
2292 #[cfg(not(feature = "defmt"))]
2293 pub fn display_payload<'a>(proto: &'a ProtoHdr, buf: &'a [u8]) -> impl Display + 'a {
2294 DetailedPacketInfo(proto, buf)
2295 }
2296
2297 fn fmt(f: &mut fmt::Formatter<'_>, peer: &Address, header: &PacketHdr) -> fmt::Result {
2298 write!(f, "{peer} {header}")?;
2299
2300 if header.proto.is_decoded() {
2301 let meta = MessageMeta::from(&header.proto);
2302
2303 write!(f, "\n {meta}")?;
2304 }
2305
2306 Ok(())
2307 }
2308
2309 #[cfg(feature = "defmt")]
2310 fn format(f: defmt::Formatter<'_>, peer: &Address, header: &PacketHdr) {
2311 defmt::write!(f, "{} {}", peer, header);
2312
2313 if header.proto.is_decoded() {
2314 let meta = MessageMeta::from(&header.proto);
2315
2316 defmt::write!(f, "\n {}", meta);
2317 }
2318 }
2319
2320 fn fmt_payload(f: &mut fmt::Formatter<'_>, proto: &ProtoHdr, buf: &[u8]) -> fmt::Result {
2321 let meta = MessageMeta::from(proto);
2322
2323 write!(f, "{meta}")?;
2324
2325 if meta.is_tlv() {
2326 write!(
2327 f,
2328 "; TLV:\n----------------\n{}\n----------------\n",
2329 TLVElement::new(buf)
2330 )?;
2331 } else {
2332 write!(
2333 f,
2334 "; Payload:\n----------------\n{:02x?}\n----------------\n",
2335 buf
2336 )?;
2337 }
2338
2339 Ok(())
2340 }
2341
2342 #[cfg(feature = "defmt")]
2343 fn format_payload(f: defmt::Formatter<'_>, proto: &ProtoHdr, buf: &[u8]) {
2344 let meta = MessageMeta::from(proto);
2345
2346 defmt::write!(f, "{}", meta);
2347
2348 if meta.is_tlv() {
2349 defmt::write!(
2350 f,
2351 "; TLV:\n----------------\n{}\n----------------\n",
2352 TLVElement::new(buf)
2353 );
2354 } else {
2355 defmt::write!(
2356 f,
2357 "; Payload:\n----------------\n{}\n----------------\n",
2358 crate::fmt::Bytes(buf)
2359 );
2360 }
2361 }
2362}
2363
2364impl<const N: usize> Display for Packet<N> {
2365 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2366 Self::fmt(f, &self.peer, &self.header)
2367 }
2368}
2369
2370#[cfg(feature = "defmt")]
2371impl<const N: usize> defmt::Format for Packet<N> {
2372 fn format(&self, f: defmt::Formatter<'_>) {
2373 Self::format(f, &self.peer, &self.header)
2374 }
2375}
2376
2377struct PacketInfo<'a>(&'a Address, &'a PacketHdr);
2378
2379impl Display for PacketInfo<'_> {
2380 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2381 Packet::<0>::fmt(f, self.0, self.1)
2382 }
2383}
2384
2385#[cfg(feature = "defmt")]
2386impl defmt::Format for PacketInfo<'_> {
2387 fn format(&self, f: defmt::Formatter<'_>) {
2388 Packet::<0>::format(f, self.0, self.1)
2389 }
2390}
2391
2392struct DetailedPacketInfo<'a>(&'a ProtoHdr, &'a [u8]);
2393
2394impl Display for DetailedPacketInfo<'_> {
2395 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2396 Packet::<0>::fmt_payload(f, self.0, self.1)
2397 }
2398}
2399
2400#[cfg(feature = "defmt")]
2401impl defmt::Format for DetailedPacketInfo<'_> {
2402 fn format(&self, f: defmt::Formatter<'_>) {
2403 Packet::<0>::format_payload(f, self.0, self.1)
2404 }
2405}
2406
2407pub(crate) struct PacketBuffer<const N: usize> {
2417 buffer: crate::utils::storage::Vec<u8, N>,
2418}
2419
2420impl<const N: usize> PacketBuffer<N> {
2421 pub const fn new() -> Self {
2422 Self {
2423 buffer: crate::utils::storage::Vec::new(),
2424 }
2425 }
2426
2427 pub fn init() -> impl Init<Self> {
2428 init!(Self {
2429 buffer <- crate::utils::storage::Vec::init(),
2430 })
2431 }
2432
2433 pub fn buf_mut(&mut self) -> &mut crate::utils::storage::Vec<u8, N> {
2434 &mut self.buffer
2435 }
2436
2437 pub fn buf_ref(&self) -> &crate::utils::storage::Vec<u8, N> {
2438 &self.buffer
2439 }
2440}
2441
2442impl<const N: usize> Deref for PacketBuffer<N> {
2443 type Target = crate::utils::storage::Vec<u8, N>;
2444
2445 fn deref(&self) -> &Self::Target {
2446 self.buf_ref()
2447 }
2448}
2449
2450impl<const N: usize> DerefMut for PacketBuffer<N> {
2451 fn deref_mut(&mut self) -> &mut Self::Target {
2452 self.buf_mut()
2453 }
2454}
2455
2456pub(crate) struct PacketAccess<'a, const N: usize>(IfMutexGuard<'a, Packet<N>>, bool);
2464
2465impl<const N: usize> PacketAccess<'_, N> {
2466 pub fn clear_on_drop(&mut self, clear: bool) {
2467 self.1 = clear;
2468 }
2469}
2470
2471impl<const N: usize> Deref for PacketAccess<'_, N> {
2472 type Target = Packet<N>;
2473
2474 fn deref(&self) -> &Self::Target {
2475 &self.0
2476 }
2477}
2478
2479impl<const N: usize> DerefMut for PacketAccess<'_, N> {
2480 fn deref_mut(&mut self) -> &mut Self::Target {
2481 &mut self.0
2482 }
2483}
2484
2485impl<const N: usize> Drop for PacketAccess<'_, N> {
2486 fn drop(&mut self) {
2487 if self.1 {
2488 self.buf.clear();
2489 }
2490 }
2491}
2492
2493impl<const N: usize> Display for PacketAccess<'_, N> {
2494 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2495 self.0.fmt(f)
2496 }
2497}
2498
2499pub struct PacketBufferExternalAccess<'a, const N: usize>(pub(crate) &'a IfMutex<Packet<N>>);
2504
2505impl<const N: usize> Buffers<[u8]> for PacketBufferExternalAccess<'_, N> {
2506 type Buffer<'b>
2507 = ExternalPacketBuffer<'b, N>
2508 where
2509 Self: 'b;
2510
2511 async fn get(&self) -> Option<ExternalPacketBuffer<'_, N>> {
2512 let mut packet = self.0.lock_if(|packet| packet.buf.is_empty()).await;
2513
2514 unwrap!(packet.buf.resize_default(N));
2517
2518 Some(ExternalPacketBuffer(packet))
2519 }
2520
2521 fn get_immediate(&self) -> Option<Self::Buffer<'_>> {
2522 self.0
2523 .try_lock_if(|packet| packet.buf.is_empty())
2524 .ok()
2525 .map(|mut packet| {
2526 unwrap!(packet.buf.resize_default(N));
2529
2530 ExternalPacketBuffer(packet)
2531 })
2532 }
2533}
2534
2535pub struct ExternalPacketBuffer<'a, const N: usize>(IfMutexGuard<'a, Packet<N>>);
2537
2538impl<const N: usize> Deref for ExternalPacketBuffer<'_, N> {
2539 type Target = [u8];
2540
2541 fn deref(&self) -> &Self::Target {
2542 &self.0.buf
2543 }
2544}
2545
2546impl<const N: usize> DerefMut for ExternalPacketBuffer<'_, N> {
2547 fn deref_mut(&mut self) -> &mut Self::Target {
2548 &mut self.0.buf
2549 }
2550}
2551
2552impl<const N: usize> Drop for ExternalPacketBuffer<'_, N> {
2553 fn drop(&mut self) {
2554 self.0.buf.clear();
2555 }
2556}
2557
2558#[derive(Default, Clone, Eq, PartialEq, Debug, Hash)]
2560#[cfg_attr(feature = "defmt", derive(defmt::Format))]
2561pub struct MessageCounters {
2562 pub im_sent: u32,
2564 pub im_received: u32,
2566}
2567
2568impl MessageCounters {
2569 const fn new() -> Self {
2570 Self {
2571 im_sent: 0,
2572 im_received: 0,
2573 }
2574 }
2575
2576 fn record_sent(&mut self, hdr: &ProtoHdr) {
2577 if hdr.proto_id == PROTO_ID_INTERACTION_MODEL {
2578 self.im_sent = self.im_sent.saturating_add(1);
2579 }
2580 }
2581
2582 fn record_recv(&mut self, hdr: &ProtoHdr) {
2583 if hdr.proto_id == PROTO_ID_INTERACTION_MODEL {
2584 self.im_received = self.im_received.saturating_add(1);
2585 }
2586 }
2587}
2588
2589#[cfg(test)]
2590mod tests {
2591 use super::*;
2592 use crate::crypto::test_only_crypto;
2593 use crate::dm::devices::test::{TEST_DEV_ATT, TEST_DEV_COMM, TEST_DEV_DET};
2594
2595 fn test_matter() -> Matter<'static> {
2596 Matter::new(&TEST_DEV_DET, TEST_DEV_COMM, &TEST_DEV_ATT, 0)
2597 }
2598
2599 #[test]
2600 fn test_create_plaintext_session() {
2601 let matter = test_matter();
2602 let crypto = test_only_crypto();
2603 let peer = Address::new();
2604
2605 let session_id = matter
2606 .transport
2607 .create_plaintext_session(&matter, &crypto, peer)
2608 .unwrap();
2609
2610 matter.with_state(|state| {
2611 let session = state.sessions.get(session_id).unwrap();
2612
2613 assert_eq!(session.id, session_id);
2614 assert!(!session.is_encrypted());
2615 assert_eq!(session.get_peer_node_id(), None);
2616 assert_eq!(*session.get_session_mode(), session::SessionMode::PlainText);
2617 });
2618 }
2619
2620 #[test]
2621 fn test_initiate_plaintext_now_creates_initiator_exchange() {
2622 let matter = test_matter();
2623 let crypto = test_only_crypto();
2624 let peer = Address::new();
2625
2626 let exchange = matter
2627 .transport
2628 .try_initiate_plaintext(&matter, &crypto, peer)
2629 .unwrap();
2630
2631 exchange
2632 .with_state(|state| {
2633 let sess = exchange.id().session(&mut state.sessions);
2634 let exch = exchange.id().exch(sess);
2635
2636 assert!(matches!(exch.role, Role::Initiator(_)));
2637 assert_eq!(sess.id, exchange.id().session_id());
2638 Ok(())
2639 })
2640 .unwrap();
2641 }
2642}
2643
2644#[cfg(test)]
2645mod resolve_tests {
2646 use core::net::{IpAddr, Ipv4Addr, SocketAddr};
2647
2648 use futures_lite::future::{block_on, zip};
2649
2650 use crate::error::ErrorCode;
2651 use crate::test::test_matter;
2652 use crate::transport::network::mdns::{DottedName, MdnsRemoteService};
2653 use crate::transport::network::MatterRemoteService;
2654
2655 fn op_service() -> MatterRemoteService {
2656 MatterRemoteService::Operational {
2657 compressed_fabric_id: 0x1122,
2658 node_id: 0x3344,
2659 }
2660 }
2661
2662 #[test]
2666 fn resolve_rendezvous_delivers_answer() {
2667 let matter = test_matter();
2668 let service = op_service();
2669
2670 let resolved = block_on(async {
2671 let resolver = matter.transport().resolve(service.clone(), 5_000);
2672
2673 let responder = async {
2674 let picked = matter.transport().wait_mdns_resolve_request().await;
2675 assert_eq!(picked, service);
2676
2677 let mut name = heapless::String::<128>::new();
2678 service.instance_name(&mut name);
2679
2680 let answer = MdnsRemoteService {
2681 instance_name: DottedName(name.as_str()),
2682 port: Some(1234),
2683 addrs: [IpAddr::V4(Ipv4Addr::new(10, 0, 0, 5))].into_iter(),
2684 txt: [("SII", "300"), ("SAI", "4000"), ("SAT", "5000")].into_iter(),
2685 scope_id: 0,
2686 };
2687
2688 matter.transport().try_deposit_mdns_resolve(&answer);
2689 };
2690
2691 let (node, ()) = zip(resolver, responder).await;
2692 node
2693 })
2694 .unwrap();
2695
2696 assert_eq!(
2697 resolved.addr,
2698 SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 5)), 1234)
2699 );
2700 assert_eq!(resolved.sii, Some(300));
2702 assert_eq!(resolved.sai, Some(4000));
2703 assert_eq!(resolved.sat, Some(5000));
2704 }
2705
2706 #[test]
2709 fn resolve_times_out_and_releases_slot() {
2710 let matter = test_matter();
2711
2712 let err = block_on(matter.transport().resolve(op_service(), 50)).unwrap_err();
2713 assert!(matches!(err.code(), ErrorCode::NotFound));
2714
2715 let err = block_on(matter.transport().resolve(op_service(), 50)).unwrap_err();
2716 assert!(matches!(err.code(), ErrorCode::NotFound));
2717 }
2718
2719 #[test]
2722 fn deposit_without_request_is_noop() {
2723 let matter = test_matter();
2724
2725 let mut name = heapless::String::<128>::new();
2726 op_service().instance_name(&mut name);
2727 let answer = MdnsRemoteService {
2728 instance_name: DottedName(name.as_str()),
2729 port: Some(1234),
2730 addrs: [IpAddr::V4(Ipv4Addr::new(10, 0, 0, 9))].into_iter(),
2731 txt: core::iter::empty::<(&str, &str)>(),
2732 scope_id: 0,
2733 };
2734 matter.transport().try_deposit_mdns_resolve(&answer);
2735
2736 let err = block_on(matter.transport().resolve(op_service(), 50)).unwrap_err();
2737 assert!(matches!(err.code(), ErrorCode::NotFound));
2738 }
2739}
2740
2741#[cfg(test)]
2742mod browse_tests {
2743 use core::net::{IpAddr, Ipv4Addr, SocketAddr};
2744
2745 use futures_lite::future::{block_on, zip};
2746
2747 use crate::error::ErrorCode;
2748 use crate::test::test_matter;
2749 use crate::transport::network::mdns::{CommissionableFilter, DottedName, MdnsRemoteService};
2750 use crate::transport::network::Address;
2751
2752 #[test]
2756 fn browse_rendezvous_delivers_first_match() {
2757 let matter = test_matter();
2758
2759 let filter = CommissionableFilter {
2760 discriminator: Some(0xA5A),
2761 vendor_id: Some(0xFFF1),
2762 ..Default::default()
2763 };
2764
2765 let found = block_on(async {
2766 let browser = matter
2767 .transport()
2768 .browse_commissionable(&filter, &[], 5_000);
2769
2770 let responder = async {
2771 let picked = matter.transport().wait_mdns_browse_request().await;
2772 assert_eq!(picked, filter);
2773
2774 let other = MdnsRemoteService {
2776 instance_name: DottedName("0000000000000001._matterc._udp.local"),
2777 port: Some(5540),
2778 addrs: [IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))].into_iter(),
2779 txt: [("D", "2650"), ("VP", "9999+1"), ("CM", "1")].into_iter(),
2780 scope_id: 0,
2781 };
2782 matter.transport().try_deposit_mdns_browse(&other);
2783
2784 let answer = MdnsRemoteService {
2786 instance_name: DottedName("00000000ABCD1234._matterc._udp.local"),
2787 port: Some(5541),
2788 addrs: [IpAddr::V4(Ipv4Addr::new(10, 0, 0, 7))].into_iter(),
2789 txt: [("D", "2650"), ("VP", "65521+42"), ("CM", "1")].into_iter(),
2790 scope_id: 0,
2791 };
2792 matter.transport().try_deposit_mdns_browse(&answer);
2793 };
2794
2795 let (found, ()) = zip(browser, responder).await;
2796 found
2797 })
2798 .unwrap();
2799
2800 assert_eq!(
2801 found,
2802 (
2803 Address::Udp(SocketAddr::new(
2804 IpAddr::V4(Ipv4Addr::new(10, 0, 0, 7)),
2805 5541
2806 )),
2807 0x00000000ABCD1234,
2808 )
2809 );
2810 }
2811
2812 #[test]
2814 fn browse_times_out_and_releases_slot() {
2815 let matter = test_matter();
2816 let filter = CommissionableFilter {
2817 short_discriminator: Some(0xA),
2818 ..Default::default()
2819 };
2820
2821 let err = block_on(matter.transport().browse_commissionable(&filter, &[], 50)).unwrap_err();
2822 assert!(matches!(err.code(), ErrorCode::NotFound));
2823
2824 let err = block_on(matter.transport().browse_commissionable(&filter, &[], 50)).unwrap_err();
2825 assert!(matches!(err.code(), ErrorCode::NotFound));
2826 }
2827
2828 #[test]
2831 fn browse_exclude_steps_to_next_match() {
2832 let matter = test_matter();
2833
2834 let filter = CommissionableFilter {
2836 short_discriminator: Some(0xA),
2837 ..Default::default()
2838 };
2839
2840 let found = block_on(async {
2842 let browser = matter
2843 .transport()
2844 .browse_commissionable(&filter, &[0x1111], 5_000);
2845
2846 let responder = async {
2847 matter.transport().wait_mdns_browse_request().await;
2848
2849 let node_a = MdnsRemoteService {
2850 instance_name: DottedName("0000000000001111._matterc._udp.local"),
2851 port: Some(5540),
2852 addrs: [IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))].into_iter(),
2853 txt: [("D", "2578"), ("CM", "1")].into_iter(), scope_id: 0,
2855 };
2856 matter.transport().try_deposit_mdns_browse(&node_a);
2858
2859 let node_b = MdnsRemoteService {
2860 instance_name: DottedName("0000000000002222._matterc._udp.local"),
2861 port: Some(5541),
2862 addrs: [IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2))].into_iter(),
2863 txt: [("D", "2815"), ("CM", "1")].into_iter(), scope_id: 0,
2865 };
2866 matter.transport().try_deposit_mdns_browse(&node_b);
2867 };
2868
2869 let (found, ()) = zip(browser, responder).await;
2870 found
2871 })
2872 .unwrap();
2873
2874 assert_eq!(
2875 found,
2876 (
2877 Address::Udp(SocketAddr::new(
2878 IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
2879 5541
2880 )),
2881 0x2222,
2882 )
2883 );
2884 }
2885}