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(&param, 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, &param) == 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