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 "bt_target.h"
22 #include "bt_utils.h"
23 #include "gatt_api.h"
24 #include "gatt_int.h"
25 #include "osi/include/log.h"
26 #include "osi/include/osi.h"
27 #include "srvc_dis_int.h"
28 #include "srvc_eng_int.h"
29
30 using base::StringPrintf;
31 #define DIS_MAX_NUM_INC_SVR 0
32 #define DIS_MAX_CHAR_NUM 9
33 #define DIS_MAX_ATTR_NUM (DIS_MAX_CHAR_NUM * 2 + DIS_MAX_NUM_INC_SVR + 1)
34
35 #ifndef DIS_ATTR_DB_SIZE
36 #define DIS_ATTR_DB_SIZE \
37 GATT_DB_MEM_SIZE(DIS_MAX_NUM_INC_SVR, DIS_MAX_CHAR_NUM, 0)
38 #endif
39
40 #define uint64_t_TO_STREAM(p, u64) \
41 { \
42 *(p)++ = (uint8_t)(u64); \
43 *(p)++ = (uint8_t)((u64) >> 8); \
44 *(p)++ = (uint8_t)((u64) >> 16); \
45 *(p)++ = (uint8_t)((u64) >> 24); \
46 *(p)++ = (uint8_t)((u64) >> 32); \
47 *(p)++ = (uint8_t)((u64) >> 40); \
48 *(p)++ = (uint8_t)((u64) >> 48); \
49 *(p)++ = (uint8_t)((u64) >> 56); \
50 }
51
52 static const uint16_t dis_attr_uuid[DIS_MAX_CHAR_NUM] = {
53 GATT_UUID_SYSTEM_ID,
54 GATT_UUID_MODEL_NUMBER_STR,
55 GATT_UUID_SERIAL_NUMBER_STR,
56 GATT_UUID_FW_VERSION_STR,
57 GATT_UUID_HW_VERSION_STR,
58 GATT_UUID_SW_VERSION_STR,
59 GATT_UUID_MANU_NAME,
60 GATT_UUID_IEEE_DATA,
61 GATT_UUID_PNP_ID};
62
63 tDIS_CB dis_cb;
64
dis_uuid_to_attr(uint16_t uuid)65 static tDIS_ATTR_MASK dis_uuid_to_attr(uint16_t uuid) {
66 switch (uuid) {
67 case GATT_UUID_SYSTEM_ID:
68 return DIS_ATTR_SYS_ID_BIT;
69 case GATT_UUID_MODEL_NUMBER_STR:
70 return DIS_ATTR_MODEL_NUM_BIT;
71 case GATT_UUID_SERIAL_NUMBER_STR:
72 return DIS_ATTR_SERIAL_NUM_BIT;
73 case GATT_UUID_FW_VERSION_STR:
74 return DIS_ATTR_FW_NUM_BIT;
75 case GATT_UUID_HW_VERSION_STR:
76 return DIS_ATTR_HW_NUM_BIT;
77 case GATT_UUID_SW_VERSION_STR:
78 return DIS_ATTR_SW_NUM_BIT;
79 case GATT_UUID_MANU_NAME:
80 return DIS_ATTR_MANU_NAME_BIT;
81 case GATT_UUID_IEEE_DATA:
82 return DIS_ATTR_IEEE_DATA_BIT;
83 case GATT_UUID_PNP_ID:
84 return DIS_ATTR_PNP_ID_BIT;
85 default:
86 return 0;
87 };
88 }
89
90 /*******************************************************************************
91 * dis_valid_handle_range
92 *
93 * validate a handle to be a DIS attribute handle or not.
94 ******************************************************************************/
dis_valid_handle_range(uint16_t handle)95 bool dis_valid_handle_range(uint16_t handle) {
96 if (handle >= dis_cb.service_handle && handle <= dis_cb.max_handle)
97 return true;
98 else
99 return false;
100 }
101 /*******************************************************************************
102 * dis_write_attr_value
103 *
104 * Process write DIS attribute request.
105 ******************************************************************************/
dis_write_attr_value(UNUSED_ATTR tGATT_WRITE_REQ * p_data,tGATT_STATUS * p_status)106 uint8_t dis_write_attr_value(UNUSED_ATTR tGATT_WRITE_REQ* p_data,
107 tGATT_STATUS* p_status) {
108 *p_status = GATT_WRITE_NOT_PERMIT;
109 return SRVC_ACT_RSP;
110 }
111 /*******************************************************************************
112 * DIS Attributes Database Server Request callback
113 ******************************************************************************/
dis_read_attr_value(UNUSED_ATTR uint8_t clcb_idx,uint16_t handle,tGATT_VALUE * p_value,bool is_long,tGATT_STATUS * p_status)114 uint8_t dis_read_attr_value(UNUSED_ATTR uint8_t clcb_idx, uint16_t handle,
115 tGATT_VALUE* p_value, bool is_long,
116 tGATT_STATUS* p_status) {
117 tDIS_DB_ENTRY* p_db_attr = dis_cb.dis_attr;
118 uint8_t *p = p_value->value, i, *pp;
119 uint16_t offset = p_value->offset;
120 uint8_t act = SRVC_ACT_RSP;
121 tGATT_STATUS st = GATT_NOT_FOUND;
122
123 for (i = 0; i < DIS_MAX_CHAR_NUM; i++, p_db_attr++) {
124 if (handle == p_db_attr->handle) {
125 if ((p_db_attr->uuid == GATT_UUID_PNP_ID ||
126 p_db_attr->uuid == GATT_UUID_SYSTEM_ID) &&
127 is_long) {
128 st = GATT_NOT_LONG;
129 break;
130 }
131 st = GATT_SUCCESS;
132
133 switch (p_db_attr->uuid) {
134 case GATT_UUID_MANU_NAME:
135 case GATT_UUID_MODEL_NUMBER_STR:
136 case GATT_UUID_SERIAL_NUMBER_STR:
137 case GATT_UUID_FW_VERSION_STR:
138 case GATT_UUID_HW_VERSION_STR:
139 case GATT_UUID_SW_VERSION_STR:
140 case GATT_UUID_IEEE_DATA:
141 pp = dis_cb.dis_value
142 .data_string[p_db_attr->uuid - GATT_UUID_MODEL_NUMBER_STR];
143 if (pp != NULL) {
144 if (strlen((char*)pp) > GATT_MAX_ATTR_LEN)
145 p_value->len = GATT_MAX_ATTR_LEN;
146 else
147 p_value->len = (uint16_t)strlen((char*)pp);
148 } else
149 p_value->len = 0;
150
151 if (offset > p_value->len) {
152 st = GATT_INVALID_OFFSET;
153 break;
154 } else {
155 p_value->len -= offset;
156 pp += offset;
157 ARRAY_TO_STREAM(p, pp, p_value->len);
158 VLOG(1) << "GATT_UUID_MANU_NAME len=0x" << std::hex
159 << +p_value->len;
160 }
161 break;
162
163 case GATT_UUID_SYSTEM_ID:
164 uint64_t_TO_STREAM(p, dis_cb.dis_value.system_id); /* int_min */
165 p_value->len = DIS_SYSTEM_ID_SIZE;
166 break;
167
168 case GATT_UUID_PNP_ID:
169 UINT8_TO_STREAM(p, dis_cb.dis_value.pnp_id.vendor_id_src);
170 UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.vendor_id);
171 UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.product_id);
172 UINT16_TO_STREAM(p, dis_cb.dis_value.pnp_id.product_version);
173 p_value->len = DIS_PNP_ID_SIZE;
174 break;
175 }
176 break;
177 }
178 }
179 *p_status = st;
180 return act;
181 }
182
183 /*******************************************************************************
184 *
185 * Function dis_gatt_c_read_dis_value_cmpl
186 *
187 * Description Client read DIS database complete callback.
188 *
189 * Returns void
190 *
191 ******************************************************************************/
dis_gatt_c_read_dis_value_cmpl(uint16_t conn_id)192 static void dis_gatt_c_read_dis_value_cmpl(uint16_t conn_id) {
193 tSRVC_CLCB* p_clcb = srvc_eng_find_clcb_by_conn_id(conn_id);
194
195 dis_cb.dis_read_uuid_idx = 0xff;
196
197 srvc_eng_release_channel(conn_id);
198
199 if (dis_cb.p_read_dis_cback && p_clcb) {
200 LOG_INFO("%s conn_id:%d attr_mask = 0x%04x", __func__, conn_id,
201 p_clcb->dis_value.attr_mask);
202
203 (*dis_cb.p_read_dis_cback)(p_clcb->bda, &p_clcb->dis_value);
204 dis_cb.p_read_dis_cback = NULL;
205 }
206 }
207
208 /*******************************************************************************
209 *
210 * Function dis_gatt_c_read_dis_req
211 *
212 * Description Read remote device DIS attribute request.
213 *
214 * Returns void
215 *
216 ******************************************************************************/
dis_gatt_c_read_dis_req(uint16_t conn_id)217 bool dis_gatt_c_read_dis_req(uint16_t conn_id) {
218 tGATT_READ_PARAM param;
219
220 memset(¶m, 0, sizeof(tGATT_READ_PARAM));
221
222 param.service.s_handle = 1;
223 param.service.e_handle = 0xFFFF;
224 param.service.auth_req = 0;
225
226 while (dis_cb.dis_read_uuid_idx < DIS_MAX_CHAR_NUM) {
227 if (dis_uuid_to_attr(dis_attr_uuid[dis_cb.dis_read_uuid_idx]) &
228 dis_cb.request_mask) {
229 param.service.uuid =
230 bluetooth::Uuid::From16Bit(dis_attr_uuid[dis_cb.dis_read_uuid_idx]);
231
232 if (GATTC_Read(conn_id, GATT_READ_BY_TYPE, ¶m) == GATT_SUCCESS)
233 return true;
234
235 LOG(ERROR) << "Read DISInfo: " << param.service.uuid
236 << " GATT_Read Failed";
237 }
238
239 dis_cb.dis_read_uuid_idx++;
240 }
241
242 dis_gatt_c_read_dis_value_cmpl(conn_id);
243
244 return (false);
245 }
246
247 /*******************************************************************************
248 *
249 * Function dis_c_cmpl_cback
250 *
251 * Description Client operation complete callback.
252 *
253 * Returns void
254 *
255 ******************************************************************************/
dis_c_cmpl_cback(tSRVC_CLCB * p_clcb,tGATTC_OPTYPE op,tGATT_STATUS status,tGATT_CL_COMPLETE * p_data)256 void dis_c_cmpl_cback(tSRVC_CLCB* p_clcb, tGATTC_OPTYPE op, tGATT_STATUS status,
257 tGATT_CL_COMPLETE* p_data) {
258 uint16_t read_type = dis_attr_uuid[dis_cb.dis_read_uuid_idx];
259 uint8_t *pp = NULL, *p_str;
260 uint16_t conn_id = p_clcb->conn_id;
261
262 VLOG(1) << __func__
263 << StringPrintf("op_code: 0x%02x status: 0x%02x read_type: 0x%04x",
264 op, status, read_type);
265
266 if (op != GATTC_OPTYPE_READ) return;
267
268 if (p_data != NULL && status == GATT_SUCCESS) {
269 pp = p_data->att_value.value;
270
271 switch (read_type) {
272 case GATT_UUID_SYSTEM_ID:
273 VLOG(1) << "DIS_ATTR_SYS_ID_BIT";
274 if (p_data->att_value.len == DIS_SYSTEM_ID_SIZE) {
275 p_clcb->dis_value.attr_mask |= DIS_ATTR_SYS_ID_BIT;
276 /* save system ID*/
277 STREAM_TO_UINT64(p_clcb->dis_value.system_id, pp);
278 }
279 break;
280
281 case GATT_UUID_PNP_ID:
282 if (p_data->att_value.len == DIS_PNP_ID_SIZE) {
283 p_clcb->dis_value.attr_mask |= DIS_ATTR_PNP_ID_BIT;
284 STREAM_TO_UINT8(p_clcb->dis_value.pnp_id.vendor_id_src, pp);
285 STREAM_TO_UINT16(p_clcb->dis_value.pnp_id.vendor_id, pp);
286 STREAM_TO_UINT16(p_clcb->dis_value.pnp_id.product_id, pp);
287 STREAM_TO_UINT16(p_clcb->dis_value.pnp_id.product_version, pp);
288 }
289 break;
290
291 case GATT_UUID_MODEL_NUMBER_STR:
292 case GATT_UUID_SERIAL_NUMBER_STR:
293 case GATT_UUID_FW_VERSION_STR:
294 case GATT_UUID_HW_VERSION_STR:
295 case GATT_UUID_SW_VERSION_STR:
296 case GATT_UUID_MANU_NAME:
297 case GATT_UUID_IEEE_DATA:
298 p_str = p_clcb->dis_value
299 .data_string[read_type - GATT_UUID_MODEL_NUMBER_STR];
300 osi_free(p_str);
301 p_str = (uint8_t*)osi_malloc(p_data->att_value.len + 1);
302 p_clcb->dis_value.attr_mask |= dis_uuid_to_attr(read_type);
303 memcpy(p_str, p_data->att_value.value, p_data->att_value.len);
304 p_str[p_data->att_value.len] = 0;
305 p_clcb->dis_value.data_string[read_type - GATT_UUID_MODEL_NUMBER_STR] =
306 p_str;
307 break;
308
309 default:
310 break;
311
312 break;
313 } /* end switch */
314 } /* end if */
315
316 dis_cb.dis_read_uuid_idx++;
317
318 dis_gatt_c_read_dis_req(conn_id);
319 }
320
321 /*******************************************************************************
322 *
323 * Function DIS_SrInit
324 *
325 * Description Initialize the Device Information Service Server.
326 *
327 ******************************************************************************/
DIS_SrInit(tDIS_ATTR_MASK dis_attr_mask)328 tDIS_STATUS DIS_SrInit(tDIS_ATTR_MASK dis_attr_mask) {
329 tGATT_STATUS status;
330
331 if (dis_cb.enabled) {
332 LOG(ERROR) << "DIS already initalized";
333 return DIS_SUCCESS;
334 }
335
336 memset(&dis_cb, 0, sizeof(tDIS_CB));
337
338 btgatt_db_element_t service[DIS_MAX_ATTR_NUM] = {};
339
340 bluetooth::Uuid svc_uuid =
341 bluetooth::Uuid::From16Bit(UUID_SERVCLASS_DEVICE_INFO);
342 service[0].type = BTGATT_DB_PRIMARY_SERVICE;
343 service[0].uuid = svc_uuid;
344
345 for (int i = 0; dis_attr_mask != 0 && i < DIS_MAX_CHAR_NUM; i++) {
346 dis_cb.dis_attr[i].uuid = dis_attr_uuid[i];
347
348 bluetooth::Uuid char_uuid =
349 bluetooth::Uuid::From16Bit(dis_cb.dis_attr[i].uuid);
350 /* index 0 is service, so characteristics start from 1 */
351 service[i + 1].type = BTGATT_DB_CHARACTERISTIC;
352 service[i + 1].uuid = char_uuid;
353 service[i + 1].properties = GATT_CHAR_PROP_BIT_READ;
354 service[i + 1].permissions = GATT_PERM_READ;
355
356 dis_attr_mask >>= 1;
357 }
358
359 /* Add a GAP service */
360 status = GATTS_AddService(srvc_eng_cb.gatt_if, service,
361 sizeof(service) / sizeof(btgatt_db_element_t));
362 if (status != GATT_SERVICE_STARTED) {
363 LOG(ERROR) << "Can not create service, DIS_Init failed!";
364 return GATT_ERROR;
365 }
366
367 dis_cb.service_handle = service[0].attribute_handle;
368 dis_cb.max_handle = dis_cb.service_handle + DIS_MAX_ATTR_NUM;
369
370 for (int i = 0; i < DIS_MAX_CHAR_NUM; i++) {
371 dis_cb.dis_attr[i].handle = service[i + 1].attribute_handle;
372
373 VLOG(1) << StringPrintf("%s: handle of new attribute 0x%04x = %d",
374 __func__, dis_cb.dis_attr[i].uuid,
375 dis_cb.dis_attr[i].handle);
376 }
377
378 dis_cb.enabled = true;
379 return (tDIS_STATUS)status;
380 }
381 /*******************************************************************************
382 *
383 * Function DIS_SrUpdate
384 *
385 * Description Update the DIS server attribute values
386 *
387 ******************************************************************************/
DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit,tDIS_ATTR * p_info)388 tDIS_STATUS DIS_SrUpdate(tDIS_ATTR_BIT dis_attr_bit, tDIS_ATTR* p_info) {
389 uint8_t i = 1;
390 tDIS_STATUS st = DIS_SUCCESS;
391
392 if (dis_attr_bit & DIS_ATTR_SYS_ID_BIT) {
393 dis_cb.dis_value.system_id = p_info->system_id;
394 } else if (dis_attr_bit & DIS_ATTR_PNP_ID_BIT) {
395 dis_cb.dis_value.pnp_id.vendor_id = p_info->pnp_id.vendor_id;
396 dis_cb.dis_value.pnp_id.vendor_id_src = p_info->pnp_id.vendor_id_src;
397 dis_cb.dis_value.pnp_id.product_id = p_info->pnp_id.product_id;
398 dis_cb.dis_value.pnp_id.product_version = p_info->pnp_id.product_version;
399 } else {
400 st = DIS_ILLEGAL_PARAM;
401
402 while (dis_attr_bit && i < (DIS_MAX_CHAR_NUM - 1)) {
403 if (dis_attr_bit & (uint16_t)(1 << i)) {
404 osi_free(dis_cb.dis_value.data_string[i - 1]);
405 dis_cb.dis_value.data_string[i - 1] =
406 (uint8_t*)osi_malloc(p_info->data_str.len + 1);
407 memcpy(dis_cb.dis_value.data_string[i - 1], p_info->data_str.p_data,
408 p_info->data_str.len);
409 dis_cb.dis_value.data_string[i - 1][p_info->data_str.len] =
410 0; /* make sure null terminate */
411 st = DIS_SUCCESS;
412
413 break;
414 }
415 i++;
416 }
417 }
418 return st;
419 }
420 /*******************************************************************************
421 *
422 * Function DIS_ReadDISInfo
423 *
424 * Description Read remote device DIS information.
425 *
426 * Returns void
427 *
428 ******************************************************************************/
DIS_ReadDISInfo(const RawAddress & peer_bda,tDIS_READ_CBACK * p_cback,tDIS_ATTR_MASK mask)429 bool DIS_ReadDISInfo(const RawAddress& peer_bda, tDIS_READ_CBACK* p_cback,
430 tDIS_ATTR_MASK mask) {
431 uint16_t conn_id;
432
433 /* Initialize the DIS client if it hasn't been initialized already. */
434 srvc_eng_init();
435
436 /* For now we only handle one at a time */
437 if (dis_cb.dis_read_uuid_idx != 0xff) return (false);
438
439 if (p_cback == NULL) return (false);
440
441 dis_cb.p_read_dis_cback = p_cback;
442 /* Mark currently active operation */
443 dis_cb.dis_read_uuid_idx = 0;
444
445 dis_cb.request_mask = mask;
446
447 VLOG(1) << __func__ << " BDA: " << peer_bda
448 << StringPrintf(" cl_read_uuid: 0x%04x",
449 dis_attr_uuid[dis_cb.dis_read_uuid_idx]);
450
451 GATT_GetConnIdIfConnected(srvc_eng_cb.gatt_if, peer_bda, &conn_id,
452 BT_TRANSPORT_LE);
453
454 /* need to enhance it as multiple service is needed */
455 srvc_eng_request_channel(peer_bda, SRVC_ID_DIS);
456
457 if (conn_id == GATT_INVALID_CONN_ID) {
458 return GATT_Connect(srvc_eng_cb.gatt_if, peer_bda, true, BT_TRANSPORT_LE,
459 false);
460 }
461
462 return dis_gatt_c_read_dis_req(conn_id);
463 }
464