diff --git a/Cargo.toml b/Cargo.toml
index cb6c6a9..f6bdf53 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@ readme = "README.md"
 rust-version = "1.77"
 
 [patch.crates-io]
-rs-matter = { git = "https://github.com/ivmarkov/rs-matter", branch = "wifi" }
+rs-matter = { git = "https://github.com/ivmarkov/rs-matter", branch = "tip" }
 #rs-matter = { path = "../rs-matter/rs-matter" }
 #edge-nal = { git = "https://github.com/ivmarkov/edge-net" }
 #edge-nal = { path = "../edge-net/edge-nal" }
@@ -25,7 +25,7 @@ rs-matter = { git = "https://github.com/ivmarkov/rs-matter", branch = "wifi" }
 [features]
 default = []
 zeroconf = ["os", "rs-matter/zeroconf"]
-os = ["backtrace", "rs-matter/os", "rs-matter/mbedtls", "embassy-time/std", "embassy-time/generic-queue"]
+os = ["backtrace", "rs-matter/os", "rs-matter/rustcrypto", "embassy-time/std", "embassy-time/generic-queue"]
 backtrace = ["std", "rs-matter/backtrace"]
 std = ["alloc", "rs-matter/std", "edge-nal-std"]
 alloc = ["embedded-svc/alloc"]
@@ -45,6 +45,7 @@ edge-nal-std = { version = "0.3", optional = true }
 edge-mdns = { version = "0.3", optional = true }
 
 [target.'cfg(all(unix, not(target_os = "espidf")))'.dependencies]
+bitflags = "2"
 nix = { version = "0.27", features = ["net"], optional = true }
 
 [dev-dependencies]
diff --git a/README.md b/README.md
index 1807c8b..40052f0 100644
--- a/README.md
+++ b/README.md
@@ -18,9 +18,7 @@ Instantiate it and then call `MatterStack::<...>::run(...)`.
 
 **Flexibility**.
 
