1 /******************************************************************************
2 *
3 * Copyright 1999-2013 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #define LOG_TAG "bt_srvc"
20
21 #include <bluetooth/log.h>
22 #include <com_android_bluetooth_flags.h>
23
24 #include "gatt_api.h"
25 #include "hardware/bt_gatt_types.h"
26 #include "osi/include/allocator.h"
27 #include "osi/include/osi.h"
28 #include "srvc_dis_int.h"
29 #include "srvc_eng_int.h"
30 #include "stack/include/bt_types.h"
31 #include "stack/include/bt_uuid16.h"
32 #include "types/bluetooth/uuid.h"
33 #include "types/raw_address.h"
34
35 using namespace bluetooth;
36
37 static const uint16_t dis_attr_uuid[] = {
38 GATT_UUID_SYSTEM_ID, GATT_UUID_MODEL_NUMBER_STR, GATT_UUID_SERIAL_NUMBER_STR,
39 GATT_UUID_FW_VERSION_STR, GATT_UUID_HW_VERSION_STR, GATT_UUID_SW_VERSION_STR,
40 GATT_UUID_MANU_NAME, GATT_UUID_IEEE_DATA, GATT_UUID_PNP_ID};
41
42 tDIS_CB dis_cb;
43
dis_uuid_to_attr(uint16_t uuid)44 static tDIS_ATTR_MASK dis_uuid_to_attr(uint16_t uuid) {
45 switch (uuid) {
46 case GATT_UUID_SYSTEM_ID:
47 return DIS_ATTR_SYS_ID_BIT;
48 case GATT_UUID_MODEL_NUMBER_STR:
49 return DIS_ATTR_MODEL_NUM_BIT;
50 case GATT_UUID_SERIAL_NUMBER_STR:
51 return DIS_ATTR_SERIAL_NUM_BIT;
52 case GATT_UUID_FW_VERSION_STR:
53 return DIS_ATTR_FW_NUM_BIT;
54 case GATT_UUID_HW_VERSION_STR:
55 return DIS_ATTR_HW_NUM_BIT;
56 case GATT_UUID_SW_VERSION_STR:
57 return DIS_ATTR_SW_NUM_BIT;
58 case GATT_UUID_MANU_NAME:
59 return DIS_ATTR_MANU_NAME_BIT;
60 case GATT_UUID_IEEE_DATA:
61 return DIS_ATTR_IEEE_DATA_BIT;
62 case GATT_UUID_PNP_ID:
63 return DIS_ATTR_PNP_ID_BIT;
64 default:
65 return 0;
66 };
67 }
68
69 /*******************************************************************************
70 *
71 * Function dis_gatt_c_read_dis_value_cmpl
72 *
73 * Description Client read DIS database complete callback.
74 *
75 * Returns void
76 *
77 ******************************************************************************/
dis_gatt_c_read_dis_value_cmpl(tCONN_ID conn_id)78 static void dis_gatt_c_read_dis_value_cmpl(tCONN_ID conn_id) {
79 tSRVC_CLCB* p_clcb = srvc_eng_find_clcb_by_conn_id(conn_id);
80
81 dis_cb.dis_read_uuid_idx = 0xff;
82
83 srvc_eng_release_channel(conn_id);
84
85 if (dis_cb.p_read_dis_cback && p_clcb) {
86 log::info("conn_id:{} attr_mask = 0x{:04x}", conn_id, p_clcb->dis_value.attr_mask);
87
88 (*dis_cb.p_read_dis_cback)(p_clcb->bda, &p_clcb->dis_value);
89 dis_cb.p_read_dis_cback = NULL;
90 }
91
92 if (com::android::bluetooth::flags::queue_dis_requests()) {
93 while (!dis_cb.pend_reqs.empty()) {
94 tDIS_REQ req = dis_cb.pend_reqs.front();
95 dis_cb.pend_reqs.pop();
96 log::info("Dequeue pending DIS request. Address:{}, mask:0x{:04x}", req.addr, req.mask);
97
98 /* only process the pending DIS if the device is connected */
99 uint16_t _conn_id;
100 if (GATT_GetConnIdIfConnected(srvc_eng_cb.gatt_if, req.addr, &_conn_id, BT_TRANSPORT_LE) &&
101 DIS_ReadDISInfo(req.addr, req.p_read_dis_cback, req.mask)) {
102 break;
103 } else if (req.p_read_dis_cback) {
104 tDIS_VALUE empty = {};
105 req.p_read_dis_cback(req.addr, &empty);
106 }
107 }
108 }
109 }
110
111 /*******************************************************************************
112 *
113 * Function dis_gatt_c_read_dis_req
114 *
115 * Description Read remote device DIS attribute request.
116 *
117 * Returns void
118 *
119 ******************************************************************************/
dis_gatt_c_read_dis_req(tCONN_ID conn_id)120 static bool dis_gatt_c_read_dis_req(tCONN_ID conn_id) {
121 tGATT_READ_PARAM param;
122
123 memset(¶m, 0, sizeof(tGATT_READ_PARAM));
124
125 param.service.s_handle = 1;
126 param.service.e_handle = 0xFFFF;
127 param.service.auth_req = 0;
128
129 while (dis_cb.dis_read_uuid_idx < (sizeof(dis_attr_uuid) / sizeof(dis_attr_uuid[0]))) {
130 if (dis_uuid_to_attr(dis_attr_uuid[dis_cb.dis_read_uuid_idx]) & dis_cb.request_mask) {
131 param.service.uuid = bluetooth::Uuid::From16Bit(dis_attr_uuid[dis_cb.dis_read_uuid_idx]);
132
133 if (GATTC_Read(conn_id, GATT_READ_BY_TYPE, ¶m) == GATT_SUCCESS) {
134 return true;
135 }
136
137 log::error("Read DISInfo: {} GATT_Read Failed", param.service.uuid);
138 }
139
140 dis_cb.dis_read_uuid_idx++;
141 }
142
143 dis_gatt_c_read_dis_value_cmpl(conn_id);
144
145 return false;
146 }
147
148 /*******************************************************************************
149 *
150 * Function dis_c_cmpl_cback
151 *
152 * Description Client operation complete callback.
153 *
154 * Returns void
155 *
156 ******************************************************************************/
dis_c_cmpl_cback(tSRVC_CLCB * p_clcb,tGATTC_OPTYPE op,tGATT_STATUS status,tGATT_CL_COMPLETE * p_data)157 void dis_c_cmpl_cback(tSRVC_CLCB* p_clcb, tGATTC_OPTYPE op, tGATT_STATUS status,
158 tGATT_CL_COMPLETE* p_data) {
159 uint16_t read_type;
160 uint8_t *pp = NULL, *p_str;
161 tCONN_ID conn_id = p_clcb->conn_id;
162
163 if (dis_cb.dis_read_uuid_idx >= (sizeof(dis_attr_uuid) / sizeof(dis_attr_uuid[0]))) {
164 log::error("invalid dis_cb.dis_read_uuid_idx");
165 return;
166 }
167
168 read_type = dis_attr_uuid[dis_cb.dis_read_uuid_idx];
169
170 log::verbose("op_code: 0x{:02x} status: 0x{:02x} read_type: 0x{:04x}", op, status, read_type);
171
172 if (op != GATTC_OPTYPE_READ) {
173 return;
174 }
175
176 if (p_data != NULL && status == GATT_SUCCESS) {
177 pp = p_data->att_value.value;
178
179 switch (read_type) {
180 case GATT_UUID_SYSTEM_ID:
181 log::verbose("DIS_ATTR_SYS_ID_BIT");
182 if (p_data->att_value.len == DIS_SYSTEM_ID_SIZE) {
183 p_clcb->dis_value.attr_mask |= DIS_ATTR_SYS_ID_BIT;
184 /* save system ID*/
185 STREAM_TO_UINT64(p_clcb->dis_value.system_id, pp);
186 }
187 break;
188
189 case GATT_UUID_PNP_ID:
190 if (p_data->att_value.len == DIS_PNP_ID_SIZE) {
191 p_clcb->dis_value.attr_mask |= DIS_ATTR_PNP_ID_BIT;
192 STREAM_TO_UINT8(p_clcb->dis_value.pnp_id.vendor_id_src, pp);
193 STREAM_TO_UINT16(p_clcb->dis_value.pnp_id.vendor_id, pp);
194 STREAM_TO_UINT16(p_clcb->dis_value.pnp_id.product_id, pp);
195 STREAM_TO_UINT16(p_clcb->dis_value.pnp_id.product_version, pp);
196 }
197 break;
198
199 case GATT_UUID_MODEL_NUMBER_STR:
200 case GATT_UUID_SERIAL_NUMBER_STR:
201 case GATT_UUID_FW_VERSION_STR:
202 case GATT_UUID_HW_VERSION_STR:
203 case GATT_UUID_SW_VERSION_STR:
204 case GATT_UUID_MANU_NAME:
205 case GATT_UUID_IEEE_DATA:
206 p_str = p_clcb->dis_value.data_string[read_type - GATT_UUID_MODEL_NUMBER_STR];
207 osi_free(p_str);
208 p_str = (uint8_t*)osi_malloc(p_data->att_value.len + 1);
209 p_clcb->dis_value.attr_mask |= dis_uuid_to_attr(read_type);
210 memcpy(p_str, p_data->att_value.value, p_data->att_value.len);
211 p_str[p_data->att_value.len] = 0;
212 p_clcb->dis_value.data_string[read_type - GATT_UUID_MODEL_NUMBER_STR] = p_str;
213 break;
214
215 default:
216 break;
217
218 break;
219 } /* end switch */
220 } /* end if */
221
222 dis_cb.dis_read_uuid_idx++;
223
224 dis_gatt_c_read_dis_req(conn_id);
225 }
226
227 /*******************************************************************************
228 *
229 * Function DIS_ReadDISInfo
230 *
231 * Description Read remote device DIS information.
232 *
233 * Returns true on success, false otherwise
234 *
235 ******************************************************************************/
DIS_ReadDISInfo(const RawAddress & peer_bda,tDIS_READ_CBACK * p_cback,tDIS_ATTR_MASK mask)236 bool DIS_ReadDISInfo(const RawAddress& peer_bda, tDIS_READ_CBACK* p_cback, tDIS_ATTR_MASK mask) {
237 tCONN_ID conn_id;
238
239 /* Initialize the DIS client if it hasn't been initialized already. */
240 srvc_eng_init();
241
242 if (p_cback == NULL) {
243 return false;
244 }
245
246 if (dis_cb.dis_read_uuid_idx != 0xff) {
247 if (!com::android::bluetooth::flags::queue_dis_requests()) {
248 /* For now we only handle one at a time */
249 return false;
250 }
251 /* GATT is busy, so let's queue the request */
252 tDIS_REQ req = {
253 .p_read_dis_cback = p_cback,
254 .mask = mask,
255 .addr = peer_bda,
256 };
257 dis_cb.pend_reqs.push(req);
258
259 return true;
260 }
261
262 if (com::android::bluetooth::flags::queue_dis_requests()) {
263 /* For now, we don't serve the request if GATT isn't connected.
264 * We need to call GATT_Connect and implement the handler for both success and failure case. */
265 if (!GATT_GetConnIdIfConnected(srvc_eng_cb.gatt_if, peer_bda, &conn_id, BT_TRANSPORT_LE)) {
266 return false;
267 }
268 }
269
270 dis_cb.p_read_dis_cback = p_cback;
271 /* Mark currently active operation */
272 dis_cb.dis_read_uuid_idx = 0;
273
274 dis_cb.request_mask = mask;
275
276 log::verbose("BDA: {} cl_read_uuid: 0x{:04x}", peer_bda, dis_attr_uuid[dis_cb.dis_read_uuid_idx]);
277
278 /* need to enhance it as multiple service is needed */
279 srvc_eng_request_channel(peer_bda, SRVC_ID_DIS);
280
281 if (!com::android::bluetooth::flags::queue_dis_requests()) {
282 if (!GATT_GetConnIdIfConnected(srvc_eng_cb.gatt_if, peer_bda, &conn_id, BT_TRANSPORT_LE)) {
283 conn_id = GATT_INVALID_CONN_ID;
284 }
285
286 if (conn_id == GATT_INVALID_CONN_ID) {
287 return GATT_Connect(srvc_eng_cb.gatt_if, peer_bda, BTM_BLE_DIRECT_CONNECTION, BT_TRANSPORT_LE,
288 false);
289 }
290 }
291
292 return dis_gatt_c_read_dis_req(conn_id);
293 }
294