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