diff options
-rw-r--r-- | system/rust/Android.bp | 1 | ||||
-rw-r--r-- | system/rust/Cargo.toml | 1 | ||||
-rw-r--r-- | system/rust/src/gatt/arbiter.rs | 30 | ||||
-rw-r--r-- | system/rust/src/gatt/ffi.rs | 33 | ||||
-rw-r--r-- | system/rust/src/gatt/server.rs | 54 | ||||
-rw-r--r-- | system/rust/src/gatt/server/isolation_manager.rs | 65 | ||||
-rw-r--r-- | system/rust/src/lib.rs | 6 | ||||
-rw-r--r-- | system/rust/tests/gatt_server_test.rs | 56 |
8 files changed, 171 insertions, 75 deletions
diff --git a/system/rust/Android.bp b/system/rust/Android.bp index 153d5e9490..06a2885e11 100644 --- a/system/rust/Android.bp +++ b/system/rust/Android.bp @@ -39,6 +39,7 @@ rust_defaults { "libbt_common", "libcxx", "liblog_rust", + "libonce_cell", "libscopeguard", // needed to work around duplicate symbols diff --git a/system/rust/Cargo.toml b/system/rust/Cargo.toml index 3067f27d1e..87429e132c 100644 --- a/system/rust/Cargo.toml +++ b/system/rust/Cargo.toml @@ -34,6 +34,7 @@ async-trait = "*" tokio-test = "0.4.2" tokio = { version = "1.23.0", features = ["macros"] } scopeguard = "1.1.0" +once_cell = "1.17.1" [lib] crate-type = ["rlib"] diff --git a/system/rust/src/gatt/arbiter.rs b/system/rust/src/gatt/arbiter.rs index c28443ba68..b6b25a10c6 100644 --- a/system/rust/src/gatt/arbiter.rs +++ b/system/rust/src/gatt/arbiter.rs @@ -1,9 +1,10 @@ //! This module handles "arbitration" of ATT packets, to determine whether they //! should be handled by the primary stack or by the Rust stack -use std::sync::Mutex; +use std::sync::{Arc, Mutex}; use log::{error, trace}; +use once_cell::sync::OnceCell; use crate::{ do_in_rust_thread, @@ -18,11 +19,12 @@ use super::{ server::isolation_manager::IsolationManager, }; -static ARBITER: Mutex<Option<IsolationManager>> = Mutex::new(None); +static ARBITER: OnceCell<Arc<Mutex<IsolationManager>>> = OnceCell::new(); /// Initialize the Arbiter -pub fn initialize_arbiter() { - *ARBITER.lock().unwrap() = Some(IsolationManager::new()); +pub fn initialize_arbiter() -> Arc<Mutex<IsolationManager>> { + let arbiter = Arc::new(Mutex::new(IsolationManager::new())); + ARBITER.set(arbiter.clone()).unwrap_or_else(|_| panic!("Rust stack should only start up once")); StoreCallbacksFromRust( on_le_connect, @@ -32,12 +34,14 @@ pub fn initialize_arbiter() { |tcb_idx, mtu| on_mtu_event(TransportIndex(tcb_idx), MtuEvent::IncomingResponse(mtu)), |tcb_idx, mtu| on_mtu_event(TransportIndex(tcb_idx), MtuEvent::IncomingRequest(mtu)), ); + + arbiter } /// Acquire the mutex holding the Arbiter and provide a mutable reference to the /// supplied closure pub fn with_arbiter<T>(f: impl FnOnce(&mut IsolationManager) -> T) -> T { - f(ARBITER.lock().unwrap().as_mut().unwrap()) + f(ARBITER.get().unwrap().lock().as_mut().unwrap()) } /// Test to see if a buffer contains a valid ATT packet with an opcode we @@ -66,12 +70,10 @@ fn try_parse_att_server_packet( fn on_le_connect(tcb_idx: u8, advertiser: u8) { let tcb_idx = TransportIndex(tcb_idx); let advertiser = AdvertiserId(advertiser); - if let Some(conn_id) = with_arbiter(|arbiter| { - arbiter.on_le_connect(tcb_idx, advertiser); - arbiter.get_conn_id(tcb_idx) - }) { + let is_isolated = with_arbiter(|arbiter| arbiter.is_advertiser_isolated(advertiser)); + if is_isolated { do_in_rust_thread(move |modules| { - if let Err(err) = modules.gatt_module.on_le_connect(conn_id) { + if let Err(err) = modules.gatt_module.on_le_connect(tcb_idx, Some(advertiser)) { error!("{err:?}") } }) @@ -80,11 +82,7 @@ fn on_le_connect(tcb_idx: u8, advertiser: u8) { fn on_le_disconnect(tcb_idx: u8) { let tcb_idx = TransportIndex(tcb_idx); - let was_isolated = with_arbiter(|arbiter| { - let was_isolated = arbiter.get_conn_id(tcb_idx).is_some(); - arbiter.on_le_disconnect(tcb_idx); - was_isolated - }); + let was_isolated = with_arbiter(|arbiter| arbiter.get_conn_id(tcb_idx).is_some()); if was_isolated { do_in_rust_thread(move |modules| { if let Err(err) = modules.gatt_module.on_le_disconnect(tcb_idx) { @@ -149,7 +147,7 @@ mod test { ) -> IsolationManager { let mut isolation_manager = IsolationManager::new(); isolation_manager.associate_server_with_advertiser(server_id, ADVERTISER_ID); - isolation_manager.on_le_connect(tcb_idx, ADVERTISER_ID); + isolation_manager.on_le_connect(tcb_idx, Some(ADVERTISER_ID)); isolation_manager } diff --git a/system/rust/src/gatt/ffi.rs b/system/rust/src/gatt/ffi.rs index 8f86efe4ca..57543bb4fc 100644 --- a/system/rust/src/gatt/ffi.rs +++ b/system/rust/src/gatt/ffi.rs @@ -21,7 +21,7 @@ use crate::{ }; use super::{ - arbiter::{self, with_arbiter}, + arbiter::with_arbiter, callbacks::{GattWriteRequestType, GattWriteType, TransactionDecision}, channel::AttTransport, ids::{AdvertiserId, AttHandle, ConnectionId, ServerId, TransactionId, TransportIndex}, @@ -288,13 +288,13 @@ fn open_server(server_id: u8) { let server_id = ServerId(server_id); - if always_use_private_gatt_for_debugging_is_enabled() { - with_arbiter(|arbiter| { - arbiter.associate_server_with_advertiser(server_id, AdvertiserId(0)) - }); - } - do_in_rust_thread(move |modules| { + if always_use_private_gatt_for_debugging_is_enabled() { + modules + .gatt_module + .get_isolation_manager() + .associate_server_with_advertiser(server_id, AdvertiserId(0)) + } if let Err(err) = modules.gatt_module.open_gatt_server(server_id) { error!("{err:?}") } @@ -308,10 +308,6 @@ fn close_server(server_id: u8) { let server_id = ServerId(server_id); - if !always_use_private_gatt_for_debugging_is_enabled() { - with_arbiter(move |arbiter| arbiter.clear_server(server_id)); - } - do_in_rust_thread(move |modules| { if let Err(err) = modules.gatt_module.close_gatt_server(server_id) { error!("{err:?}") @@ -495,8 +491,13 @@ fn associate_server_with_advertiser(server_id: u8, advertiser_id: u8) { return; } - arbiter::with_arbiter(move |arbiter| { - arbiter.associate_server_with_advertiser(ServerId(server_id), AdvertiserId(advertiser_id)) + let server_id = ServerId(server_id); + let advertiser_id = AdvertiserId(advertiser_id); + do_in_rust_thread(move |modules| { + modules + .gatt_module + .get_isolation_manager() + .associate_server_with_advertiser(server_id, advertiser_id); }) } @@ -505,7 +506,11 @@ fn clear_advertiser(advertiser_id: u8) { return; } - arbiter::with_arbiter(move |arbiter| arbiter.clear_advertiser(AdvertiserId(advertiser_id))) + let advertiser_id = AdvertiserId(advertiser_id); + + do_in_rust_thread(move |modules| { + modules.gatt_module.get_isolation_manager().clear_advertiser(advertiser_id); + }) } #[cfg(test)] diff --git a/system/rust/src/gatt/server.rs b/system/rust/src/gatt/server.rs index 132779cf08..d6869349c4 100644 --- a/system/rust/src/gatt/server.rs +++ b/system/rust/src/gatt/server.rs @@ -14,26 +14,32 @@ pub mod isolation_manager; #[cfg(test)] mod test; -use std::{collections::HashMap, rc::Rc}; +use std::{ + collections::HashMap, + rc::Rc, + sync::{Arc, Mutex, MutexGuard}, +}; use crate::{ core::shared_box::{SharedBox, WeakBox, WeakBoxRef}, - gatt::{ids::ConnectionId, server::gatt_database::GattDatabase}, + gatt::server::gatt_database::GattDatabase, }; use self::{ super::ids::ServerId, att_server_bearer::AttServerBearer, gatt_database::{AttDatabaseImpl, GattServiceWithHandle}, + isolation_manager::IsolationManager, services::register_builtin_services, }; use super::{ callbacks::RawGattDatastore, channel::AttTransport, - ids::{AttHandle, TransportIndex}, + ids::{AdvertiserId, AttHandle, TransportIndex}, }; use anyhow::{anyhow, bail, Result}; +use bt_common::init_flags::always_use_private_gatt_for_debugging_is_enabled; use log::info; pub use indication_handler::IndicationError; @@ -43,6 +49,10 @@ pub struct GattModule { connections: HashMap<TransportIndex, GattConnection>, databases: HashMap<ServerId, SharedBox<GattDatabase>>, transport: Rc<dyn AttTransport>, + // NOTE: this is logically owned by the GattModule. We share it behind a Mutex just so we + // can use it as part of the Arbiter. Once the Arbiter is removed, this should be owned + // fully by the GattModule. + isolation_manager: Arc<Mutex<IsolationManager>>, } struct GattConnection { @@ -52,13 +62,30 @@ struct GattConnection { impl GattModule { /// Constructor. - pub fn new(transport: Rc<dyn AttTransport>) -> Self { - Self { connections: HashMap::new(), databases: HashMap::new(), transport } + pub fn new( + transport: Rc<dyn AttTransport>, + isolation_manager: Arc<Mutex<IsolationManager>>, + ) -> Self { + Self { + connections: HashMap::new(), + databases: HashMap::new(), + transport, + isolation_manager, + } } /// Handle LE link connect - pub fn on_le_connect(&mut self, conn_id: ConnectionId) -> Result<()> { - info!("connected on conn_id {conn_id:?}"); + pub fn on_le_connect( + &mut self, + tcb_idx: TransportIndex, + advertiser_id: Option<AdvertiserId>, + ) -> Result<()> { + info!("connected on tcb_idx {tcb_idx:?}"); + self.isolation_manager.lock().unwrap().on_le_connect(tcb_idx, advertiser_id); + + let Some(conn_id) = self.isolation_manager.lock().unwrap().get_conn_id(tcb_idx) else { + bail!("non-isolated servers are not yet supported (b/274945531)") + }; let database = self.databases.get(&conn_id.get_server_id()); let Some(database) = database else { bail!( @@ -67,9 +94,6 @@ impl GattModule { ); }; - // TODO(aryarahul): do not pass in conn_id at all, derive it using the IsolationManager instead - let tcb_idx = conn_id.get_tcb_idx(); - let transport = self.transport.clone(); let bearer = SharedBox::new(AttServerBearer::new( database.get_att_database(tcb_idx), @@ -83,6 +107,7 @@ impl GattModule { /// Handle an LE link disconnect pub fn on_le_disconnect(&mut self, tcb_idx: TransportIndex) -> Result<()> { info!("disconnected conn_id {tcb_idx:?}"); + self.isolation_manager.lock().unwrap().on_le_disconnect(tcb_idx); let connection = self.connections.remove(&tcb_idx); let Some(connection) = connection else { bail!("got disconnection from {tcb_idx:?} but bearer does not exist"); @@ -135,6 +160,10 @@ impl GattModule { bail!("GATT server {server_id:?} did not exist") }; + if !always_use_private_gatt_for_debugging_is_enabled() { + self.isolation_manager.lock().unwrap().clear_server(server_id); + } + Ok(()) } @@ -145,4 +174,9 @@ impl GattModule { ) -> Option<WeakBoxRef<AttServerBearer<AttDatabaseImpl>>> { self.connections.get(&tcb_idx).map(|x| x.bearer.as_ref()) } + + /// Get the IsolationManager to manage associations between servers + advertisers + pub fn get_isolation_manager(&mut self) -> MutexGuard<'_, IsolationManager> { + self.isolation_manager.lock().unwrap() + } } diff --git a/system/rust/src/gatt/server/isolation_manager.rs b/system/rust/src/gatt/server/isolation_manager.rs index 31db3cbe23..2d0cfa6dde 100644 --- a/system/rust/src/gatt/server/isolation_manager.rs +++ b/system/rust/src/gatt/server/isolation_manager.rs @@ -39,12 +39,6 @@ impl IsolationManager { } } - /// Remove all linked advertising sets from the provided server - pub fn clear_server(&mut self, server_id: ServerId) { - info!("clearing advertisers associated with {server_id:?}"); - self.advertiser_to_server.retain(|_, server| *server != server_id); - } - /// Clear the server associated with this advertiser, if one exists pub fn clear_advertiser(&mut self, advertiser_id: AdvertiserId) { info!("removing server (if any) associated with advertiser {advertiser_id:?}"); @@ -56,29 +50,50 @@ impl IsolationManager { self.transport_to_owned_connection.values().any(|owned_conn_id| *owned_conn_id == conn_id) } + /// Check if this advertiser is tied to a private server + pub fn is_advertiser_isolated(&self, advertiser_id: AdvertiserId) -> bool { + self.advertiser_to_server.contains_key(&advertiser_id) + } + /// Look up the conn_id for a given tcb_idx, if present pub fn get_conn_id(&self, tcb_idx: TransportIndex) -> Option<ConnectionId> { self.transport_to_owned_connection.get(&tcb_idx).copied() } + /// Remove all linked advertising sets from the provided server + /// + /// This is invoked by the GATT server module, not separately from the upper layer. + pub fn clear_server(&mut self, server_id: ServerId) { + info!("clearing advertisers associated with {server_id:?}"); + self.advertiser_to_server.retain(|_, server| *server != server_id); + } + /// Handles an incoming connection - pub fn on_le_connect(&mut self, tcb_idx: TransportIndex, advertiser: AdvertiserId) { + /// + /// This event should be supplied from the enclosing module, not directly from the upper layer. + pub fn on_le_connect(&mut self, tcb_idx: TransportIndex, advertiser: Option<AdvertiserId>) { info!( "processing incoming connection on transport {tcb_idx:?} to advertiser {advertiser:?}" ); - if let Some(server_id) = self.advertiser_to_server.get(&advertiser).copied() { - info!("connection is isolated to server {server_id:?}"); - let conn_id = ConnectionId::new(tcb_idx, server_id); - let old = self.transport_to_owned_connection.insert(tcb_idx, conn_id); - if old.is_some() { - error!("new server {server_id:?} on transport {tcb_idx:?} displacing existing registered connection {conn_id:?}") - } - } else { + let Some(advertiser) = advertiser else { + info!("processing outgoing connection, granting access to all servers"); + return; + }; + let Some(server_id) = self.advertiser_to_server.get(&advertiser).copied() else { info!("connection can access all servers"); + return; + }; + info!("connection is isolated to server {server_id:?}"); + let conn_id = ConnectionId::new(tcb_idx, server_id); + let old = self.transport_to_owned_connection.insert(tcb_idx, conn_id); + if old.is_some() { + error!("new server {server_id:?} on transport {tcb_idx:?} displacing existing registered connection {conn_id:?}") } } /// Handle a disconnection + /// + /// This event should be supplied from the enclosing module, not directly from the upper layer. pub fn on_le_disconnect(&mut self, tcb_idx: TransportIndex) { info!("processing disconnection on transport {tcb_idx:?}"); self.transport_to_owned_connection.remove(&tcb_idx); @@ -101,7 +116,7 @@ mod test { fn test_non_isolated_connect() { let mut isolation_manager = IsolationManager::new(); - isolation_manager.on_le_connect(TCB_IDX, ADVERTISER_ID); + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); let conn_id = isolation_manager.get_conn_id(TCB_IDX); assert!(conn_id.is_none()) @@ -112,7 +127,7 @@ mod test { let mut isolation_manager = IsolationManager::new(); isolation_manager.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - isolation_manager.on_le_connect(TCB_IDX, ADVERTISER_ID); + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); let conn_id = isolation_manager.get_conn_id(TCB_IDX); assert_eq!(conn_id, Some(CONN_ID)); @@ -123,7 +138,7 @@ mod test { let mut isolation_manager = IsolationManager::new(); isolation_manager.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - isolation_manager.on_le_connect(TCB_IDX, ANOTHER_ADVERTISER_ID); + isolation_manager.on_le_connect(TCB_IDX, Some(ANOTHER_ADVERTISER_ID)); let conn_id = isolation_manager.get_conn_id(TCB_IDX); assert!(conn_id.is_none()) @@ -137,7 +152,7 @@ mod test { isolation_manager.clear_advertiser(ADVERTISER_ID); // a new advertiser appeared with the same ID and got a connection - isolation_manager.on_le_connect(TCB_IDX, ADVERTISER_ID); + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); let conn_id = isolation_manager.get_conn_id(TCB_IDX); // but we should not be isolated since this is a new advertiser reusing the old @@ -153,7 +168,7 @@ mod test { isolation_manager.clear_server(SERVER_ID); // then afterwards we get a connection to this advertiser - isolation_manager.on_le_connect(TCB_IDX, ADVERTISER_ID); + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); let conn_id = isolation_manager.get_conn_id(TCB_IDX); // since the server is gone, we should not capture the connection @@ -164,7 +179,7 @@ mod test { fn test_connection_isolated_after_advertiser_stops() { let mut isolation_manager = IsolationManager::new(); isolation_manager.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - isolation_manager.on_le_connect(TCB_IDX, ADVERTISER_ID); + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); let conn_id = isolation_manager.get_conn_id(TCB_IDX).unwrap(); isolation_manager.clear_advertiser(ADVERTISER_ID); @@ -177,7 +192,7 @@ mod test { fn test_connection_isolated_after_server_stops() { let mut isolation_manager = IsolationManager::new(); isolation_manager.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - isolation_manager.on_le_connect(TCB_IDX, ADVERTISER_ID); + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); let conn_id = isolation_manager.get_conn_id(TCB_IDX).unwrap(); isolation_manager.clear_server(SERVER_ID); @@ -190,7 +205,7 @@ mod test { fn test_not_isolated_after_disconnection() { let mut isolation_manager = IsolationManager::new(); isolation_manager.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - isolation_manager.on_le_connect(TCB_IDX, ADVERTISER_ID); + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); isolation_manager.on_le_disconnect(TCB_IDX); let is_isolated = isolation_manager.is_connection_isolated(CONN_ID); @@ -202,11 +217,11 @@ mod test { fn test_tcb_idx_reuse_after_isolated() { let mut isolation_manager = IsolationManager::new(); isolation_manager.associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); - isolation_manager.on_le_connect(TCB_IDX, ADVERTISER_ID); + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); isolation_manager.clear_advertiser(ADVERTISER_ID); isolation_manager.on_le_disconnect(TCB_IDX); - isolation_manager.on_le_connect(TCB_IDX, ADVERTISER_ID); + isolation_manager.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)); let conn_id = isolation_manager.get_conn_id(TCB_IDX); assert!(conn_id.is_none()); diff --git a/system/rust/src/lib.rs b/system/rust/src/lib.rs index d944e0214e..7e628608a5 100644 --- a/system/rust/src/lib.rs +++ b/system/rust/src/lib.rs @@ -86,15 +86,15 @@ impl GlobalModuleRegistry { assert!(prev_registry.is_none()); // First, setup FFI and C++ modules - gatt::arbiter::initialize_arbiter(); + let arbiter = gatt::arbiter::initialize_arbiter(); connection::register_callbacks(); // Now enter the runtime - local.block_on(&rt, async { + local.block_on(&rt, async move { // Then follow the pure-Rust modules let gatt_incoming_callbacks = Rc::new(gatt::callbacks::CallbackTransactionManager::new(gatt_callbacks.clone())); - let gatt_module = &mut gatt::server::GattModule::new(att_transport.clone()); + let gatt_module = &mut gatt::server::GattModule::new(att_transport.clone(), arbiter); let connection_manager = connection::ConnectionManager::new(le_acl_manager); diff --git a/system/rust/tests/gatt_server_test.rs b/system/rust/tests/gatt_server_test.rs index 8ec91f74e4..7ee6fd7402 100644 --- a/system/rust/tests/gatt_server_test.rs +++ b/system/rust/tests/gatt_server_test.rs @@ -1,11 +1,14 @@ -use std::rc::Rc; +use std::{ + rc::Rc, + sync::{Arc, Mutex}, +}; use bluetooth_core::{ core::uuid::Uuid, gatt::{ self, ffi::AttributeBackingType, - ids::{AttHandle, ConnectionId, ServerId, TransportIndex}, + ids::{AdvertiserId, AttHandle, ServerId, TransportIndex}, mocks::{ mock_datastore::{MockDatastore, MockDatastoreEvents}, mock_transport::MockAttTransport, @@ -15,6 +18,7 @@ use bluetooth_core::{ AttPermissions, GattCharacteristicWithHandle, GattDescriptorWithHandle, GattServiceWithHandle, CHARACTERISTIC_UUID, PRIMARY_SERVICE_DECLARATION_UUID, }, + isolation_manager::IsolationManager, services::{ gap::DEVICE_NAME_UUID, gatt::{ @@ -48,11 +52,11 @@ mod utils; const TCB_IDX: TransportIndex = TransportIndex(1); const SERVER_ID: ServerId = ServerId(2); -const CONN_ID: ConnectionId = ConnectionId::new(TCB_IDX, SERVER_ID); +const ADVERTISER_ID: AdvertiserId = AdvertiserId(3); const ANOTHER_TCB_IDX: TransportIndex = TransportIndex(2); const ANOTHER_SERVER_ID: ServerId = ServerId(3); -const ANOTHER_CONN_ID: ConnectionId = ConnectionId::new(ANOTHER_TCB_IDX, ANOTHER_SERVER_ID); +const ANOTHER_ADVERTISER_ID: AdvertiserId = AdvertiserId(4); const SERVICE_HANDLE: AttHandle = AttHandle(6); const CHARACTERISTIC_HANDLE: AttHandle = AttHandle(8); @@ -68,7 +72,8 @@ const ANOTHER_DATA: [u8; 4] = [5, 6, 7, 8]; fn start_gatt_module() -> (gatt::server::GattModule, UnboundedReceiver<(TransportIndex, AttBuilder)>) { let (transport, transport_rx) = MockAttTransport::new(); - let gatt = GattModule::new(Rc::new(transport)); + let arbiter = IsolationManager::new(); + let gatt = GattModule::new(Rc::new(transport), Arc::new(Mutex::new(arbiter))); (gatt, transport_rx) } @@ -99,7 +104,8 @@ fn create_server_and_open_connection( datastore, ) .unwrap(); - gatt.on_le_connect(CONN_ID).unwrap(); + gatt.get_isolation_manager().associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); + gatt.on_le_connect(TCB_IDX, Some(ADVERTISER_ID)).unwrap(); data_rx } @@ -400,7 +406,9 @@ fn test_multiple_servers() { datastore, ) .unwrap(); - gatt.on_le_connect(ANOTHER_CONN_ID).unwrap(); + gatt.get_isolation_manager() + .associate_server_with_advertiser(ANOTHER_SERVER_ID, ANOTHER_ADVERTISER_ID); + gatt.on_le_connect(ANOTHER_TCB_IDX, Some(ANOTHER_ADVERTISER_ID)).unwrap(); // act: read from both connections gatt.get_bearer(TCB_IDX).unwrap().handle_packet( @@ -613,3 +621,37 @@ fn test_service_change_indication() { ); }); } + +#[test] +fn test_closing_gatt_server_unisolates_advertiser() { + start_test(async move { + // arrange + let (mut gatt, _) = start_gatt_module(); + gatt.open_gatt_server(SERVER_ID).unwrap(); + gatt.get_isolation_manager().associate_server_with_advertiser(SERVER_ID, ADVERTISER_ID); + + // act + gatt.close_gatt_server(SERVER_ID).unwrap(); + + // assert + let is_advertiser_isolated = + gatt.get_isolation_manager().is_advertiser_isolated(ADVERTISER_ID); + assert!(!is_advertiser_isolated); + }); +} + +#[test] +fn test_disconnection_unisolates_connection() { + start_test(async move { + // arrange + let (mut gatt, _) = start_gatt_module(); + create_server_and_open_connection(&mut gatt); + + // act + gatt.on_le_disconnect(TCB_IDX).unwrap(); + + // assert + let is_connection_isolated = gatt.get_isolation_manager().get_conn_id(TCB_IDX).is_some(); + assert!(!is_connection_isolated); + }); +} |