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 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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(LOG_TAG, "%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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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