diff options
author | 2023-05-10 18:56:24 +0000 | |
---|---|---|
committer | 2023-05-10 18:56:24 +0000 | |
commit | 9066159c6aff46c222f996794686b5bec09d457f (patch) | |
tree | 506345f257b35f0bdf319c24b8e9420255dea2d4 | |
parent | 34ecd8fefa0a1c02bc53ac326af5719ade54a762 (diff) |
[GATT Server] Expose IsolationManager from GATT server module
The IsolationManager is made a submodule of the GATT server, so we can
query it to figure out what services are exposed to each connection. It
is temporarily also available directly from FFI, solely for the purpose
of arbitration. This will be removed once the Rust server is used for
100% of GATT server operations.
Test: unit + CTS multi-device
Bug: 274945531
Change-Id: Idc3cdd78ec2435a7a286413d7b1ebaae83a8f07a
-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); + }); +} |