pub struct Commissioner<'a, C>where
C: Crypto,{ /* private fields */ }Expand description
Stateful commissioner.
Holds the references needed for the whole flow so individual steps
don’t have to take them. &mut NocGenerator because each
commission() call mutably borrows the generator’s scratch buffer
to write the device NOC into; &mut [u8] buf is a caller-owned
scratch slice used to stage the fabric’s RCAC and ICAC bytes
across the on-wire async calls (the fabric record itself can only
be borrowed inside Matter::with_state, which doesn’t compose
with await).
The controller’s fabric is expected to already be in
matter.state.fabrics at the given fab_idx — the caller installs
it once via crate::fabric::Fabrics::add before constructing any
commissioner. A single Commissioner instance can then be reused to
commission any number of devices onto that fabric.
Implementations§
Source§impl<'a, C> Commissioner<'a, C>where
C: Crypto,
impl<'a, C> Commissioner<'a, C>where
C: Crypto,
Sourcepub const fn new(
matter: &'a Matter<'a>,
crypto: C,
fab_idx: NonZero<u8>,
noc_generator: &'a mut NocGenerator<'a>,
buf: &'a mut [u8],
) -> Commissioner<'a, C>
pub const fn new( matter: &'a Matter<'a>, crypto: C, fab_idx: NonZero<u8>, noc_generator: &'a mut NocGenerator<'a>, buf: &'a mut [u8], ) -> Commissioner<'a, C>
Create a commissioner bound to a Matter stack, crypto backend,
an already-installed fabric (fab_idx), an already-constructed
NOC generator that signs against the chain stored on that
fabric, and a scratch buffer.
buf is used to copy the fabric’s RCAC and (optionally) ICAC
bytes out of the locked fabric table so they can be passed to
the asynchronous AddTrustedRootCertificate / AddNOC invokes.
It must be at least crate::cert::MAX_CERT_TLV_LEN bytes; the
commissioner sequences the two transfers (RCAC first, then ICAC
re-uses the same slot) so a single-cert worth of memory is
enough.
Sourcepub const fn fab_idx(&self) -> NonZero<u8>
pub const fn fab_idx(&self) -> NonZero<u8>
Index of the controller’s fabric in matter.state.fabrics. The
caller picked this when installing the fabric; the commissioner
simply propagates it (e.g. into CommissionResult callers
build on top).
Sourcepub async fn commission(
&mut self,
peer_addr: Address,
passcode: u32,
opts: &CommissionOptions,
device_node_id: u64,
validity: Validity,
) -> Result<CommissionResult, Error>
pub async fn commission( &mut self, peer_addr: Address, passcode: u32, opts: &CommissionOptions, device_node_id: u64, validity: Validity, ) -> Result<CommissionResult, Error>
Phase 1 — drive ArmFailSafe through AddNOC over PASE.
Pre-condition: PASE handshake against the device has completed
successfully on matter’s transport. The function locates that
PASE session by the (fab=0, peer=0, secure=true) lookup tuple
every step uses — it implicitly assumes a single in-flight PASE
session, which is the case in practice for a controller driving
one device at a time.
device_node_id is the NodeID the caller wishes to assign to
the device on the controller’s fabric. validity is the NOC’s
validity window — typically crate::cert::gen::VALID_FOREVER
for long-lived deployments, or a bounded window for short-lived
re-issuance. The NOC’s ASN.1 serial number is derived from the
NodeID (see NocGenerator::generate).
On success the device has accepted our RCAC + NOC and assigned
us a CommissionResult::fabric_index, but its fail-safe is
still armed and PASE is still live. Phase 2
(Self::complete_via_case) finalises commissioning over
CASE; if the caller doesn’t run it before the fail-safe expires
the device rolls back.
Sourcepub async fn complete_via_case(
&mut self,
peer_addr: Address,
phase1: &CommissionResult,
) -> Result<(), Error>
pub async fn complete_via_case( &mut self, peer_addr: Address, phase1: &CommissionResult, ) -> Result<(), Error>
Phase 2 — establish CASE against the device’s freshly-installed
operational identity and invoke CommissioningComplete over it.
peer_addr is the device’s operational endpoint. In production
it’s discovered via _matter._tcp mDNS; in tests / examples it
can be the same address PASE used, since the device announces on
the same UDP port post-AddNOC.
Steps:
- Open a fresh plaintext exchange to
peer_addrand run [CaseInitiator::initiate] (Sigma1 → Sigma2 → Sigma3 → StatusReport). On success the new CASE session is keyed inmatter.state.sessionsat(fab_idx, device_node_id, secure=true). - Open a CASE-secured exchange on that session and invoke
GeneralCommissioning::CommissioningComplete. The device disarms its fail-safe and persists the new fabric.
Sourcepub async fn complete_via_case_operational(
&mut self,
phase1: &CommissionResult,
) -> Result<(), Error>
pub async fn complete_via_case_operational( &mut self, phase1: &CommissionResult, ) -> Result<(), Error>
Phase 2, resolving the device’s operational address via mDNS.
Identical to Self::complete_via_case except that, instead of being
handed a fixed peer_addr, it looks up the device’s operational endpoint
via _matter._tcp mDNS from (fabric, device_node_id) (using
Exchange::initiate_plaintext_operational).
This is the production phase-2 path: after phase 1 the device may only be reachable at a different address than PASE used - most notably when the device was commissioned over BLE and has since joined its operational (Wi-Fi / Thread) network, where its operational IP is not known until it announces itself. It requires the mDNS backend to be running (so the resolve request is answered), and the device to have joined the network and started announcing operationally.
Auto Trait Implementations§
impl<'a, C> !RefUnwindSafe for Commissioner<'a, C>
impl<'a, C> !Send for Commissioner<'a, C>
impl<'a, C> !Sync for Commissioner<'a, C>
impl<'a, C> !UnwindSafe for Commissioner<'a, C>
impl<'a, C> Freeze for Commissioner<'a, C>where
C: Freeze,
impl<'a, C> Unpin for Commissioner<'a, C>where
C: Unpin,
impl<'a, C> UnsafeUnpin for Commissioner<'a, C>where
C: UnsafeUnpin,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more