-Using `MatterStack<...>` hard-codes the following:
-* _One large future_: The Matter stack is assembled as one large future which is not `Send`. Using an executor to poll that future together with others is still possible, but the executor should be a local one (i.e. Tokio's `LocalSet`, `async_executor::LocalExecutor` and so on).
-* _Allocation strategy_: a number of large-ish buffers are const-allocated inside the `MatterStack` struct. This allows the whole stack to be statically-allocated with `ConstStaticCell` - yet - that would eat up 20 to 60K of your flash size, depending on the selected max number of subscriptions, exchange buffers and so on. A different allocation strategy might be provided in future.
+The Matter stack is assembled as one large future which is not `Send`. Using an executor to poll that future together with others is still possible, but the executor should be a local one (i.e. Tokio's `LocalSet`, `async_executor::LocalExecutor` and so on).
 
 ## The examples are STD-only?
 
@@ -69,6 +67,7 @@ use rs_matter::data_model::objects::{Dataver, Endpoint, HandlerCompat, Node};
 use rs_matter::data_model::system_model::descriptor;
 use rs_matter::error::Error;
 use rs_matter::secure_channel::spake2p::VerifierData;
+use rs_matter::utils::init::InitMaybeUninit;
 use rs_matter::utils::select::Coalesce;
 use rs_matter::CommissioningData;
 
@@ -76,7 +75,7 @@ use rs_matter_stack::netif::UnixNetif;
 use rs_matter_stack::persist::{DirKvBlobStore, KvBlobBuf, KvPersist};
 use rs_matter_stack::EthMatterStack;
 
-use static_cell::ConstStaticCell;
+use static_cell::StaticCell;
 
 #[path = "dev_att/dev_att.rs"]
 mod dev_att;
@@ -88,9 +87,24 @@ fn main() -> Result<(), Error> {
 
     info!("Starting...");
 
-    // Take the Matter stack (can be done only once),
+    // Initialize the Matter stack (can be done only once),
     // as we'll run it in this thread
-    let stack = MATTER_STACK.take();
+    let stack = MATTER_STACK
+        .uninit()
+        .init_with(EthMatterStack::init_default(
+            &BasicInfoConfig {
+                vid: 0xFFF1,
+                pid: 0x8000,
+                hw_ver: 2,
+                sw_ver: 1,
+                sw_ver_str: "1",
+                serial_no: "aabbccdd",
+                device_name: "MyLight",
+                product_name: "ACME Light",
+                vendor_name: "ACME",
+            },
+            &DEV_ATT,
+        ));
 
     // Our "light" on-off cluster.
     // Can be anything implementing `rs_matter::data_model::AsyncHandler`
@@ -162,21 +176,9 @@ fn main() -> Result<(), Error> {
 
 /// The Matter stack is allocated statically to avoid
 /// program stack blowups.
-static MATTER_STACK: ConstStaticCell<EthMatterStack<KvBlobBuf<()>>> =
-    ConstStaticCell::new(EthMatterStack::new_default(
-        &BasicInfoConfig {
-            vid: 0xFFF1,
-            pid: 0x8000,
-            hw_ver: 2,
-            sw_ver: 1,
-            sw_ver_str: "1",
-            serial_no: "aabbccdd",
-            device_name: "MyLight",
-            product_name: "ACME Light",
-            vendor_name: "ACME",
-        },
-        &dev_att::HardCodedDevAtt::new(),
-    ));
+static MATTER_STACK: StaticCell<EthMatterStack<KvBlobBuf<()>>> = StaticCell::new();
+
+const DEV_ATT: dev_att::HardCodedDevAtt = dev_att::HardCodedDevAtt::new();
 
 /// Endpoint 0 (the root endpoint) always runs
 /// the hidden Matter system clusters, so we pick ID=1
diff --git a/examples/light.rs b/examples/light.rs
index 5985517..3781907 100644
--- a/examples/light.rs
+++ b/examples/light.rs
@@ -18,16 +18,16 @@ use rs_matter::data_model::device_types::DEV_TYPE_ON_OFF_LIGHT;
 use rs_matter::data_model::objects::{Dataver, Endpoint, HandlerCompat, Node};
 use rs_matter::data_model::system_model::descriptor;
 use rs_matter::error::Error;
-use rs_matter::secure_channel::spake2p::VerifierData;
+use rs_matter::utils::init::InitMaybeUninit;
 use rs_matter::utils::select::Coalesce;
-use rs_matter::utils::std_mutex::StdRawMutex;
-use rs_matter::CommissioningData;
+use rs_matter::utils::sync::blocking::raw::StdRawMutex;
+use rs_matter::BasicCommData;
 
 use rs_matter_stack::modem::DummyLinuxModem;
 use rs_matter_stack::persist::{DirKvBlobStore, KvBlobBuf, KvPersist};
 use rs_matter_stack::WifiBleMatterStack;
 
-use static_cell::ConstStaticCell;
+use static_cell::StaticCell;
 
 #[path = "dev_att/dev_att.rs"]
 mod dev_att;
@@ -39,9 +39,28 @@ fn main() -> Result<(), Error> {
 
     info!("Starting...");
 
-    // Take the Matter stack (can be done only once),
+    // Initialize the Matter stack (can be done only once),
     // as we'll run it in this thread
-    let stack = MATTER_STACK.take();
+    let stack = MATTER_STACK
+        .uninit()
+        .init_with(WifiBleMatterStack::init_default(
+            &BasicInfoConfig {
+                vid: 0xFFF1,
+                pid: 0x8001,
+                hw_ver: 2,
+                sw_ver: 1,
+                sw_ver_str: "1",
+                serial_no: "aabbccdd",
+                device_name: "MyLight",
+                product_name: "ACME Light",
+                vendor_name: "ACME",
+            },
+            BasicCommData {
+                password: 20202021,
+                discriminator: 3840,
+            },
+            &DEV_ATT,
+        ));
 
     // Our "light" on-off cluster.
     // Can be anything implementing `rs_matter::data_model::AsyncHandler`
@@ -75,11 +94,6 @@ fn main() -> Result<(), Error> {
         KvPersist::new_wifi_ble(DirKvBlobStore::new_default(), stack),
         // A Linux-specific modem using BlueZ
         DummyLinuxModem::default(),
-        // Hard-coded for demo purposes
-        CommissioningData {
-            verifier: VerifierData::new_with_pw(123456, stack.matter().rand()),
-            discriminator: 250,
-        },
         // Our `AsyncHandler` + `AsyncMetadata` impl
         (NODE, handler),
         // No user future to run
@@ -116,21 +130,9 @@ fn main() -> Result<(), Error> {
 /// The Matter stack is allocated statically to avoid
 /// program stack blowups.
 /// It is also a mandatory requirement when the `WifiBle` stack variation is used.
-static MATTER_STACK: ConstStaticCell<WifiBleMatterStack<StdRawMutex, KvBlobBuf<()>>> =
-    ConstStaticCell::new(WifiBleMatterStack::new_default(
-        &BasicInfoConfig {
-            vid: 0xFFF1,
-            pid: 0x8000,
-            hw_ver: 2,
-            sw_ver: 1,
-            sw_ver_str: "1",
-            serial_no: "aabbccdd",
-            device_name: "MyLight",
-            product_name: "ACME Light",
-            vendor_name: "ACME",
-        },
-        &dev_att::HardCodedDevAtt::new(),
-    ));
+static MATTER_STACK: StaticCell<WifiBleMatterStack<StdRawMutex, KvBlobBuf<()>>> = StaticCell::new();
+
+const DEV_ATT: dev_att::HardCodedDevAtt = dev_att::HardCodedDevAtt::new();
 
 /// Endpoint 0 (the root endpoint) always runs
 /// the hidden Matter system clusters, so we pick ID=1
diff --git a/examples/light_eth.rs b/examples/light_eth.rs
index 0a5aa41..31e6047 100644
--- a/examples/light_eth.rs
+++ b/examples/light_eth.rs
@@ -14,6 +14,7 @@ use core::pin::pin;
 use embassy_futures::select::select;
 use embassy_time::{Duration, Timer};
 
+use env_logger::Target;
 use log::info;
 
 use rs_matter::data_model::cluster_basic_information::BasicInfoConfig;
@@ -22,29 +23,50 @@ use rs_matter::data_model::device_types::DEV_TYPE_ON_OFF_LIGHT;
 use rs_matter::data_model::objects::{Dataver, Endpoint, HandlerCompat, Node};
 use rs_matter::data_model::system_model::descriptor;
 use rs_matter::error::Error;
-use rs_matter::secure_channel::spake2p::VerifierData;
+use rs_matter::utils::init::InitMaybeUninit;
 use rs_matter::utils::select::Coalesce;
-use rs_matter::CommissioningData;
+use rs_matter::BasicCommData;
 
 use rs_matter_stack::netif::UnixNetif;
 use rs_matter_stack::persist::{DirKvBlobStore, KvBlobBuf, KvPersist};
 use rs_matter_stack::EthMatterStack;
 
-use static_cell::ConstStaticCell;
+use static_cell::StaticCell;
 
 #[path = "dev_att/dev_att.rs"]
 mod dev_att;
 
 fn main() -> Result<(), Error> {
-    env_logger::init_from_env(
+    env_logger::Builder::from_env(
         env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
-    );
+    )
+    .target(Target::Stdout)
+    .init();
 
     info!("Starting...");
 
-    // Take the Matter stack (can be done only once),
+    // Initialize the Matter stack (can be done only once),
     // as we'll run it in this thread
-    let stack = MATTER_STACK.take();
+    let stack = MATTER_STACK
+        .uninit()
+        .init_with(EthMatterStack::init_default(
+            &BasicInfoConfig {
+                vid: 0xFFF1,
+                pid: 0x8001,
+                hw_ver: 2,
+                sw_ver: 1,
+                sw_ver_str: "1",
+                serial_no: "aabbccdd",
+                device_name: "MyLight",
+                product_name: "ACME Light",
+                vendor_name: "ACME",
+            },
+            BasicCommData {
+                password: 20202021,
+                discriminator: 3840,
+            },
+            &DEV_ATT,
+        ));
 
     // Our "light" on-off cluster.
     // Can be anything implementing `rs_matter::data_model::AsyncHandler`
@@ -78,11 +100,6 @@ fn main() -> Result<(), Error> {
         KvPersist::new_eth(DirKvBlobStore::new_default(), stack),
         // Will try to find a default network interface
         UnixNetif::default(),
-        // Hard-coded for demo purposes
-        CommissioningData {
-            verifier: VerifierData::new_with_pw(123456, stack.matter().rand()),
-            discriminator: 250,
-        },
         // Our `AsyncHandler` + `AsyncMetadata` impl
         (NODE, handler),
         // No user future to run
@@ -116,21 +133,9 @@ fn main() -> Result<(), Error> {
 
 /// The Matter stack is allocated statically to avoid
 /// program stack blowups.
-static MATTER_STACK: ConstStaticCell<EthMatterStack<KvBlobBuf<()>>> =
-    ConstStaticCell::new(EthMatterStack::new_default(
-        &BasicInfoConfig {
-            vid: 0xFFF1,
-            pid: 0x8000,
-            hw_ver: 2,
-            sw_ver: 1,
-            sw_ver_str: "1",
-            serial_no: "aabbccdd",
-            device_name: "MyLight",
-            product_name: "ACME Light",
-            vendor_name: "ACME",
-        },
-        &dev_att::HardCodedDevAtt::new(),
-    ));
+static MATTER_STACK: StaticCell<EthMatterStack<KvBlobBuf<()>>> = StaticCell::new();
+
+const DEV_ATT: dev_att::HardCodedDevAtt = dev_att::HardCodedDevAtt::new();
 
 /// Endpoint 0 (the root endpoint) always runs
 /// the hidden Matter system clusters, so we pick ID=1
diff --git a/src/eth.rs b/src/eth.rs
index 41746ff..6e359d2 100644
--- a/src/eth.rs
+++ b/src/eth.rs
@@ -15,7 +15,7 @@ use rs_matter::data_model::sdm::nw_commissioning::EthNwCommCluster;
 use rs_matter::data_model::sdm::{ethernet_nw_diagnostics, nw_commissioning};
 use rs_matter::error::Error;
 use rs_matter::pairing::DiscoveryCapabilities;
-use rs_matter::CommissioningData;
+use rs_matter::utils::init::{init, Init};
 
 use crate::netif::Netif;
 use crate::network::{Embedding, Network};
@@ -32,18 +32,26 @@ use crate::MatterStack;
 ///
 /// The expectation is nevertheless that for production use-cases
 /// the `Eth` network would really only be used for Ethernet.
-pub struct Eth<E = ()>(E);
+pub struct Eth<E = ()> {
+    embedding: E,
+}
 
 impl<E> Network for Eth<E>
 where
     E: Embedding + 'static,
 {
-    const INIT: Self = Self(E::INIT);
+    const INIT: Self = Self { embedding: E::INIT };
 
     type Embedding = E;
 
     fn embedding(&self) -> &Self::Embedding {
-        &self.0
+        &self.embedding
+    }
+
+    fn init() -> impl Init<Self> {
+        init!(Self {
+            embedding <- E::init(),
+        })
     }
 }
 
@@ -85,6 +93,16 @@ where
         Ok(())
     }
 
+    /// Enable basic commissioning over IP (mDNS) by setting up a PASE session and printing the pairing code and QR code.
+    ///
+    /// The method will return an error if there is not enough space in the buffer to print the pairing code and QR code
+    /// or if the PASE session could not be set up (due to another PASE session already being active, for example).
+    pub async fn enable_basic_commissioning(&self) -> Result<(), Error> {
+        self.matter()
+            .enable_basic_commissioning(DiscoveryCapabilities::IP, 0)
+            .await // TODO
+    }
+
     /// Run the Matter stack for Ethernet network.
     ///
     /// Parameters:
@@ -97,7 +115,6 @@ where
         &self,
         persist: P,
         netif: I,
-        dev_comm: CommissioningData,
         handler: H,
         user: U,
     ) -> Result<(), Error>
@@ -111,14 +128,14 @@ where
 
         let mut user = pin!(user);
 
-        self.run_with_netif(
-            persist,
-            netif,
-            Some((dev_comm, DiscoveryCapabilities::new(true, false, false))),
-            handler,
-            &mut user,
-        )
-        .await
+        // TODO persist.load().await?;
+
+        if !self.is_commissioned().await? {
+            self.enable_basic_commissioning().await?;
+        }
+
+        self.run_with_netif(persist, netif, handler, &mut user)
+            .await
     }
 }
 
diff --git a/src/lib.rs b/src/lib.rs
index 0e0cb24..aba6a6b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -26,15 +26,15 @@ use rs_matter::data_model::sdm::dev_att::DevAttDataFetcher;
 use rs_matter::data_model::subscriptions::Subscriptions;
 use rs_matter::error::{Error, ErrorCode};
 use rs_matter::mdns::{Mdns, MdnsService};
-use rs_matter::pairing::DiscoveryCapabilities;
 use rs_matter::respond::DefaultResponder;
 use rs_matter::transport::network::{NetworkReceive, NetworkSend};
-use rs_matter::utils::buf::PooledBuffers;
 use rs_matter::utils::epoch::Epoch;
+use rs_matter::utils::init::{init, Init};
 use rs_matter::utils::rand::Rand;
 use rs_matter::utils::select::Coalesce;
-use rs_matter::utils::signal::Signal;
-use rs_matter::{CommissioningData, Matter, MATTER_PORT};
+use rs_matter::utils::storage::pooled::PooledBuffers;
+use rs_matter::utils::sync::Signal;
+use rs_matter::{BasicCommData, Matter, MATTER_PORT};
 
 use crate::netif::{Netif, NetifConf};
 use crate::network::Network;
@@ -124,10 +124,12 @@ where
     #[inline(always)]
     pub const fn new_default(
         dev_det: &'a BasicInfoConfig,
+        dev_comm: BasicCommData,
         dev_att: &'a dyn DevAttDataFetcher,
     ) -> Self {
         Self::new(
             dev_det,
+            dev_comm,
             dev_att,
             MdnsType::default(),
             rs_matter::utils::epoch::sys_epoch,
@@ -140,6 +142,7 @@ where
     #[inline(always)]
     pub const fn new(
         dev_det: &'a BasicInfoConfig,
+        dev_comm: BasicCommData,
         dev_att: &'a dyn DevAttDataFetcher,
         mdns: MdnsType<'a>,
         epoch: Epoch,
@@ -148,6 +151,7 @@ where
         Self {
             matter: Matter::new(
                 dev_det,
+                dev_comm,
                 dev_att,
                 mdns.mdns_service(),
                 epoch,
@@ -162,6 +166,51 @@ where
         }
     }
 
+    /// Create a new `MatterStack` instance.
+    #[cfg(feature = "std")]
+    #[allow(clippy::large_stack_frames)]
+    pub fn init_default(
+        dev_det: &'a BasicInfoConfig,
+        dev_comm: BasicCommData,
+        dev_att: &'a dyn DevAttDataFetcher,
+    ) -> impl Init<Self> {
+        Self::init(
+            dev_det,
+            dev_comm,
+            dev_att,
+            MdnsType::default(),
+            rs_matter::utils::epoch::sys_epoch,
+            rs_matter::utils::rand::sys_rand,
+        )
+    }
+
+    #[allow(clippy::large_stack_frames)]
+    pub fn init(
+        dev_det: &'a BasicInfoConfig,
+        dev_comm: BasicCommData,
+        dev_att: &'a dyn DevAttDataFetcher,
+        mdns: MdnsType<'a>,
+        epoch: Epoch,
+        rand: Rand,
+    ) -> impl Init<Self> {
+        init!(Self {
+            matter <- Matter::init(
+                dev_det,
+                dev_comm,
+                dev_att,
+                mdns.mdns_service(),
+                epoch,
+                rand,
+                MATTER_PORT,
+            ),
+            buffers <- PooledBuffers::init(0),
+            subscriptions <- Subscriptions::init(),
+            network <- N::init(),
+            mdns,
+            netif_conf: Signal::new(None),
+        })
+    }
+
     /// A utility method to replace the initial mDNS implementation with another one.
     ///
     /// Useful in particular with `MdnsType::Provided()`, where the user would still like
@@ -235,6 +284,11 @@ where
             .await
     }
 
+    /// Return information whether the Matter instance is already commissioned.
+    pub async fn is_commissioned(&self) -> Result<bool, Error> {
+        Ok(self.matter().is_commissioned())
+    }
+
     /// This method is a specialization of `run_with_transport` over the UDP transport (both IPv4 and IPv6).
     /// It calls `run_with_transport` and in parallel runs the mDNS service.
     ///
@@ -244,14 +298,12 @@ where
     /// Parameters:
     /// - `persist` - a user-provided `Persist` implementation
     /// - `netif` - a user-provided `Netif` implementation
-    /// - `dev_comm` - the commissioning data and discovery capabilities
     /// - `handler` - a user-provided DM handler implementation
     /// - `user` - a user-provided future that will be polled only when the netif interface is up
     pub async fn run_with_netif<'d, H, P, I, U>(
         &self,
         mut persist: P,
         netif: I,
-        dev_comm: Option<(CommissioningData, DiscoveryCapabilities)>,
         handler: H,
         user: U,
     ) -> Result<(), Error>
@@ -313,7 +365,6 @@ where
                 udp::Udp(send),
                 udp::Udp(recv),
                 &mut persist,
-                dev_comm.clone(),
                 &handler
             ));
             let mut mdns = pin!(self.run_builtin_mdns(&netif, &netif_conf));
@@ -358,7 +409,6 @@ where
         send: S,
         recv: R,
         persist: P,
-        dev_comm: Option<(CommissioningData, DiscoveryCapabilities)>,
         handler: H,
     ) -> Result<(), Error>
     where
@@ -372,7 +422,7 @@ where
 
         let mut psm = pin!(self.run_psm(persist));
         let mut respond = pin!(self.run_responder(handler));
-        let mut transport = pin!(self.run_transport(send, recv, dev_comm));
+        let mut transport = pin!(self.run_transport(send, recv));
 
         select3(&mut psm, &mut respond, &mut transport)
             .coalesce()
@@ -473,9 +523,10 @@ where
                         &Host {
                             id: 0,
                             hostname: &hostname,
-                            ip: _netif_conf.ipv4.octets(),
-                            ipv6: Some(_netif_conf.ipv6.octets()),
+                            ip: _netif_conf.ipv4,
+                            ipv6: _netif_conf.ipv6,
                         },
+                        Some(_netif_conf.ipv4),
                         Some(_netif_conf.interface),
                     )
                     .await?;
@@ -493,17 +544,12 @@ where
         Ok(())
     }
 
-    async fn run_transport<S, R>(
-        &self,
-        send: S,
-        recv: R,
-        dev_comm: Option<(CommissioningData, DiscoveryCapabilities)>,
-    ) -> Result<(), Error>
+    async fn run_transport<S, R>(&self, send: S, recv: R) -> Result<(), Error>
     where
         S: NetworkSend,
         R: NetworkReceive,
     {
-        self.matter().run(send, recv, dev_comm).await?;
+        self.matter().run_transport(send, recv).await?;
 
         Ok(())
     }
diff --git a/src/mdns.rs b/src/mdns.rs
index b562dc2..7cea48f 100644
--- a/src/mdns.rs
+++ b/src/mdns.rs
@@ -14,18 +14,18 @@
 //! Using `edge-mdns` solves this problem by providing a general-purpose mDNS which can be
 //! shared between the `rs-matter` stack and other - user-specific use cases.
 
-use core::cell::RefCell;
-
 use edge_mdns::host::Service;
 
 use embassy_sync::blocking_mutex::raw::RawMutex;
-use embassy_sync::blocking_mutex::Mutex;
 use embassy_sync::signal::Signal;
 
 use rs_matter::data_model::cluster_basic_information::BasicInfoConfig;
 use rs_matter::error::{Error, ErrorCode};
 use rs_matter::mdns::{Mdns, ServiceMode};
+use rs_matter::utils::blmutex::Mutex;
 use rs_matter::utils::buf::BufferAccess;
+use rs_matter::utils::init::{init, Init};
+use rs_matter::utils::refcell::RefCell;
 
 const MAX_MATTER_SERVICES: usize = 4;
 const MAX_MATTER_SERVICE_NAME_LEN: usize = 40;
@@ -68,7 +68,7 @@ where
     services: Mutex<
         M,
         RefCell<
-            heapless::Vec<
+            rs_matter::utils::vec::Vec<
                 (heapless::String<MAX_MATTER_SERVICE_NAME_LEN>, ServiceMode),
                 MAX_MATTER_SERVICES,
             >,
@@ -87,11 +87,21 @@ where
         Self {
             dev_det,
             matter_port,
-            services: Mutex::new(RefCell::new(heapless::Vec::new())),
+            services: Mutex::new(RefCell::new(rs_matter::utils::vec::Vec::new())),
             broadcast_signal: Signal::new(),
         }
     }
 
+    /// Create an in-place initializer for `MatterServices`
+    pub fn init(dev_det: &'a BasicInfoConfig<'a>, matter_port: u16) -> impl Init<Self> {
+        init!(Self {
+            dev_det,
+            matter_port,
+            services <- Mutex::init(RefCell::init(rs_matter::utils::vec::Vec::init())),
+            broadcast_signal: Signal::new(),
+        })
+    }
+
     fn reset(&self) {
         self.services.lock(|services| {
             services.borrow_mut().clear();
diff --git a/src/netif.rs b/src/netif.rs
index 7cd5327..7077609 100644
--- a/src/netif.rs
+++ b/src/netif.rs
@@ -151,14 +151,87 @@ where
 mod unix {
     use alloc::string::String;
 
+    use bitflags::bitflags;
+
     use embassy_time::{Duration, Timer};
-    use nix::{
-        net::if_::InterfaceFlags,
-        sys::socket::{SockaddrIn6, SockaddrStorage},
-    };
+
+    use nix::net::if_::InterfaceFlags;
+    use nix::sys::socket::{SockaddrIn6, SockaddrStorage};
 
     use super::{Netif, NetifConf};
 
+    bitflags! {
+        /// DefaultNetif is a set of flags that can be used to filter network interfaces
+        /// when calling `default_if`
+        #[repr(transparent)]
+        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+        pub struct NetifSearchFlags: u16 {
+            /// Consider only interfaces which have the Loopback flag set
+            const LOOPBACK = 0x0001;
+            /// Consider only interfaces which do not have the Loopback flag set
+            const NON_LOOPBACK = 0x0002;
+            /// Consider only interfaces which have the Point-to-Point flag set
+            const PEER_TO_PEER = 0x0004;
+            /// Consider only interfaces which do not have the Point-to-Point flag set
+            const NON_PEER_TO_PEER = 0x0008;
+            /// Consider only interfaces which have the Broadcast flag set
+            const BROADCAST = 0x0010;
+            /// Consider only interfaces which do have an IPv4 address assigned
+            const IPV4 = 0x0020;
+            /// Consider only interfaces which do have an IPv6 address assigned
+            const IPV6 = 0x0040;
+            /// Consider only interfaces which do have a Link-Local IPv6 address assigned
+            const IPV6_LINK_LOCAL = 0x0080;
+            /// Consider only interfaces which do have a non-Link-Local IPv6 address assigned
+            const IPV6_NON_LINK_LOCAL = 0x0100;
+        }
+    }
+
+    impl NetifSearchFlags {
+        fn contains_if_flags(&self) -> InterfaceFlags {
+            let mut flags = InterfaceFlags::empty();
+
+            if self.contains(NetifSearchFlags::LOOPBACK) {
+                flags |= InterfaceFlags::IFF_LOOPBACK;
+            }
+
+            if self.contains(NetifSearchFlags::PEER_TO_PEER) {
+                flags |= InterfaceFlags::IFF_POINTOPOINT;
+            }
+
+            if self.contains(NetifSearchFlags::BROADCAST) {
+                flags |= InterfaceFlags::IFF_BROADCAST;
+            }
+
+            flags
+        }
+
+        fn not_contains_if_flags(&self) -> InterfaceFlags {
+            let mut flags = InterfaceFlags::empty();
+
+            if self.contains(NetifSearchFlags::NON_LOOPBACK) {
+                flags |= InterfaceFlags::IFF_LOOPBACK;
+            }
+
+            if self.contains(NetifSearchFlags::NON_PEER_TO_PEER) {
+                flags |= InterfaceFlags::IFF_POINTOPOINT;
+            }
+
+            flags
+        }
+    }
+
+    impl Default for NetifSearchFlags {
+        fn default() -> Self {
+            NetifSearchFlags::NON_LOOPBACK
+                | NetifSearchFlags::NON_PEER_TO_PEER
+                | NetifSearchFlags::BROADCAST
+                | NetifSearchFlags::IPV4
+                | NetifSearchFlags::IPV6
+                | NetifSearchFlags::IPV6_LINK_LOCAL
+        }
+    }
+
     /// UnixNetif works on any Unix-like OS
     ///
     /// It is a simple implementation of the `Netif` trait that uses polling instead of actual notifications
@@ -169,7 +242,7 @@ mod unix {
         /// Create a new `UnixNetif`. The implementation will try
         /// to find and use a suitable interface automatically.
         pub fn new_default() -> Self {
-            Self(default_if().unwrap())
+            Self::search(NetifSearchFlags::default()).next().unwrap()
         }
 
         /// Create a new `UnixNetif` for the given interface name
@@ -180,6 +253,72 @@ mod unix {
         pub fn get_conf(&self) -> Option<NetifConf> {
             get_if_conf(&self.0)
         }
+
+        /// Search for network interfaces that match the given flags
+        pub fn search(flags: NetifSearchFlags) -> impl Iterator<Item = Self> {
+            nix::ifaddrs::getifaddrs()
+                .ok()
+                .into_iter()
+                .flatten()
+                .filter(move |ia| {
+                    ia.flags.contains(flags.contains_if_flags())
+                        && !ia.flags.intersects(flags.not_contains_if_flags())
+                })
+                .filter(move |ia| {
+                    !flags.contains(NetifSearchFlags::IPV4)
+                        || ia
+                            .address
+                            .map(|addr| addr.as_sockaddr_in().is_some())
+                            .unwrap_or(false)
+                })
+                .map(|ia| ia.interface_name)
+                .filter(move |ifname| {
+                    // Now also check the Ipv6 conditions
+
+                    if !flags.intersects(
+                        NetifSearchFlags::IPV6
+                            | NetifSearchFlags::IPV6_LINK_LOCAL
+                            | NetifSearchFlags::IPV6_NON_LINK_LOCAL,
+                    ) {
+                        return true;
+                    }
+
+                    let Ok(iter) = nix::ifaddrs::getifaddrs() else {
+                        return false;
+                    };
+
+                    let mut ipv6 = false;
+                    let mut ipv6_link_local = !flags.contains(NetifSearchFlags::IPV6_LINK_LOCAL);
+                    let mut ipv6_non_link_local =
+                        !flags.contains(NetifSearchFlags::IPV6_NON_LINK_LOCAL);
+
+                    for ia2 in iter {
+                        if &ia2.interface_name == ifname {
+                            if let Some(ip) = ia2
+                                .address
+                                .and_then(|addr| addr.as_sockaddr_in6().map(SockaddrIn6::ip))
+                            {
+                                ipv6 = true;
+
+                                if flags.contains(NetifSearchFlags::IPV6_LINK_LOCAL)
+                                    && ip.octets()[..2] == [0xfe, 0x80]
+                                {
+                                    ipv6_link_local = true;
+                                }
+
+                                if flags.contains(NetifSearchFlags::IPV6_NON_LINK_LOCAL)
+                                    && ip.octets()[..2] != [0xfe, 0x80]
+                                {
+                                    ipv6_non_link_local = true;
+                                }
+                            }
+                        }
+                    }
+
+                    ipv6 && ipv6_link_local && ipv6_non_link_local
+                })
+                .map(UnixNetif)
+        }
     }
 
     impl Default for UnixNetif {
@@ -211,40 +350,6 @@ mod unix {
         }
     }
 
-    fn default_if() -> Option<String> {
-        // A quick and dirty way to get a network interface that has a link-local IPv6 address assigned as well as a non-loopback IPv4
-        // Most likely, this is the interface we need
-        // (as opposed to all the docker and libvirt interfaces that might be assigned on the machine and which seem by default to be IPv4 only)
-        nix::ifaddrs::getifaddrs()
-            .unwrap()
-            .filter(|ia| {
-                // Only take interfaces which are up, which are not PTP or loopback
-                // and which have IPv4 IP assigned
-                ia.flags
-                    .contains(InterfaceFlags::IFF_UP | InterfaceFlags::IFF_BROADCAST)
-                    && !ia
-                        .flags
-                        .intersects(InterfaceFlags::IFF_LOOPBACK | InterfaceFlags::IFF_POINTOPOINT)
-                    && ia
-                        .address
-                        .and_then(|addr| addr.as_sockaddr_in().map(|_| ()))
-                        .is_some()
-            })
-            .map(|ia| ia.interface_name)
-            .find(|ifname| {
-                // Only take interfaces which have an IPv4 address
-                nix::ifaddrs::getifaddrs()
-                    .unwrap()
-                    .filter(|ia2| &ia2.interface_name == ifname)
-                    .any(|ia2| {
-                        ia2.address
-                            .and_then(|addr| addr.as_sockaddr_in6().map(SockaddrIn6::ip))
-                            .filter(|ip| ip.octets()[..2] == [0xfe, 0x80])
-                            .is_some()
-                    })
-            })
-    }
-
     fn get_if_conf(if_name: &str) -> Option<NetifConf> {
         extract_if_conf(
             nix::ifaddrs::getifaddrs()
diff --git a/src/network.rs b/src/network.rs
index 23651c1..710125a 100644
--- a/src/network.rs
+++ b/src/network.rs
@@ -1,10 +1,18 @@
+use rs_matter::utils::init::{init_from_closure, Init};
+
 /// User data that can be embedded in the stack network
 pub trait Embedding {
     const INIT: Self;
+
+    fn init() -> impl Init<Self>;
 }
 
 impl Embedding for () {
     const INIT: Self = ();
+
+    fn init() -> impl Init<Self> {
+        unsafe { init_from_closure(|_| Ok(())) }
+    }
 }
 
 /// A trait modeling a specific network type.
@@ -15,4 +23,6 @@ pub trait Network {
     type Embedding: Embedding + 'static;
 
     fn embedding(&self) -> &Self::Embedding;
+
+    fn init() -> impl Init<Self>;
 }
diff --git a/src/persist.rs b/src/persist.rs
index f9488ff..be922a5 100644
--- a/src/persist.rs
+++ b/src/persist.rs
@@ -2,7 +2,8 @@ use embassy_futures::select::select;
 use embassy_sync::blocking_mutex::raw::{NoopRawMutex, RawMutex};
 
 use rs_matter::error::Error;
-use rs_matter::utils::buf::{BufferAccess, PooledBuffers};
+use rs_matter::utils::init::{init, Init};
+use rs_matter::utils::storage::pooled::{BufferAccess, PooledBuffers};
 use rs_matter::Matter;
 
 use crate::network::{Embedding, Network};
@@ -48,7 +49,6 @@ pub struct DummyPersist;
 
 impl Persist for DummyPersist {
     async fn reset(&mut self) -> Result<(), Error> {
-        // TODO
         Ok(())
     }
 
@@ -157,10 +157,6 @@ where
         let mut buf = self.buf.get().await.unwrap();
         buf.resize_default(KV_BLOB_BUF_SIZE).unwrap();
 
-        if let Some(data) = self.store.load("acls", &mut buf).await? {
-            self.matter.load_acls(data)?;
-        }
-
         if let Some(data) = self.store.load("fabrics", &mut buf).await? {
             self.matter.load_fabrics(data)?;
         }
@@ -177,7 +173,7 @@ where
     /// Run the persist instance, listening for changes in the Matter stack's state.
     pub async fn run(&mut self) -> Result<(), Error> {
         loop {
-            let wait_matter = self.matter.wait_changed();
+            let wait_fabrics = self.matter.wait_fabrics_changed();
             let wait_wifi = async {
                 if let Some(wifi_networks) = self.wifi_networks {
                     wifi_networks.wait_state_changed().await;
@@ -186,16 +182,12 @@ where
                 }
             };
 
-            select(wait_matter, wait_wifi).await;
+            select(wait_fabrics, wait_wifi).await;
 
             let mut buf = self.buf.get().await.unwrap();
             buf.resize_default(KV_BLOB_BUF_SIZE).unwrap();
 
-            if self.matter.is_changed() {
-                if let Some(data) = self.matter.store_acls(&mut buf)? {
-                    self.store.store("acls", data).await?;
-                }
-
+            if self.matter.fabrics_changed() {
                 if let Some(data) = self.matter.store_fabrics(&mut buf)? {
                     self.store.store("fabrics", data).await?;
                 }
@@ -410,6 +402,13 @@ where
         }
     }
 
+    fn init() -> impl Init<Self> {
+        init!(Self {
+            buf <- PooledBuffers::init(0),
+            embedding <- E::init(),
+        })
+    }
+
     pub fn buf(&self) -> &PooledBuffers<1, NoopRawMutex, KvBlobBuffer> {
         &self.buf
     }
@@ -424,4 +423,8 @@ where
     E: Embedding,
 {
     const INIT: Self = Self::new();
+
+    fn init() -> impl Init<Self> {
+        KvBlobBuf::init()
+    }
 }
diff --git a/src/wifi.rs b/src/wifi.rs
index d312825..d736c21 100644
--- a/src/wifi.rs
+++ b/src/wifi.rs
@@ -1,15 +1,16 @@
-use core::cell::RefCell;
-
-use embassy_sync::blocking_mutex::{self, raw::RawMutex};
+use embassy_sync::blocking_mutex::raw::RawMutex;
 use embassy_time::{Duration, Timer};
 
 use log::{info, warn};
 
 use rs_matter::data_model::sdm::nw_commissioning::NetworkCommissioningStatus;
 use rs_matter::error::{Error, ErrorCode};
-use rs_matter::tlv::{self, FromTLV, TLVList, TLVWriter, TagType, ToTLV};
-use rs_matter::utils::notification::Notification;
-use rs_matter::utils::writebuf::WriteBuf;
+use rs_matter::tlv::{FromTLV, TLVElement, TLVTag, ToTLV};
+use rs_matter::utils::cell::RefCell;
+use rs_matter::utils::init::{init, Init};
+use rs_matter::utils::storage::WriteBuf;
+use rs_matter::utils::sync::blocking::Mutex;
+use rs_matter::utils::sync::Notification;
 
 pub mod comm;
 pub mod mgmt;
@@ -27,7 +28,7 @@ struct WifiStatus {
 }
 
 struct WifiState<const N: usize> {
-    networks: heapless::Vec<WifiCredentials, N>,
+    networks: rs_matter::utils::storage::Vec<WifiCredentials, N>,
     connected_once: bool,
     connect_requested: Option<heapless::String<32>>,
     status: Option<WifiStatus>,
@@ -35,6 +36,26 @@ struct WifiState<const N: usize> {
 }
 
 impl<const N: usize> WifiState<N> {
+    const fn new() -> Self {
+        Self {
+            networks: rs_matter::utils::storage::Vec::new(),
+            connected_once: false,
+            connect_requested: None,
+            status: None,
+            changed: false,
+        }
+    }
+
+    fn init() -> impl Init<Self> {
+        init!(Self {
+            networks <- rs_matter::utils::storage::Vec::init(),
+            connected_once: false,
+            connect_requested: None,
+            status: None,
+            changed: false,
+        })
+    }
+
     pub(crate) fn get_next_network(&mut self, last_ssid: Option<&str>) -> Option<WifiCredentials> {
         // Return the requested network with priority
         if let Some(ssid) = self.connect_requested.take() {
@@ -83,9 +104,20 @@ impl<const N: usize> WifiState<N> {
     }
 
     fn load(&mut self, data: &[u8]) -> Result<(), Error> {
-        let root = TLVList::new(data).iter().next().ok_or(ErrorCode::Invalid)?;
+        let root = TLVElement::new(data);
+
+        let iter = root.array()?.iter();
 
-        tlv::from_tlv(&mut self.networks, &root)?;
+        self.networks.clear();
+
+        for creds in iter {
+            let creds = creds?;
+
+            self.networks
+                .push_init(WifiCredentials::init_from_tlv(creds), || {
+                    ErrorCode::NoSpace.into()
+                })?;
+        }
 
         self.changed = false;
 
@@ -98,15 +130,12 @@ impl<const N: usize> WifiState<N> {
         }
 
         let mut wb = WriteBuf::new(buf);
-        let mut tw = TLVWriter::new(&mut wb);
 
-        self.networks
-            .as_slice()
-            .to_tlv(&mut tw, TagType::Anonymous)?;
+        self.networks.to_tlv(&TLVTag::Anonymous, &mut wb)?;
 
         self.changed = false;
 
-        let len = tw.get_tail();
+        let len = wb.get_tail();
 
         Ok(Some(&buf[..len]))
     }
@@ -119,7 +148,7 @@ pub struct WifiContext<const N: usize, M>
 where
     M: RawMutex,
 {
-    state: blocking_mutex::Mutex<M, RefCell<WifiState<N>>>,
+    state: Mutex<M, RefCell<WifiState<N>>>,
     state_changed: Notification<M>,
     network_connect_requested: Notification<M>,
 }
@@ -131,18 +160,20 @@ where
     /// Create a new instance.
     pub const fn new() -> Self {
         Self {
-            state: blocking_mutex::Mutex::new(RefCell::new(WifiState {
-                networks: heapless::Vec::new(),
-                connected_once: false,
-                connect_requested: None,
-                status: None,
-                changed: false,
-            })),
+            state: Mutex::new(RefCell::new(WifiState::new())),
             state_changed: Notification::new(),
             network_connect_requested: Notification::new(),
         }
     }
 
+    pub fn init() -> impl Init<Self> {
+        init!(Self {
+            state <- Mutex::init(RefCell::init(WifiState::init())),
+            state_changed: Notification::new(),
+            network_connect_requested: Notification::new(),
+        })
+    }
+
     /// Reset the state.
     pub fn reset(&self) {
         self.state.lock(|state| state.borrow_mut().reset());
diff --git a/src/wifi/comm.rs b/src/wifi/comm.rs
index 403ab8a..bf3af64 100644
--- a/src/wifi/comm.rs
+++ b/src/wifi/comm.rs
@@ -12,9 +12,7 @@ use rs_matter::data_model::sdm::nw_commissioning::{
     ReorderNetworkRequest, ResponseCommands, ScanNetworksRequest, WIFI_CLUSTER,
 };
 use rs_matter::error::{Error, ErrorCode};
-use rs_matter::interaction_model::core::IMStatusCode;
-use rs_matter::interaction_model::messages::ib::Status;
-use rs_matter::tlv::{FromTLV, OctetStr, TLVElement, TagType, ToTLV};
+use rs_matter::tlv::{FromTLV, Octets, TLVElement, TLVTag, TLVWrite, ToTLV};
 use rs_matter::transport::exchange::Exchange;
 
 use super::{WifiContext, WifiCredentials};
@@ -54,14 +52,14 @@ where
                 match attr.attr_id.try_into()? {
                     Attributes::MaxNetworks => AttrType::<u8>::new().encode(writer, N as u8),
                     Attributes::Networks => {
-                        writer.start_array(AttrDataWriter::TAG)?;
+                        writer.start_array(&AttrDataWriter::TAG)?;
 
                         self.networks.state.lock(|state| {
                             let state = state.borrow();
 
                             for network in &state.networks {
                                 let nw_info = NwInfo {
-                                    network_id: OctetStr(network.ssid.as_str().as_bytes()),
+                                    network_id: Octets(network.ssid.as_str().as_bytes()),
                                     connected: state
                                         .status
                                         .as_ref()
@@ -75,7 +73,7 @@ where
                                         .unwrap_or(false),
                                 };
 
-                                nw_info.to_tlv(&mut writer, TagType::Anonymous)?;
+                                nw_info.to_tlv(&TLVTag::Anonymous, &mut *writer)?;
                             }
 
                             Ok::<_, Error>(())
@@ -100,7 +98,7 @@ where
                                 .borrow()
                                 .status
                                 .as_ref()
-                                .map(|o| OctetStr(o.ssid.as_str().as_bytes())),
+                                .map(|o| Octets(o.ssid.as_str().as_bytes())),
                         )
                     }),
                     Attributes::LastConnectErrorValue => self.networks.state.lock(|state| {
@@ -157,16 +155,45 @@ where
     fn scan_networks(
         &self,
         _exchange: &Exchange<'_>,
-        _req: &ScanNetworksRequest<'_>,
-        encoder: CmdDataEncoder<'_, '_, '_>,
+        req: &ScanNetworksRequest<'_>,
+        _encoder: CmdDataEncoder<'_, '_, '_>,
     ) -> Result<(), Error> {
-        let writer = encoder.with_command(ResponseCommands::ScanNetworksResponse as _)?;
-
+        info!("ScanNetworks req: {:?}", req);
         warn!("Scan network not supported");
 
-        writer.set(Status::new(IMStatusCode::Busy, 0))?;
+        // Unfortunately Alexa calls `ScanNetworks` even if we have explicitly communicated
+        // that we do not support concurrent commissioning
+        //
+        // Cheat and declare that the SSID it is asking for is found
 
-        Ok(())
+        // let mut writer = encoder.with_command(ResponseCommands::ScanNetworksResponse as _)?;
+
+        // writer.start_struct(&CmdDataWriter::TAG)?;
+
+        // NetworkCommissioningStatus::Success.to_tlv(&TLVTag::Context(ScanNetworksResponseTag::Status as _), &mut *writer)?;
+
+        // writer.utf8(&TLVTag::Context(ScanNetworksResponseTag::DebugText as _), "")?;
+
+        // writer.start_array(&TLVTag::Context(ScanNetworksResponseTag::WifiScanResults as _))?;
+
+        // WiFiInterfaceScanResult {
+        //     security: WiFiSecurity::Wpa2Personal,
+        //     ssid: Octets(b"test\0"),
+        //     bssid: Octets(&[0xF4, 0x6A, 0xDD, 0xF4, 0xF2, 0xB5]),
+        //     channel: 20,
+        //     band: None,
+        //     rssi: None,
+        // }
+        // .to_tlv(&TLVTag::Anonymous, &mut *writer)?;
+
+        // writer.end_container()?;
+        // writer.end_container()?;
+
+        // writer.complete()?;
+
+        // Ok(())
+
+        Err(ErrorCode::Busy)?
     }
 
     fn add_network(
diff --git a/src/wifible.rs b/src/wifible.rs
index 8b16cf7..c351482 100644
--- a/src/wifible.rs
+++ b/src/wifible.rs
@@ -22,8 +22,8 @@ use rs_matter::data_model::sdm::wifi_nw_diagnostics::{
 use rs_matter::error::Error;
 use rs_matter::pairing::DiscoveryCapabilities;
 use rs_matter::transport::network::btp::{Btp, BtpContext, GattPeripheral};
+use rs_matter::utils::init::{init, Init};
 use rs_matter::utils::select::Coalesce;
-use rs_matter::CommissioningData;
 
 use crate::modem::{Modem, WifiDevice};
 use crate::netif::Netif;
@@ -76,6 +76,14 @@ where
     fn embedding(&self) -> &Self::Embedding {
         &self.embedding
     }
+
+    fn init() -> impl Init<Self> {
+        init!(Self {
+            btp_context <- BtpContext::init(),
+            wifi_context <- WifiContext::init(),
+            embedding <- E::init(),
+        })
+    }
 }
 
 pub type WifiBleMatterStack<'a, M, E> = MatterStack<'a, WifiBle<M, E>>;
@@ -128,15 +136,6 @@ where
         Ok(())
     }
 
-    /// Return information whether the Matter instance is already commissioned.
-    ///
-    /// User might need to reach out to this method only when it needs finer-grained control
-    /// and utilizes the `commission` and `operate` methods rather than the all-in-one `run` loop.
-    pub async fn is_commissioned(&self) -> Result<bool, Error> {
-        // TODO
-        Ok(false)
-    }
-
     /// A utility method to run the Matter stack in Operating mode (as per the Matter Core spec) over Wifi.
     ///
     /// This method assumes that the Matter instance is already commissioned and therefore
@@ -174,7 +173,7 @@ where
 
         let mut mgr = WifiManager::new(wifi, &self.network.wifi_context);
 
-        let mut main = pin!(self.run_with_netif(persist, netif, None, handler, &mut user));
+        let mut main = pin!(self.run_with_netif(persist, netif, handler, &mut user));
         let mut wifi = pin!(mgr.run());
 
         select(&mut wifi, &mut main).coalesce().await
@@ -195,7 +194,6 @@ where
         &'static self,
         persist: P,
         gatt: G,
-        dev_comm: CommissioningData,
         handler: H,
     ) -> Result<(), Error>
     where
@@ -205,24 +203,23 @@ where
     {
         info!("Running Matter in commissioning mode (BLE)");
 
+        self.matter()
+            .enable_basic_commissioning(DiscoveryCapabilities::BLE, 0)
+            .await?; // TODO
+
         let btp = Btp::new(gatt, &self.network.btp_context);
 
         let mut ble = pin!(async {
-            btp.run("BT", self.matter().dev_det(), &dev_comm)
-                .await
-                .map_err(Into::into)
+            btp.run(
+                "BT",
+                self.matter().dev_det(),
+                self.matter().dev_comm().discriminator,
+            )
+            .await
+            .map_err(Into::into)
         });
 
-        let mut main = pin!(self.run_with_transport(
-            &btp,
-            &btp,
-            persist,
-            Some((
-                dev_comm.clone(),
-                DiscoveryCapabilities::new(false, true, false)
-            )),
-            &handler
-        ));
+        let mut main = pin!(self.run_with_transport(&btp, &btp, persist, &handler));
 
         select(&mut ble, &mut main).coalesce().await
     }
@@ -241,7 +238,6 @@ where
         &'static self,
         mut persist: P,
         mut modem: O,
-        dev_comm: CommissioningData,
         handler: H,
         user: U,
     ) -> Result<(), Error>
@@ -256,16 +252,14 @@ where
         let mut user = pin!(user);
 
         loop {
-            if !self.is_commissioned().await? {
-                // Reset to factory defaults everything, as we'll do commissioning all over
-                self.reset()?;
+            // TODO persist.load().await?;
 
+            if !self.is_commissioned().await? {
                 let gatt = modem.ble().await;
 
                 info!("BLE driver initialized");
 
-                let mut main =
-                    pin!(self.commission(&mut persist, gatt, dev_comm.clone(), &handler));
+                let mut main = pin!(self.commission(&mut persist, gatt, &handler));
                 let mut wait_network_connect = pin!(async {
                     self.network.wifi_context.wait_network_connect().await;
                     Ok(())