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