summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--system/rust/Android.bp1
-rw-r--r--system/rust/Cargo.toml1
-rw-r--r--system/rust/src/gatt/arbiter.rs30
-rw-r--r--system/rust/src/gatt/ffi.rs33
-rw-r--r--system/rust/src/gatt/server.rs54
-rw-r--r--system/rust/src/gatt/server/isolation_manager.rs65
-rw-r--r--system/rust/src/lib.rs6
-rw-r--r--system/rust/tests/gatt_server_test.rs56
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);
+ });
+}