• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! This module is a simple GATT server that shares the ATT channel with the
2 //! existing C++ GATT client.
3 
4 mod att_database;
5 pub mod att_server_bearer;
6 pub mod gatt_database;
7 mod indication_handler;
8 mod request_handler;
9 pub mod services;
10 mod transactions;
11 
12 mod command_handler;
13 #[cfg(test)]
14 mod test;
15 
16 use std::{collections::HashMap, rc::Rc};
17 
18 use crate::{
19     core::shared_box::{SharedBox, WeakBox, WeakBoxRef},
20     gatt::{ids::ConnectionId, server::gatt_database::GattDatabase},
21 };
22 
23 use self::{
24     super::ids::ServerId,
25     att_server_bearer::AttServerBearer,
26     gatt_database::{AttDatabaseImpl, GattServiceWithHandle},
27     services::register_builtin_services,
28 };
29 
30 use super::{
31     callbacks::RawGattDatastore,
32     channel::AttTransport,
33     ids::{AttHandle, TransportIndex},
34 };
35 use anyhow::{anyhow, bail, Result};
36 use log::info;
37 
38 pub use indication_handler::IndicationError;
39 
40 #[allow(missing_docs)]
41 pub struct GattModule {
42     connections: HashMap<TransportIndex, GattConnection>,
43     databases: HashMap<ServerId, SharedBox<GattDatabase>>,
44     transport: Rc<dyn AttTransport>,
45 }
46 
47 struct GattConnection {
48     bearer: SharedBox<AttServerBearer<AttDatabaseImpl>>,
49     database: WeakBox<GattDatabase>,
50 }
51 
52 impl GattModule {
53     /// Constructor.
new(transport: Rc<dyn AttTransport>) -> Self54     pub fn new(transport: Rc<dyn AttTransport>) -> Self {
55         Self { connections: HashMap::new(), databases: HashMap::new(), transport }
56     }
57 
58     /// Handle LE link connect
on_le_connect(&mut self, conn_id: ConnectionId) -> Result<()>59     pub fn on_le_connect(&mut self, conn_id: ConnectionId) -> Result<()> {
60         info!("connected on conn_id {conn_id:?}");
61         let database = self.databases.get(&conn_id.get_server_id());
62         let Some(database) = database else {
63             bail!(
64                 "got connection to conn_id {conn_id:?} (server_id {:?}) but this server does not exist!",
65                 conn_id.get_server_id(),
66             );
67         };
68 
69         // TODO(aryarahul): do not pass in conn_id at all, derive it using the IsolationManager instead
70         let tcb_idx = conn_id.get_tcb_idx();
71 
72         let transport = self.transport.clone();
73         let bearer = SharedBox::new(AttServerBearer::new(
74             database.get_att_database(tcb_idx),
75             move |packet| transport.send_packet(tcb_idx, packet),
76         ));
77         database.on_bearer_ready(tcb_idx, bearer.as_ref());
78         self.connections.insert(tcb_idx, GattConnection { bearer, database: database.downgrade() });
79         Ok(())
80     }
81 
82     /// Handle an LE link disconnect
on_le_disconnect(&mut self, tcb_idx: TransportIndex) -> Result<()>83     pub fn on_le_disconnect(&mut self, tcb_idx: TransportIndex) -> Result<()> {
84         info!("disconnected conn_id {tcb_idx:?}");
85         let connection = self.connections.remove(&tcb_idx);
86         let Some(connection) = connection else {
87             bail!("got disconnection from {tcb_idx:?} but bearer does not exist");
88         };
89         drop(connection.bearer);
90         connection.database.with(|db| db.map(|db| db.on_bearer_dropped(tcb_idx)));
91         Ok(())
92     }
93 
94     /// Register a new GATT service on a given server
register_gatt_service( &mut self, server_id: ServerId, service: GattServiceWithHandle, datastore: impl RawGattDatastore + 'static, ) -> Result<()>95     pub fn register_gatt_service(
96         &mut self,
97         server_id: ServerId,
98         service: GattServiceWithHandle,
99         datastore: impl RawGattDatastore + 'static,
100     ) -> Result<()> {
101         self.databases
102             .get(&server_id)
103             .ok_or_else(|| anyhow!("server {server_id:?} not opened"))?
104             .add_service_with_handles(service, Rc::new(datastore))
105     }
106 
107     /// Unregister an existing GATT service on a given server
unregister_gatt_service( &mut self, server_id: ServerId, service_handle: AttHandle, ) -> Result<()>108     pub fn unregister_gatt_service(
109         &mut self,
110         server_id: ServerId,
111         service_handle: AttHandle,
112     ) -> Result<()> {
113         self.databases
114             .get(&server_id)
115             .ok_or_else(|| anyhow!("server {server_id:?} not opened"))?
116             .remove_service_at_handle(service_handle)
117     }
118 
119     /// Open a GATT server
open_gatt_server(&mut self, server_id: ServerId) -> Result<()>120     pub fn open_gatt_server(&mut self, server_id: ServerId) -> Result<()> {
121         let mut db = GattDatabase::new();
122         register_builtin_services(&mut db)?;
123         let old = self.databases.insert(server_id, db.into());
124         if old.is_some() {
125             bail!("GATT server {server_id:?} already exists but was re-opened, clobbering old value...")
126         }
127         Ok(())
128     }
129 
130     /// Close a GATT server
close_gatt_server(&mut self, server_id: ServerId) -> Result<()>131     pub fn close_gatt_server(&mut self, server_id: ServerId) -> Result<()> {
132         let old = self.databases.remove(&server_id);
133         if old.is_none() {
134             bail!("GATT server {server_id:?} did not exist")
135         };
136 
137         Ok(())
138     }
139 
140     /// Get an ATT bearer for a particular connection
get_bearer( &self, tcb_idx: TransportIndex, ) -> Option<WeakBoxRef<AttServerBearer<AttDatabaseImpl>>>141     pub fn get_bearer(
142         &self,
143         tcb_idx: TransportIndex,
144     ) -> Option<WeakBoxRef<AttServerBearer<AttDatabaseImpl>>> {
145         self.connections.get(&tcb_idx).map(|x| x.bearer.as_ref())
146     }
147 }
148