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_execute_next_op(tCONN_ID conn_id)148 void BtaGattQueue::gatt_execute_next_op(tCONN_ID conn_id) {
149 log::verbose("conn_id=0x{:x}", conn_id);
150 if (gatt_op_queue.empty()) {
151 log::verbose("op queue is empty");
152 return;
153 }
154
155 auto map_ptr = gatt_op_queue.find(conn_id);
156 if (map_ptr == gatt_op_queue.end() || map_ptr->second.empty()) {
157 log::verbose("no more operations queued for conn_id {}", conn_id);
158 return;
159 }
160
161 if (gatt_op_queue_executing.count(conn_id)) {
162 log::verbose("can't enqueue next op, already executing");
163 return;
164 }
165
166 gatt_op_queue_executing.insert(conn_id);
167
168 std::list<gatt_operation>& gatt_ops = map_ptr->second;
169
170 gatt_operation& op = gatt_ops.front();
171
172 if (op.type == GATT_READ_CHAR) {
173 gatt_read_op_data* data = (gatt_read_op_data*)osi_malloc(sizeof(gatt_read_op_data));
174 data->cb = op.read_cb;
175 data->cb_data = op.read_cb_data;
176 BTA_GATTC_ReadCharacteristic(conn_id, op.handle, GATT_AUTH_REQ_NONE, gatt_read_op_finished,
177 data);
178
179 } else if (op.type == GATT_READ_DESC) {
180 gatt_read_op_data* data = (gatt_read_op_data*)osi_malloc(sizeof(gatt_read_op_data));
181 data->cb = op.read_cb;
182 data->cb_data = op.read_cb_data;
183 BTA_GATTC_ReadCharDescr(conn_id, op.handle, GATT_AUTH_REQ_NONE, gatt_read_op_finished, data);
184
185 } else if (op.type == GATT_WRITE_CHAR) {
186 gatt_write_op_data* data = (gatt_write_op_data*)osi_malloc(sizeof(gatt_write_op_data));
187 data->cb = op.write_cb;
188 data->cb_data = op.write_cb_data;
189 BTA_GATTC_WriteCharValue(conn_id, op.handle, op.write_type, std::move(op.value),
190 GATT_AUTH_REQ_NONE, gatt_write_op_finished, data);
191
192 } else if (op.type == GATT_WRITE_DESC) {
193 gatt_write_op_data* data = (gatt_write_op_data*)osi_malloc(sizeof(gatt_write_op_data));
194 data->cb = op.write_cb;
195 data->cb_data = op.write_cb_data;
196 BTA_GATTC_WriteCharDescr(conn_id, op.handle, std::move(op.value), GATT_AUTH_REQ_NONE,
197 gatt_write_op_finished, data);
198 } else if (op.type == GATT_CONFIG_MTU) {
199 gatt_configure_mtu_op_data* data =
200 (gatt_configure_mtu_op_data*)osi_malloc(sizeof(gatt_configure_mtu_op_data));
201 data->cb = op.mtu_cb;
202 data->cb_data = op.mtu_cb_data;
203 BTA_GATTC_ConfigureMTU(conn_id, static_cast<uint16_t>(op.value[0] | (op.value[1] << 8)),
204 gatt_configure_mtu_op_finished, data);
205 } else if (op.type == GATT_READ_MULTI) {
206 if (gatt_profile_get_eatt_support_by_conn_id(conn_id)) {
207 gatt_read_multi_op_data* data =
208 (gatt_read_multi_op_data*)osi_malloc(sizeof(gatt_read_multi_op_data));
209 data->cb = op.read_multi_cb;
210 data->cb_data = op.read_cb_data;
211 BTA_GATTC_ReadMultiple(conn_id, op.handles, true, GATT_AUTH_REQ_NONE,
212 gatt_read_multi_op_finished, data);
213 }
214 }
215
216 gatt_ops.pop_front();
217 }
218
Clean(tCONN_ID conn_id)219 void BtaGattQueue::Clean(tCONN_ID conn_id) {
220 gatt_op_queue.erase(conn_id);
221 gatt_op_queue_executing.erase(conn_id);
222 }
223
ReadCharacteristic(tCONN_ID conn_id,uint16_t handle,GATT_READ_OP_CB cb,void * cb_data)224 void BtaGattQueue::ReadCharacteristic(tCONN_ID conn_id, uint16_t handle, GATT_READ_OP_CB cb,
225 void* cb_data) {
226 gatt_op_queue[conn_id].push_back(
227 {.type = GATT_READ_CHAR, .handle = handle, .read_cb = cb, .read_cb_data = cb_data});
228 gatt_execute_next_op(conn_id);
229 }
230
ReadDescriptor(tCONN_ID conn_id,uint16_t handle,GATT_READ_OP_CB cb,void * cb_data)231 void BtaGattQueue::ReadDescriptor(tCONN_ID conn_id, uint16_t handle, GATT_READ_OP_CB cb,
232 void* cb_data) {
233 gatt_op_queue[conn_id].push_back(
234 {.type = GATT_READ_DESC, .handle = handle, .read_cb = cb, .read_cb_data = cb_data});
235 gatt_execute_next_op(conn_id);
236 }
237
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)238 void BtaGattQueue::WriteCharacteristic(tCONN_ID conn_id, uint16_t handle,
239 std::vector<uint8_t> value, tGATT_WRITE_TYPE write_type,
240 GATT_WRITE_OP_CB cb, void* cb_data) {
241 gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_CHAR,
242 .handle = handle,
243 .write_cb = cb,
244 .write_cb_data = cb_data,
245 .write_type = write_type,
246 .value = std::move(value)});
247 gatt_execute_next_op(conn_id);
248 }
249
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)250 void BtaGattQueue::WriteDescriptor(tCONN_ID conn_id, uint16_t handle, std::vector<uint8_t> value,
251 tGATT_WRITE_TYPE write_type, GATT_WRITE_OP_CB cb,
252 void* cb_data) {
253 gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_DESC,
254 .handle = handle,
255 .write_cb = cb,
256 .write_cb_data = cb_data,
257 .write_type = write_type,
258 .value = std::move(value)});
259 gatt_execute_next_op(conn_id);
260 }
261
ConfigureMtu(tCONN_ID conn_id,uint16_t mtu)262 void BtaGattQueue::ConfigureMtu(tCONN_ID conn_id, uint16_t mtu) {
263 log::info("mtu: {}", static_cast<int>(mtu));
264 std::vector<uint8_t> value = {static_cast<uint8_t>(mtu & 0xff), static_cast<uint8_t>(mtu >> 8)};
265 gatt_op_queue[conn_id].push_back({.type = GATT_CONFIG_MTU, .value = std::move(value)});
266 gatt_execute_next_op(conn_id);
267 }
268
ReadMultiCharacteristic(tCONN_ID conn_id,tBTA_GATTC_MULTI & handles,GATT_READ_MULTI_OP_CB cb,void * cb_data)269 bool BtaGattQueue::ReadMultiCharacteristic(tCONN_ID conn_id, tBTA_GATTC_MULTI& handles,
270 GATT_READ_MULTI_OP_CB cb, void* cb_data) {
271 if (!gatt_profile_get_eatt_support_by_conn_id(conn_id)) {
272 return false;
273 }
274 gatt_op_queue[conn_id].push_back({.type = GATT_READ_MULTI,
275 .handles = handles,
276 .read_multi_cb = cb,
277 .read_cb_data = cb_data});
278 gatt_execute_next_op(conn_id);
279 return true;
280 }
281