1 /*
2  * Copyright 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "gatt"
18 
19 #include <bluetooth/log.h>
20 
21 #include <list>
22 #include <unordered_map>
23 #include <unordered_set>
24 #include <vector>
25 
26 #include "bta_gatt_queue.h"
27 #include "osi/include/allocator.h"
28 #include "stack/eatt/eatt.h"
29 
30 using gatt_operation = BtaGattQueue::gatt_operation;
31 using namespace bluetooth;
32 
33 constexpr uint8_t GATT_READ_CHAR = 1;
34 constexpr uint8_t GATT_READ_DESC = 2;
35 constexpr uint8_t GATT_WRITE_CHAR = 3;
36 constexpr uint8_t GATT_WRITE_DESC = 4;
37 constexpr uint8_t GATT_CONFIG_MTU = 5;
38 constexpr uint8_t GATT_READ_MULTI = 6;
39 
40 struct gatt_read_op_data {
41   GATT_READ_OP_CB cb;
42   void* cb_data;
43 };
44 
45 std::unordered_map<tCONN_ID, std::list<gatt_operation>> BtaGattQueue::gatt_op_queue;
46 std::unordered_set<tCONN_ID> BtaGattQueue::gatt_op_queue_executing;
47 
mark_as_not_executing(tCONN_ID conn_id)48 void BtaGattQueue::mark_as_not_executing(tCONN_ID conn_id) {
49   gatt_op_queue_executing.erase(conn_id);
50 }
51 
gatt_read_op_finished(tCONN_ID conn_id,tGATT_STATUS status,uint16_t handle,uint16_t len,uint8_t * value,void * data)52 void BtaGattQueue::gatt_read_op_finished(tCONN_ID conn_id, tGATT_STATUS status, uint16_t handle,
53                                          uint16_t len, uint8_t* value, void* data) {
54   gatt_read_op_data* tmp = (gatt_read_op_data*)data;
55   GATT_READ_OP_CB tmp_cb = tmp->cb;
56   void* tmp_cb_data = tmp->cb_data;
57 
58   osi_free(data);
59 
60   mark_as_not_executing(conn_id);
61   gatt_execute_next_op(conn_id);
62 
63   if (tmp_cb) {
64     tmp_cb(conn_id, status, handle, len, value, tmp_cb_data);
65     return;
66   }
67 }
68 
69 struct gatt_write_op_data {
70   GATT_WRITE_OP_CB cb;
71   void* cb_data;
72 };
73 
gatt_write_op_finished(tCONN_ID conn_id,tGATT_STATUS status,uint16_t handle,uint16_t len,const uint8_t * value,void * data)74 void BtaGattQueue::gatt_write_op_finished(tCONN_ID conn_id, tGATT_STATUS status, uint16_t handle,
75                                           uint16_t len, const uint8_t* value, void* data) {
76   gatt_write_op_data* tmp = (gatt_write_op_data*)data;
77   GATT_WRITE_OP_CB tmp_cb = tmp->cb;
78   void* tmp_cb_data = tmp->cb_data;
79 
80   osi_free(data);
81 
82   mark_as_not_executing(conn_id);
83   gatt_execute_next_op(conn_id);
84 
85   if (tmp_cb) {
86     tmp_cb(conn_id, status, handle, len, value, tmp_cb_data);
87     return;
88   }
89 }
90 
91 struct gatt_configure_mtu_op_data {
92   GATT_CONFIGURE_MTU_OP_CB cb;
93   void* cb_data;
94 };
95 
gatt_configure_mtu_op_finished(tCONN_ID conn_id,tGATT_STATUS status,void * data)96 void BtaGattQueue::gatt_configure_mtu_op_finished(tCONN_ID conn_id, tGATT_STATUS status,
97                                                   void* data) {
98   gatt_configure_mtu_op_data* tmp = (gatt_configure_mtu_op_data*)data;
99   GATT_CONFIGURE_MTU_OP_CB tmp_cb = tmp->cb;
100   void* tmp_cb_data = tmp->cb_data;
101 
102   osi_free(data);
103 
104   mark_as_not_executing(conn_id);
105   gatt_execute_next_op(conn_id);
106 
107   if (tmp_cb) {
108     tmp_cb(conn_id, status, tmp_cb_data);
109     return;
110   }
111 }
112 
113 struct gatt_read_multi_op_data {
114   GATT_READ_MULTI_OP_CB cb;
115   void* cb_data;
116 };
117 
118 #define MAX_ATT_MTU 0xffff
119 
120 struct gatt_read_multi_simulate_op_data {
121   GATT_READ_MULTI_OP_CB cb;
122   void* cb_data;
123 
124   tBTA_GATTC_MULTI handles;
125   uint8_t read_index;
126   std::array<uint8_t, MAX_ATT_MTU> values;
127   uint16_t values_end;
128 };
129 
gatt_read_multi_op_finished(tCONN_ID conn_id,tGATT_STATUS status,tBTA_GATTC_MULTI & handles,uint16_t len,uint8_t * value,void * data)130 void BtaGattQueue::gatt_read_multi_op_finished(tCONN_ID conn_id, tGATT_STATUS status,
131                                                tBTA_GATTC_MULTI& handles, uint16_t len,
132                                                uint8_t* value, void* data) {
133   gatt_read_multi_op_data* tmp = (gatt_read_multi_op_data*)data;
134   GATT_READ_MULTI_OP_CB tmp_cb = tmp->cb;
135   void* tmp_cb_data = tmp->cb_data;
136 
137   osi_free(data);
138 
139   mark_as_not_executing(conn_id);
140   gatt_execute_next_op(conn_id);
141 
142   if (tmp_cb) {
143     tmp_cb(conn_id, status, handles, len, value, tmp_cb_data);
144     return;
145   }
146 }
147 
gatt_read_multi_op_simulate(tCONN_ID conn_id,tGATT_STATUS status,uint16_t handle,uint16_t len,uint8_t * value,void * data_read)148 void BtaGattQueue::gatt_read_multi_op_simulate(tCONN_ID conn_id, tGATT_STATUS status,
149                                                uint16_t handle, uint16_t len, uint8_t* value,
150                                                void* data_read) {
151   gatt_read_multi_simulate_op_data* data = (gatt_read_multi_simulate_op_data*)data_read;
152 
153   log::verbose("conn_id: 0x{:x} handle: 0x{:x} status: 0x{:x} len: {}", conn_id, handle, status,
154                len);
155   if (status == GATT_SUCCESS && ((data->values_end + 2 + len) < MAX_ATT_MTU)) {
156     data->values[data->values_end] = (len & 0x00ff);
157     data->values[data->values_end + 1] = (len & 0xff00) >> 8;
158     data->values_end += 2;
159 
160     // concatenate all read values together
161     std::copy(value, value + len, data->values.data() + data->values_end);
162     data->values_end += len;
163 
164     if (data->read_index < data->handles.num_attr - 1) {
165       // grab next handle and read it
166       data->read_index++;
167       uint16_t next_handle = data->handles.handles[data->read_index];
168 
169       BTA_GATTC_ReadCharacteristic(conn_id, next_handle, GATT_AUTH_REQ_NONE,
170                                    gatt_read_multi_op_simulate, data_read);
171       return;
172     }
173   }
174 
175   // all handles read, or bad status, or values too long
176   GATT_READ_MULTI_OP_CB tmp_cb = data->cb;
177   void* tmp_cb_data = data->cb_data;
178 
179   std::array<uint8_t, MAX_ATT_MTU> value_copy = data->values;
180   uint16_t value_len = data->values_end;
181   auto handles = data->handles;
182 
183   osi_free(data_read);
184 
185   mark_as_not_executing(conn_id);
186   gatt_execute_next_op(conn_id);
187 
188   if (tmp_cb) {
189     tmp_cb(conn_id, status, handles, value_len, value_copy.data(), tmp_cb_data);
190   }
191 }
192 
gatt_execute_next_op(tCONN_ID conn_id)193 void BtaGattQueue::gatt_execute_next_op(tCONN_ID conn_id) {
194   log::verbose("conn_id=0x{:x}", conn_id);
195   if (gatt_op_queue.empty()) {
196     log::verbose("op queue is empty");
197     return;
198   }
199 
200   auto map_ptr = gatt_op_queue.find(conn_id);
201   if (map_ptr == gatt_op_queue.end() || map_ptr->second.empty()) {
202     log::verbose("no more operations queued for conn_id {}", conn_id);
203     return;
204   }
205 
206   if (gatt_op_queue_executing.count(conn_id)) {
207     log::verbose("can't enqueue next op, already executing");
208     return;
209   }
210 
211   gatt_op_queue_executing.insert(conn_id);
212 
213   std::list<gatt_operation>& gatt_ops = map_ptr->second;
214 
215   gatt_operation& op = gatt_ops.front();
216 
217   if (op.type == GATT_READ_CHAR) {
218     gatt_read_op_data* data = (gatt_read_op_data*)osi_malloc(sizeof(gatt_read_op_data));
219     data->cb = op.read_cb;
220     data->cb_data = op.read_cb_data;
221     BTA_GATTC_ReadCharacteristic(conn_id, op.handle, GATT_AUTH_REQ_NONE, gatt_read_op_finished,
222                                  data);
223 
224   } else if (op.type == GATT_READ_DESC) {
225     gatt_read_op_data* data = (gatt_read_op_data*)osi_malloc(sizeof(gatt_read_op_data));
226     data->cb = op.read_cb;
227     data->cb_data = op.read_cb_data;
228     BTA_GATTC_ReadCharDescr(conn_id, op.handle, GATT_AUTH_REQ_NONE, gatt_read_op_finished, data);
229 
230   } else if (op.type == GATT_WRITE_CHAR) {
231     gatt_write_op_data* data = (gatt_write_op_data*)osi_malloc(sizeof(gatt_write_op_data));
232     data->cb = op.write_cb;
233     data->cb_data = op.write_cb_data;
234     BTA_GATTC_WriteCharValue(conn_id, op.handle, op.write_type, std::move(op.value),
235                              GATT_AUTH_REQ_NONE, gatt_write_op_finished, data);
236 
237   } else if (op.type == GATT_WRITE_DESC) {
238     gatt_write_op_data* data = (gatt_write_op_data*)osi_malloc(sizeof(gatt_write_op_data));
239     data->cb = op.write_cb;
240     data->cb_data = op.write_cb_data;
241     BTA_GATTC_WriteCharDescr(conn_id, op.handle, std::move(op.value), GATT_AUTH_REQ_NONE,
242                              gatt_write_op_finished, data);
243   } else if (op.type == GATT_CONFIG_MTU) {
244     gatt_configure_mtu_op_data* data =
245             (gatt_configure_mtu_op_data*)osi_malloc(sizeof(gatt_configure_mtu_op_data));
246     data->cb = op.mtu_cb;
247     data->cb_data = op.mtu_cb_data;
248     BTA_GATTC_ConfigureMTU(conn_id, static_cast<uint16_t>(op.value[0] | (op.value[1] << 8)),
249                            gatt_configure_mtu_op_finished, data);
250   } else if (op.type == GATT_READ_MULTI) {
251     if (gatt_profile_get_eatt_support_by_conn_id(conn_id)) {
252       gatt_read_multi_op_data* data =
253               (gatt_read_multi_op_data*)osi_malloc(sizeof(gatt_read_multi_op_data));
254       data->cb = op.read_multi_cb;
255       data->cb_data = op.read_cb_data;
256       BTA_GATTC_ReadMultiple(conn_id, op.handles, true, GATT_AUTH_REQ_NONE,
257                              gatt_read_multi_op_finished, data);
258     } else {
259       /* This file contains just queue, and simulating reads should rather live in BTA or
260        * stack/gatt. However, placing this logic in layers below would be significantly harder.
261        * Having it here is a good balance - it's easy to add, and the API we expose to apps is same
262        * as if it was in layers below.
263        */
264       log::verbose("EATT not supported, simulating read multi. conn_id: 0x{:x} num_handles: {}",
265                    conn_id, op.handles.num_attr);
266       gatt_read_multi_simulate_op_data* data = (gatt_read_multi_simulate_op_data*)osi_malloc(
267               sizeof(gatt_read_multi_simulate_op_data));
268       data->cb = op.read_multi_cb;
269       data->cb_data = op.read_cb_data;
270 
271       std::fill(data->values.begin(), data->values.end(), 0);
272       data->values_end = 0;
273 
274       data->handles = op.handles;
275       data->read_index = 0;
276       uint16_t handle = data->handles.handles[data->read_index];
277 
278       BTA_GATTC_ReadCharacteristic(conn_id, handle, GATT_AUTH_REQ_NONE, gatt_read_multi_op_simulate,
279                                    data);
280     }
281   }
282 
283   gatt_ops.pop_front();
284 }
285 
Clean(tCONN_ID conn_id)286 void BtaGattQueue::Clean(tCONN_ID conn_id) {
287   gatt_op_queue.erase(conn_id);
288   gatt_op_queue_executing.erase(conn_id);
289 }
290 
ReadCharacteristic(tCONN_ID conn_id,uint16_t handle,GATT_READ_OP_CB cb,void * cb_data)291 void BtaGattQueue::ReadCharacteristic(tCONN_ID conn_id, uint16_t handle, GATT_READ_OP_CB cb,
292                                       void* cb_data) {
293   gatt_op_queue[conn_id].push_back(
294           {.type = GATT_READ_CHAR, .handle = handle, .read_cb = cb, .read_cb_data = cb_data});
295   gatt_execute_next_op(conn_id);
296 }
297 
ReadDescriptor(tCONN_ID conn_id,uint16_t handle,GATT_READ_OP_CB cb,void * cb_data)298 void BtaGattQueue::ReadDescriptor(tCONN_ID conn_id, uint16_t handle, GATT_READ_OP_CB cb,
299                                   void* cb_data) {
300   gatt_op_queue[conn_id].push_back(
301           {.type = GATT_READ_DESC, .handle = handle, .read_cb = cb, .read_cb_data = cb_data});
302   gatt_execute_next_op(conn_id);
303 }
304 
WriteCharacteristic(tCONN_ID conn_id,uint16_t handle,std::vector<uint8_t> value,tGATT_WRITE_TYPE write_type,GATT_WRITE_OP_CB cb,void * cb_data)305 void BtaGattQueue::WriteCharacteristic(tCONN_ID conn_id, uint16_t handle,
306                                        std::vector<uint8_t> value, tGATT_WRITE_TYPE write_type,
307                                        GATT_WRITE_OP_CB cb, void* cb_data) {
308   gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_CHAR,
309                                     .handle = handle,
310                                     .write_cb = cb,
311                                     .write_cb_data = cb_data,
312                                     .write_type = write_type,
313                                     .value = std::move(value)});
314   gatt_execute_next_op(conn_id);
315 }
316 
WriteDescriptor(tCONN_ID conn_id,uint16_t handle,std::vector<uint8_t> value,tGATT_WRITE_TYPE write_type,GATT_WRITE_OP_CB cb,void * cb_data)317 void BtaGattQueue::WriteDescriptor(tCONN_ID conn_id, uint16_t handle, std::vector<uint8_t> value,
318                                    tGATT_WRITE_TYPE write_type, GATT_WRITE_OP_CB cb,
319                                    void* cb_data) {
320   gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_DESC,
321                                     .handle = handle,
322                                     .write_cb = cb,
323                                     .write_cb_data = cb_data,
324                                     .write_type = write_type,
325                                     .value = std::move(value)});
326   gatt_execute_next_op(conn_id);
327 }
328 
ConfigureMtu(tCONN_ID conn_id,uint16_t mtu)329 void BtaGattQueue::ConfigureMtu(tCONN_ID conn_id, uint16_t mtu) {
330   log::info("mtu: {}", static_cast<int>(mtu));
331   std::vector<uint8_t> value = {static_cast<uint8_t>(mtu & 0xff), static_cast<uint8_t>(mtu >> 8)};
332   gatt_op_queue[conn_id].push_back({.type = GATT_CONFIG_MTU, .value = std::move(value)});
333   gatt_execute_next_op(conn_id);
334 }
335 
ReadMultiCharacteristic(tCONN_ID conn_id,tBTA_GATTC_MULTI & handles,GATT_READ_MULTI_OP_CB cb,void * cb_data)336 void BtaGattQueue::ReadMultiCharacteristic(tCONN_ID conn_id, tBTA_GATTC_MULTI& handles,
337                                            GATT_READ_MULTI_OP_CB cb, void* cb_data) {
338   gatt_op_queue[conn_id].push_back({.type = GATT_READ_MULTI,
339                                     .handles = handles,
340                                     .read_multi_cb = cb,
341                                     .read_cb_data = cb_data});
342   gatt_execute_next_op(conn_id);
343 }
344