1818#include < platform/internal/CHIPDeviceLayerInternal.h>
1919#include < platform/internal/NFCCommissioningManager.h>
2020
21+ #include < app/server/Server.h> // nogncheck
22+ #include < transport/SecureSession.h> // nogncheck
23+ #include < transport/raw/PeerAddress.h> // nogncheck
24+
2125#include < platform/nrfconnect/NFCCommissioningManagerImpl.h>
2226
2327#include < lib/support/CHIPMem.h>
@@ -153,27 +157,105 @@ CHIP_ERROR NFCCommissioningManagerImpl::_Init()
153157 ChipLogDetail (DeviceLayer, " Initializing NFC Commissioning Manager" );
154158
155159 ResetSession ();
156- StartRawIsoDepTagEmulation ();
157160 ReturnErrorOnFailure (PlatformMgr ().AddEventHandler (OnPlatformEvent, reinterpret_cast <intptr_t >(this )));
158161
159- return mRawIsoDepStarted ? CHIP_NO_ERROR : CHIP_ERROR_INTERNAL ;
162+ return CHIP_NO_ERROR ;
160163}
161164
162165void NFCCommissioningManagerImpl::OnPlatformEvent (const ChipDeviceEvent * event, intptr_t arg)
163166{
164- if (event->Type == DeviceEventType::kCommissioningComplete )
167+ auto * self = reinterpret_cast <NFCCommissioningManagerImpl *>(arg);
168+
169+ switch (event->Type )
165170 {
166- reinterpret_cast <NFCCommissioningManagerImpl *>(arg)->HandleCommissioningComplete ();
171+ case DeviceEventType::kServerReady :
172+ case DeviceEventType::kDnssdInitialized :
173+ self->StartNfcCommissioning ();
174+ break ;
175+ case DeviceEventType::kCommissioningComplete :
176+ self->HandleCommissioningComplete ();
177+ break ;
178+ case DeviceEventType::kFailSafeTimerExpired :
179+ self->HandleFailSafeTimerExpired ();
180+ break ;
181+ case DeviceEventType::kSecureSessionEstablished :
182+ self->HandleSecureSessionEstablished (event);
183+ break ;
184+ default :
185+ break ;
186+ }
187+ }
188+
189+ void NFCCommissioningManagerImpl::ScheduledStartNfcCommissioning (intptr_t arg)
190+ {
191+ auto * self = reinterpret_cast <NFCCommissioningManagerImpl *>(arg);
192+ VerifyOrReturn (self != nullptr );
193+ self->StartNfcCommissioning ();
194+ }
195+
196+ void NFCCommissioningManagerImpl::StartNfcCommissioning ()
197+ {
198+ VerifyOrReturn (!mRawIsoDepStarted );
199+
200+ if (Server::GetInstance ().GetFabricTable ().FabricCount () != 0 )
201+ {
202+ ChipLogProgress (DeviceLayer, " Device already commissioned: NFC commissioning will stay disabled" );
203+ return ;
204+ }
205+
206+ StartRawIsoDepTagEmulation ();
207+ if (!mRawIsoDepStarted )
208+ {
209+ ChipLogError (DeviceLayer, " Failed to start NFC tag emulation for commissioning" );
167210 }
168211}
169212
170213void NFCCommissioningManagerImpl::HandleCommissioningComplete ()
171214{
215+ mBlockMatterAidSelection = false ;
216+ mNfcEmulationPausedForFailSafe = false ;
172217 ChipLogProgress (DeviceLayer, " Commissioning complete: stopping NFC commissioning" );
173- PlatformMgr ().RemoveEventHandler (OnPlatformEvent, reinterpret_cast <intptr_t >(this ));
174218 NFCCommissioningMgr ().Shutdown ();
175219}
176220
221+ void NFCCommissioningManagerImpl::HandleFailSafeTimerExpired ()
222+ {
223+ VerifyOrReturn (mBlockMatterAidSelection || mNfcEmulationPausedForFailSafe );
224+
225+ mBlockMatterAidSelection = false ;
226+ mNfcEmulationPausedForFailSafe = false ;
227+
228+ if (Server::GetInstance ().GetFabricTable ().FabricCount () != 0 )
229+ {
230+ return ;
231+ }
232+
233+ TEMPORARY_RETURN_IGNORED ConfigureOnboardingPayload ();
234+ ChipLogProgress (DeviceLayer, " Fail-safe expired: NFC commissioning is available again" );
235+ }
236+
237+ void NFCCommissioningManagerImpl::HandleSecureSessionEstablished (const ChipDeviceEvent * event)
238+ {
239+ VerifyOrReturn (event != nullptr );
240+
241+ const auto & sessionEstablished = event->SecureSessionEstablished ;
242+ if (sessionEstablished.TransportType != static_cast <uint8_t >(Transport::Type::kNfc ))
243+ {
244+ return ;
245+ }
246+
247+ if (sessionEstablished.SecureSessionType != static_cast <uint8_t >(Transport::SecureSession::Type::kPASE ))
248+ {
249+ return ;
250+ }
251+
252+ SessionLock lock;
253+ mBlockMatterAidSelection = true ;
254+ TEMPORARY_RETURN_IGNORED ClearOnboardingPayload ();
255+ ChipLogProgress (DeviceLayer,
256+ " NFC PASE session established: blocking NFC commissioning until fail-safe completes or commissioning succeeds" );
257+ }
258+
177259CHIP_ERROR NFCCommissioningManagerImpl::ConfigureOnboardingPayload ()
178260{
179261 PayloadContents payload;
@@ -193,7 +275,14 @@ CHIP_ERROR NFCCommissioningManagerImpl::ConfigureOnboardingPayload()
193275 MutableCharSpan qrCode (qrCodeBuffer);
194276 ReturnErrorOnFailure (QRCodeBasicSetupPayloadGenerator (payload).payloadBase38Representation (qrCode));
195277
196- return SetOnboardingPayload (qrCode.data (), qrCode.size ());
278+ ReturnErrorOnFailure (SetOnboardingPayload (qrCode.data (), qrCode.size ()));
279+
280+ // ConfigureOnboardingPayload() runs before Server::Init(); defer NFC start until the fabric
281+ // table is loaded. kServerReady is not reliable on all networking paths (e.g. Wi-Fi builds
282+ // without an IPv6 mDNS listener at boot), so schedule an explicit start attempt as well.
283+ TEMPORARY_RETURN_IGNORED PlatformMgr ().ScheduleWork (ScheduledStartNfcCommissioning, reinterpret_cast <intptr_t >(this ));
284+
285+ return CHIP_NO_ERROR ;
197286}
198287
199288void NFCCommissioningManagerImpl::StartRawIsoDepTagEmulation ()
@@ -219,15 +308,35 @@ void NFCCommissioningManagerImpl::StartRawIsoDepTagEmulation()
219308 ChipLogProgress (DeviceLayer, " NFC NDEF Tag emulation started" );
220309}
221310
311+ void NFCCommissioningManagerImpl::StopRawIsoDepTagEmulation ()
312+ {
313+ VerifyOrReturn (mRawIsoDepStarted );
314+
315+ nfc_t4t_emulation_stop ();
316+ nfc_t4t_done ();
317+ mRawIsoDepStarted = false ;
318+ }
319+
320+ void NFCCommissioningManagerImpl::PauseNfcTagEmulationForFailSafe ()
321+ {
322+ VerifyOrReturn (!mNfcEmulationPausedForFailSafe );
323+
324+ mNfcEmulationPausedForFailSafe = true ;
325+ StopRawIsoDepTagEmulation ();
326+ ChipLogProgress (DeviceLayer, " NFC tag emulation paused until fail-safe completes" );
327+ }
328+
329+ bool NFCCommissioningManagerImpl::IsSessionIdle () const
330+ {
331+ return mSelectedApplication == SelectedApplication::kNone && !mOutgoingContinuationPending && mApduLength == 0 &&
332+ mApduFragmentCount == 0 && !mAwaitingApplicationResponse && mOutgoingMessage .IsNull ();
333+ }
334+
222335void NFCCommissioningManagerImpl::_Shutdown ()
223336{
224337 ChipLogDetail (DeviceLayer, " Shutting down NFC Commissioning Manager" );
225- if (mRawIsoDepStarted )
226- {
227- nfc_t4t_emulation_stop ();
228- nfc_t4t_done ();
229- mRawIsoDepStarted = false ;
230- }
338+ PlatformMgr ().RemoveEventHandler (OnPlatformEvent, reinterpret_cast <intptr_t >(this ));
339+ StopRawIsoDepTagEmulation ();
231340 ResetSession (/* notifyAborted = */ true );
232341}
233342
@@ -378,6 +487,11 @@ void NFCCommissioningManagerImpl::OnT4TEvent(void * context, nfc_t4t_event_t eve
378487 return ;
379488 }
380489
490+ if (self->mNfcEmulationPausedForFailSafe )
491+ {
492+ return ;
493+ }
494+
381495 switch (event)
382496 {
383497 case NFC_T4T_EVENT_FIELD_ON :
@@ -399,17 +513,46 @@ void NFCCommissioningManagerImpl::OnT4TEvent(void * context, nfc_t4t_event_t eve
399513
400514void NFCCommissioningManagerImpl::HandleFieldOn ()
401515{
516+ SessionLock lock;
517+
518+ if (mNfcEmulationPausedForFailSafe )
519+ {
520+ ChipLogProgress (DeviceLayer, " NFC field detected while fail-safe pause is active: ignoring" );
521+ return ;
522+ }
523+
524+ if (mBlockMatterAidSelection && IsSessionIdle ())
525+ {
526+ ChipLogProgress (DeviceLayer, " NFC field detected while fail-safe is active: pausing tag emulation" );
527+ ResetSessionState ();
528+ PauseNfcTagEmulationForFailSafe ();
529+ return ;
530+ }
531+
402532 ChipLogDetail (DeviceLayer, " NFC field detected: an NFC Reader/Writer is polling" );
403533 // A field-on event always precedes a fresh ISO-DEP activation: start with a clean slate.
404- SessionLock lock;
405534 ResetSessionState ();
406535}
407536
408537void NFCCommissioningManagerImpl::HandleFieldOff ()
409538{
410- ChipLogDetail (DeviceLayer, " NFC field lost: the NFC Reader/Writer moved away" );
411539 SessionLock lock;
540+
541+ if (IsSessionIdle ())
542+ {
543+ if (mNfcEmulationPausedForFailSafe || !mBlockMatterAidSelection )
544+ {
545+ return ;
546+ }
547+ }
548+
549+ ChipLogProgress (DeviceLayer, " NFC field lost: the NFC Reader/Writer moved away" );
412550 ResetSessionState (/* notifyAborted = */ true );
551+
552+ if (mBlockMatterAidSelection && mRawIsoDepStarted )
553+ {
554+ PauseNfcTagEmulationForFailSafe ();
555+ }
413556}
414557
415558void NFCCommissioningManagerImpl::HandleDataTransmitted ()
@@ -553,6 +696,17 @@ void NFCCommissioningManagerImpl::HandleSelectByNameCommand(const uint8_t * aid,
553696
554697 if (aidLength == sizeof (kNdefAid ) && memcmp (aid, kNdefAid , sizeof (kNdefAid )) == 0 )
555698 {
699+ if (mBlockMatterAidSelection )
700+ {
701+ mSelectedApplication = SelectedApplication::kNone ;
702+ mSelectedFile = SelectedFile::kNone ;
703+ SendStatusResponse (kSwConditionsNotSatisfied1 , kSwConditionsNotSatisfied2 );
704+ ChipLogProgress (DeviceLayer,
705+ " Rejecting NDEF Tag Application selection: commissioning fail-safe is active, waiting for fail-safe "
706+ " to complete" );
707+ return ;
708+ }
709+
556710 mSelectedApplication = SelectedApplication::kNdef ;
557711 SendStatusResponse (kSwSuccess1 , kSwSuccess2 );
558712 ChipLogProgress (DeviceLayer, " NDEF Tag Application selected" );
@@ -594,6 +748,16 @@ void NFCCommissioningManagerImpl::HandleSelectByFileIdCommand(const uint8_t * fi
594748
595749void NFCCommissioningManagerImpl::HandleMatterAidSelected ()
596750{
751+ if (mBlockMatterAidSelection )
752+ {
753+ mSelectedApplication = SelectedApplication::kNone ;
754+ mSelectedFile = SelectedFile::kNone ;
755+ SendStatusResponse (kSwConditionsNotSatisfied1 , kSwConditionsNotSatisfied2 );
756+ ChipLogProgress (DeviceLayer,
757+ " Rejecting Matter AID selection: commissioning fail-safe is active, waiting for fail-safe to complete" );
758+ return ;
759+ }
760+
597761 mSelectedApplication = SelectedApplication::kMatter ;
598762
599763 uint16_t discriminator = 0 ;
@@ -634,6 +798,13 @@ void NFCCommissioningManagerImpl::HandleMatterAidSelected()
634798
635799void NFCCommissioningManagerImpl::HandleReadBinaryCommand (const uint8_t * apdu, size_t apduLength)
636800{
801+ if (mBlockMatterAidSelection )
802+ {
803+ SendStatusResponse (kSwConditionsNotSatisfied1 , kSwConditionsNotSatisfied2 );
804+ ChipLogProgress (DeviceLayer, " Rejecting READ BINARY: commissioning fail-safe is active, waiting for fail-safe to complete" );
805+ return ;
806+ }
807+
637808 if (mSelectedApplication != SelectedApplication::kNdef || mSelectedFile == SelectedFile::kNone )
638809 {
639810 SendStatusResponse (kSwConditionsNotSatisfied1 , kSwConditionsNotSatisfied2 );
0 commit comments