1 /****************************************************************************** 2 * 3 * Copyright (C) 1999-2012 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 /****************************************************************************** 20 * 21 * this file contains GATT interface functions 22 * 23 ******************************************************************************/ 24 #include "bt_target.h" 25 26 27 #if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE) 28 29 #include "gki.h" 30 #include <stdio.h> 31 #include <string.h> 32 #include "gatt_api.h" 33 #include "gatt_int.h" 34 #include "l2c_api.h" 35 #include "btm_int.h" 36 37 38 /******************************************************************************* 39 ** 40 ** Function GATT_SetTraceLevel 41 ** 42 ** Description This function sets the trace level. If called with 43 ** a value of 0xFF, it simply returns the current trace level. 44 ** 45 ** Input Parameters: 46 ** level: The level to set the GATT tracing to: 47 ** 0xff-returns the current setting. 48 ** 0-turns off tracing. 49 ** >= 1-Errors. 50 ** >= 2-Warnings. 51 ** >= 3-APIs. 52 ** >= 4-Events. 53 ** >= 5-Debug. 54 ** 55 ** Returns The new or current trace level 56 ** 57 *******************************************************************************/ 58 UINT8 GATT_SetTraceLevel (UINT8 new_level) 59 { 60 if (new_level != 0xFF) 61 gatt_cb.trace_level = new_level; 62 63 return(gatt_cb.trace_level); 64 } 65 66 /***************************************************************************** 67 ** 68 ** GATT SERVER API 69 ** 70 ******************************************************************************/ 71 /******************************************************************************* 72 ** 73 ** Function GATTS_AddHandleRange 74 ** 75 ** Description This function add the allocated handles range for the specifed 76 ** application UUID, service UUID and service instance 77 ** 78 ** Parameter p_hndl_range: pointer to allocated handles information 79 ** 80 ** Returns TRUE if handle range is added sucessfully; otherwise FALSE. 81 ** 82 *******************************************************************************/ 83 84 BOOLEAN GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range) 85 { 86 tGATT_HDL_LIST_ELEM *p_buf; 87 BOOLEAN status= FALSE; 88 89 if ((p_buf = gatt_alloc_hdl_buffer()) != NULL) 90 { 91 p_buf->asgn_range = *p_hndl_range; 92 status = gatt_add_an_item_to_list(&gatt_cb.hdl_list_info, p_buf); 93 } 94 return status; 95 } 96 97 98 /******************************************************************************* 99 ** 100 ** Function GATTS_NVRegister 101 ** 102 ** Description Application manager calls this function to register for 103 ** NV save callback function. There can be one and only one 104 ** NV save callback function. 105 ** 106 ** Parameter p_cb_info : callback informaiton 107 ** 108 ** Returns TRUE if registered OK, else FALSE 109 ** 110 *******************************************************************************/ 111 BOOLEAN GATTS_NVRegister (tGATT_APPL_INFO *p_cb_info) 112 { 113 BOOLEAN status= FALSE; 114 if (p_cb_info) 115 { 116 gatt_cb.cb_info = *p_cb_info; 117 status = TRUE; 118 gatt_init_srv_chg(); 119 } 120 121 return status; 122 } 123 124 /******************************************************************************* 125 ** 126 ** Function GATTS_CreateService 127 ** 128 ** Description This function is called to reserve a block of handles for a service. 129 ** 130 ** *** It should be called only once per service instance *** 131 ** 132 ** Parameter gatt_if : application if 133 ** p_svc_uuid : service UUID 134 ** svc_inst : instance of the service inside the application 135 ** num_handles : number of handles needed by the service. 136 ** is_pri : is a primary service or not. 137 ** 138 ** Returns service handle if sucessful, otherwise 0. 139 ** 140 *******************************************************************************/ 141 UINT16 GATTS_CreateService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, 142 UINT16 svc_inst, UINT16 num_handles, BOOLEAN is_pri) 143 { 144 145 tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info; 146 tGATT_HDL_LIST_ELEM *p_list=NULL; 147 UINT16 s_hdl=0; 148 BOOLEAN save_hdl=FALSE; 149 tGATTS_PENDING_NEW_SRV_START *p_buf=NULL; 150 tGATT_REG *p_reg = gatt_get_regcb(gatt_if); 151 tBT_UUID *p_app_uuid128; 152 153 154 GATT_TRACE_API0 ("GATTS_CreateService" ); 155 156 if (p_reg == NULL) 157 { 158 GATT_TRACE_ERROR1 ("Inavlid gatt_if=%d", gatt_if); 159 return(0); 160 } 161 162 p_app_uuid128 = &p_reg->app_uuid128; 163 164 if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) != NULL) 165 { 166 s_hdl = p_list->asgn_range.s_handle; 167 GATT_TRACE_DEBUG0 ("Service already been created!!"); 168 } 169 else 170 { 171 if ( (p_svc_uuid->len == LEN_UUID_16) && (p_svc_uuid->uu.uuid16 == UUID_SERVCLASS_GATT_SERVER)) 172 { 173 s_hdl= gatt_cb.hdl_cfg.gatt_start_hdl; 174 } 175 else if ((p_svc_uuid->len == LEN_UUID_16) && (p_svc_uuid->uu.uuid16 == UUID_SERVCLASS_GAP_SERVER)) 176 { 177 s_hdl= gatt_cb.hdl_cfg.gap_start_hdl; 178 } 179 else 180 { 181 p_list = p_list_info->p_first; 182 183 if (p_list) 184 { 185 s_hdl = p_list->asgn_range.e_handle + 1; 186 } 187 188 if (s_hdl < gatt_cb.hdl_cfg.app_start_hdl) 189 { 190 191 s_hdl= gatt_cb.hdl_cfg.app_start_hdl; 192 } 193 save_hdl = TRUE; 194 } 195 196 /* check for space */ 197 if (num_handles > (0xFFFF - s_hdl + 1)) 198 { 199 GATT_TRACE_ERROR2 ("GATTS_ReserveHandles: no handles, s_hdl: %u needed: %u", s_hdl, num_handles); 200 return(0); 201 } 202 203 if ( (p_list = gatt_alloc_hdl_buffer()) == NULL) 204 { 205 /* No free entry */ 206 GATT_TRACE_ERROR0 ("GATTS_ReserveHandles: no free handle blocks"); 207 return(0); 208 } 209 210 p_list->asgn_range.app_uuid128 = *p_app_uuid128; 211 p_list->asgn_range.svc_uuid = *p_svc_uuid; 212 p_list->asgn_range.svc_inst = svc_inst; 213 p_list->asgn_range.s_handle = s_hdl; 214 p_list->asgn_range.e_handle = s_hdl+num_handles-1; 215 p_list->asgn_range.is_primary = is_pri; 216 217 gatt_add_an_item_to_list(p_list_info, p_list); 218 219 if (save_hdl) 220 { 221 if (gatt_cb.cb_info.p_nv_save_callback) 222 (*gatt_cb.cb_info.p_nv_save_callback)(TRUE, &p_list->asgn_range); 223 /* add a pending new service change item to the list */ 224 if ( (p_buf = gatt_add_pending_new_srv_start(&p_list->asgn_range)) == NULL) 225 { 226 /* No free entry */ 227 GATT_TRACE_ERROR0 ("gatt_add_pending_new_srv_start: no free blocks"); 228 229 if (p_list) 230 { 231 gatt_remove_an_item_from_list(p_list_info, p_list); 232 gatt_free_hdl_buffer(p_list); 233 } 234 return(0); 235 } 236 237 GATT_TRACE_DEBUG0 ("Add a new srv chg item"); 238 } 239 } 240 241 if (!gatts_init_service_db(&p_list->svc_db, *p_svc_uuid, is_pri, s_hdl , num_handles)) 242 { 243 GATT_TRACE_ERROR0 ("GATTS_ReserveHandles: service DB initialization failed"); 244 if (p_list) 245 { 246 gatt_remove_an_item_from_list(p_list_info, p_list); 247 gatt_free_hdl_buffer(p_list); 248 } 249 250 if (p_buf) 251 GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf)); 252 return(0); 253 } 254 255 GATT_TRACE_DEBUG6 ("GATTS_CreateService(success): handles needed:%u s_hdl=%u e_hdl=%u %s[%x] is_primary=%d", 256 num_handles, p_list->asgn_range.s_handle , p_list->asgn_range.e_handle, 257 ((p_list->asgn_range.svc_uuid.len == 2) ? "uuid16": "uuid128" ), 258 p_list->asgn_range.svc_uuid.uu.uuid16, 259 p_list->asgn_range.is_primary); 260 261 return(s_hdl); 262 } 263 264 /******************************************************************************* 265 ** 266 ** Function GATTS_AddIncludeService 267 ** 268 ** Description This function is called to add an included service. 269 ** 270 ** Parameter service_handle : To which service this included service is added to. 271 ** include_svc_handle : included service handle. 272 ** 273 ** Returns included service attribute handle. If 0, add included service 274 ** fail. 275 ** 276 *******************************************************************************/ 277 UINT16 GATTS_AddIncludeService (UINT16 service_handle, UINT16 include_svc_handle) 278 279 { 280 tGATT_HDL_LIST_ELEM *p_decl, *p_incl_decl; 281 282 if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) 283 { 284 GATT_TRACE_DEBUG0("Service not created"); 285 return 0; 286 } 287 if ((p_incl_decl = gatt_find_hdl_buffer_by_handle(include_svc_handle)) == NULL) 288 { 289 GATT_TRACE_DEBUG0("Included Service not created"); 290 return 0; 291 } 292 293 return gatts_add_included_service(&p_decl->svc_db, 294 p_incl_decl->asgn_range.s_handle, 295 p_incl_decl->asgn_range.e_handle, 296 p_incl_decl->asgn_range.svc_uuid); 297 } 298 /******************************************************************************* 299 ** 300 ** Function GATTS_AddCharacteristic 301 ** 302 ** Description This function is called to add a characteristic into a service. 303 ** It will add a characteristic declaration and characteristic 304 ** value declaration into the service database identified by the 305 ** service handle. 306 ** 307 ** Parameter service_handle : To which service this included service is added to. 308 ** char_uuid : Characteristic UUID. 309 ** perm : Characteristic value declaration attribute permission. 310 ** property : Characteristic Properties 311 ** 312 ** Returns Characteristic value declaration attribute handle. 0 if failed. 313 ** 314 *******************************************************************************/ 315 UINT16 GATTS_AddCharacteristic (UINT16 service_handle, tBT_UUID *p_char_uuid, 316 tGATT_PERM perm,tGATT_CHAR_PROP property) 317 { 318 tGATT_HDL_LIST_ELEM *p_decl; 319 320 if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) 321 { 322 GATT_TRACE_DEBUG0("Service not created"); 323 return 0; 324 } 325 /* data validity checking */ 326 if ( ((property & GATT_CHAR_PROP_BIT_AUTH) && !(perm & GATT_WRITE_SIGNED_PERM)) || 327 ((perm & GATT_WRITE_SIGNED_PERM) && !(property & GATT_CHAR_PROP_BIT_AUTH)) ) 328 { 329 GATT_TRACE_DEBUG2("Invalid configuration property=0x%x perm=0x%x ", property, perm); 330 return 0; 331 } 332 333 return gatts_add_characteristic(&p_decl->svc_db, 334 perm, 335 property, 336 p_char_uuid); 337 } 338 /******************************************************************************* 339 ** 340 ** Function GATTS_AddCharDescriptor 341 ** 342 ** Description This function is called to add a characteristic descriptor 343 ** into a service database. Add descriptor should follow add char 344 ** to which it belongs, and next add char should be done only 345 ** after all add descriptors for the previous char. 346 ** 347 ** Parameter service_handle : To which service this characteristic descriptor 348 ** is added to. 349 ** perm : Characteristic value declaration attribute 350 ** permission. 351 ** p_descr_uuid : Characteristic descriptor UUID 352 ** 353 ** Returns Characteristic descriptor attribute handle. 0 if add 354 ** characteristic descriptor failed. 355 ** 356 *******************************************************************************/ 357 UINT16 GATTS_AddCharDescriptor (UINT16 service_handle, 358 tGATT_PERM perm, 359 tBT_UUID * p_descr_uuid) 360 { 361 tGATT_HDL_LIST_ELEM *p_decl; 362 363 if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) 364 { 365 GATT_TRACE_DEBUG0("Service not created"); 366 return 0; 367 } 368 if (p_descr_uuid == NULL || 369 (p_descr_uuid->len != LEN_UUID_128 && p_descr_uuid->len != LEN_UUID_16)) 370 { 371 GATT_TRACE_DEBUG0("Illegal parameter"); 372 return 0; 373 } 374 375 return gatts_add_char_descr(&p_decl->svc_db, 376 perm, 377 p_descr_uuid); 378 379 } 380 /******************************************************************************* 381 ** 382 ** Function GATTS_DeleteService 383 ** 384 ** Description This function is called to delete a service. 385 ** 386 ** Parameter gatt_if : application interface 387 ** p_svc_uuid : service UUID 388 ** svc_inst : instance of the service inside the application 389 ** 390 ** Returns TRUE if operation succeed, FALSE if handle block was not found. 391 ** 392 *******************************************************************************/ 393 BOOLEAN GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, UINT16 svc_inst) 394 { 395 396 tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info; 397 tGATT_HDL_LIST_ELEM *p_list=NULL; 398 UINT8 i_sreg; 399 tGATTS_PENDING_NEW_SRV_START *p_buf; 400 tGATT_REG *p_reg = gatt_get_regcb(gatt_if); 401 tBT_UUID *p_app_uuid128; 402 403 GATT_TRACE_DEBUG0 ("GATTS_DeleteService"); 404 405 if (p_reg == NULL) 406 { 407 GATT_TRACE_ERROR0 ("Applicaiton not foud"); 408 return(FALSE); 409 } 410 p_app_uuid128 = &p_reg->app_uuid128; 411 412 if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) == NULL) 413 { 414 GATT_TRACE_ERROR0 ("No Service found"); 415 return(FALSE); 416 } 417 418 if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128, 419 &p_list->asgn_range.svc_uuid, 420 p_list->asgn_range.svc_inst)) != NULL) 421 { 422 GATT_TRACE_DEBUG0 ("Delete a new service changed item - the service has not yet started"); 423 GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf)); 424 } 425 else 426 { 427 gatt_proc_srv_chg(); 428 } 429 430 if ((i_sreg = gatt_sr_find_i_rcb_by_app_id (p_app_uuid128, 431 p_svc_uuid, 432 svc_inst)) != GATT_MAX_SR_PROFILES) 433 { 434 GATTS_StopService(gatt_cb.sr_reg[i_sreg].s_hdl); 435 } 436 437 GATT_TRACE_DEBUG2 ("released handles s_hdl=%u e_hdl=%u", 438 p_list->asgn_range.s_handle , p_list->asgn_range.e_handle ); 439 440 if ( (p_list->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl) 441 && gatt_cb.cb_info.p_nv_save_callback) 442 (*gatt_cb.cb_info.p_nv_save_callback)(FALSE, &p_list->asgn_range); 443 444 gatt_remove_an_item_from_list(p_list_info, p_list); 445 gatt_free_hdl_buffer(p_list); 446 447 return(TRUE); 448 } 449 450 /******************************************************************************* 451 ** 452 ** Function GATTS_StartService 453 ** 454 ** Description This function is called to start a service with GATT 455 ** 456 ** Parameter gatt_if : service handle. 457 ** p_cback : application service callback functions. 458 ** sup_transport : supported transport(s) for this primary service 459 ** 460 ** return GATT_SUCCESS if sucessfully started; otherwise error code. 461 ** 462 *******************************************************************************/ 463 tGATT_STATUS GATTS_StartService (tGATT_IF gatt_if, UINT16 service_handle, 464 tGATT_TRANSPORT sup_transport) 465 { 466 tGATT_SR_REG *p_sreg; 467 tGATT_HDL_LIST_ELEM *p_list=NULL; 468 UINT8 i_sreg; 469 tBT_UUID *p_uuid; 470 tGATT_REG *p_reg = gatt_get_regcb(gatt_if); 471 472 tGATTS_PENDING_NEW_SRV_START *p_buf; 473 474 GATT_TRACE_API0 ("GATTS_StartService"); 475 476 if (p_reg == NULL) 477 { 478 /* Not found */ 479 GATT_TRACE_ERROR0 ("Applicaiton not found "); 480 return GATT_NOT_FOUND; 481 } 482 483 if ((p_list = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) 484 { 485 /* Not found */ 486 GATT_TRACE_ERROR0 ("no service found"); 487 return GATT_NOT_FOUND; 488 } 489 490 if (gatt_sr_find_i_rcb_by_app_id (&p_list->asgn_range.app_uuid128, 491 &p_list->asgn_range.svc_uuid, 492 p_list->asgn_range.svc_inst) != GATT_MAX_SR_PROFILES) 493 { 494 GATT_TRACE_ERROR0 ("Duplicate Service start - Service already started"); 495 return GATT_SERVICE_STARTED; 496 } 497 498 /*this is a new application servoce start */ 499 if ((i_sreg = gatt_sr_alloc_rcb(p_list)) == GATT_MAX_SR_PROFILES) 500 { 501 GATT_TRACE_ERROR0 ("GATTS_StartService: no free server registration block"); 502 return GATT_NO_RESOURCES; 503 } 504 505 p_sreg = &gatt_cb.sr_reg[i_sreg]; 506 p_sreg->gatt_if = gatt_if; 507 508 switch (sup_transport) 509 { 510 case GATT_TRANSPORT_BR_EDR: 511 case GATT_TRANSPORT_LE_BR_EDR: 512 if (p_sreg->type == GATT_UUID_PRI_SERVICE) 513 { 514 p_uuid = gatts_get_service_uuid (p_sreg->p_db); 515 516 p_sreg->sdp_handle = gatt_add_sdp_record(p_uuid, p_sreg->s_hdl, p_sreg->e_hdl); 517 } 518 break; 519 default: 520 break; 521 } 522 523 gatts_update_srv_list_elem(i_sreg, p_sreg->s_hdl, 524 p_list->asgn_range.is_primary); 525 526 gatt_add_a_srv_to_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[i_sreg]); 527 528 GATT_TRACE_DEBUG1 ("allocated i_sreg=%d ",i_sreg); 529 530 GATT_TRACE_DEBUG5 ("s_hdl=%d e_hdl=%d type=0x%x svc_inst=%d sdp_hdl=0x%x", 531 p_sreg->s_hdl,p_sreg->e_hdl, 532 p_sreg->type, p_sreg->service_instance, 533 p_sreg->sdp_handle); 534 535 536 if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128, 537 &p_list->asgn_range.svc_uuid, 538 p_list->asgn_range.svc_inst)) != NULL) 539 { 540 gatt_proc_srv_chg(); 541 /* remove the new service element after the srv changed processing is completed*/ 542 543 GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf)); 544 } 545 return GATT_SUCCESS; 546 } 547 548 /******************************************************************************* 549 ** 550 ** Function GATTS_StopService 551 ** 552 ** Description This function is called to stop a service 553 ** 554 ** Parameter service_handle : this is the start handle of a service 555 ** 556 ** Returns None. 557 ** 558 *******************************************************************************/ 559 void GATTS_StopService (UINT16 service_handle) 560 { 561 UINT8 ii = gatt_sr_find_i_rcb_by_handle(service_handle); 562 563 GATT_TRACE_API1("GATTS_StopService %u", service_handle); 564 565 /* Index 0 is reserved for GATT, and is never stopped */ 566 if ( (ii > 0) && (ii < GATT_MAX_SR_PROFILES) && (gatt_cb.sr_reg[ii].in_use) ) 567 { 568 if (gatt_cb.sr_reg[ii].sdp_handle) 569 { 570 SDP_DeleteRecord(gatt_cb.sr_reg[ii].sdp_handle); 571 } 572 gatt_remove_a_srv_from_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[ii]); 573 gatt_cb.srv_list[ii].in_use = FALSE; 574 memset (&gatt_cb.sr_reg[ii], 0, sizeof(tGATT_SR_REG)); 575 } 576 else 577 { 578 GATT_TRACE_ERROR1("GATTS_StopService service_handle: %u is not in use", service_handle); 579 } 580 } 581 /******************************************************************************* 582 ** 583 ** Function GATTs_HandleValueIndication 584 ** 585 ** Description This function sends a handle value indication to a client. 586 ** 587 ** Parameter conn_id: connection identifier. 588 ** attr_handle: Attribute handle of this handle value indication. 589 ** val_len: Length of the indicated attribute value. 590 ** p_val: Pointer to the indicated attribute value data. 591 ** 592 ** Returns GATT_SUCCESS if sucessfully sent or queued; otherwise error code. 593 ** 594 *******************************************************************************/ 595 tGATT_STATUS GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_handle, UINT16 val_len, UINT8 *p_val) 596 { 597 tGATT_STATUS cmd_status = GATT_ILLEGAL_PARAMETER; 598 599 tGATT_VALUE indication; 600 BT_HDR *p_msg; 601 tGATT_VALUE *p_buf; 602 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); 603 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); 604 tGATT_REG *p_reg = gatt_get_regcb(gatt_if); 605 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); 606 607 608 GATT_TRACE_API0 ("GATTS_HandleValueIndication"); 609 if ( (p_reg == NULL) || (p_tcb == NULL)) 610 { 611 GATT_TRACE_ERROR1 ("GATTS_HandleValueIndication Unknown conn_id: %u ", conn_id); 612 return(tGATT_STATUS) GATT_INVALID_CONN_ID; 613 } 614 indication.conn_id = conn_id; 615 indication.handle = attr_handle; 616 indication.len = val_len; 617 memcpy (indication.value, p_val, val_len); 618 indication.auth_req = GATT_AUTH_REQ_NONE; 619 620 if (GATT_HANDLE_IS_VALID (attr_handle) ) 621 { 622 if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle)) 623 { 624 GATT_TRACE_DEBUG0 ("Add a pending indication"); 625 if ((p_buf = gatt_add_pending_ind(p_tcb, &indication)) !=NULL) 626 { 627 cmd_status = GATT_SUCCESS; 628 } 629 else 630 { 631 cmd_status = GATT_NO_RESOURCES; 632 } 633 } 634 else 635 { 636 637 if ( (p_msg = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_IND, (tGATT_SR_MSG *)&indication)) != NULL) 638 { 639 cmd_status = attp_send_sr_msg (p_tcb, p_msg); 640 641 if (cmd_status == GATT_SUCCESS) 642 { 643 p_tcb->indicate_handle = indication.handle; 644 gatt_start_conf_timer(p_tcb); 645 } 646 } 647 } 648 } 649 return cmd_status; 650 } 651 652 /******************************************************************************* 653 ** 654 ** Function GATTS_HandleValueNotification 655 ** 656 ** Description This function sends a handle value notification to a client. 657 ** 658 ** Parameter conn_id: connection identifier. 659 ** attr_handle: Attribute handle of this handle value indication. 660 ** val_len: Length of the indicated attribute value. 661 ** p_val: Pointer to the indicated attribute value data. 662 ** 663 ** Returns GATT_SUCCESS if sucessfully sent; otherwise error code. 664 ** 665 *******************************************************************************/ 666 tGATT_STATUS GATTS_HandleValueNotification (UINT16 conn_id, UINT16 attr_handle, 667 UINT16 val_len, UINT8 *p_val) 668 { 669 tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER; 670 BT_HDR *p_buf; 671 tGATT_VALUE notif; 672 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); 673 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); 674 tGATT_REG *p_reg = gatt_get_regcb(gatt_if); 675 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); 676 677 GATT_TRACE_API0 ("GATTS_HandleValueNotification"); 678 679 if ( (p_reg == NULL) || (p_tcb == NULL)) 680 { 681 GATT_TRACE_ERROR1 ("GATTS_HandleValueNotification Unknown conn_id: %u ", conn_id); 682 return(tGATT_STATUS) GATT_INVALID_CONN_ID; 683 } 684 685 if (GATT_HANDLE_IS_VALID (attr_handle)) 686 { 687 notif.handle = attr_handle; 688 notif.len = val_len; 689 memcpy (notif.value, p_val, val_len); 690 notif.auth_req = GATT_AUTH_REQ_NONE;; 691 692 p_buf = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_NOTIF, (tGATT_SR_MSG *)¬if); 693 cmd_sent = attp_send_sr_msg (p_tcb, p_buf); 694 } 695 return cmd_sent; 696 } 697 698 /******************************************************************************* 699 ** 700 ** Function GATTS_SendRsp 701 ** 702 ** Description This function sends the server response to client. 703 ** 704 ** Parameter conn_id: connection identifier. 705 ** trans_id: transaction id 706 ** status: response status 707 ** p_msg: pointer to message parameters structure. 708 ** 709 ** Returns GATT_SUCCESS if sucessfully sent; otherwise error code. 710 ** 711 *******************************************************************************/ 712 tGATT_STATUS GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id, 713 tGATT_STATUS status, tGATTS_RSP *p_msg) 714 { 715 tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER; 716 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); 717 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); 718 tGATT_REG *p_reg = gatt_get_regcb(gatt_if); 719 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); 720 721 GATT_TRACE_API3 ("GATTS_SendRsp: conn_id: %u trans_id: %u Status: 0x%04x", 722 conn_id, trans_id, status); 723 724 if ( (p_reg == NULL) || (p_tcb == NULL)) 725 { 726 GATT_TRACE_ERROR1 ("GATTS_SendRsp Unknown conn_id: %u ", conn_id); 727 return(tGATT_STATUS) GATT_INVALID_CONN_ID; 728 } 729 730 if (p_tcb->sr_cmd.trans_id != trans_id) 731 { 732 GATT_TRACE_ERROR2 ("GATTS_SendRsp conn_id: %u waiting for op_code = %02x", 733 conn_id, p_tcb->sr_cmd.op_code); 734 735 return(GATT_WRONG_STATE); 736 } 737 /* Process App response */ 738 cmd_sent = gatt_sr_process_app_rsp (p_tcb, gatt_if, trans_id, p_tcb->sr_cmd.op_code, status, p_msg); 739 740 return cmd_sent; 741 } 742 743 /*******************************************************************************/ 744 /* GATT Profile Srvr Functions */ 745 /*******************************************************************************/ 746 747 /*******************************************************************************/ 748 /* */ 749 /* GATT CLIENT APIs */ 750 /* */ 751 /*******************************************************************************/ 752 753 754 /******************************************************************************* 755 ** 756 ** Function GATTC_ConfigureMTU 757 ** 758 ** Description This function is called to configure the ATT MTU size. 759 ** 760 ** Parameters conn_id: connection identifier. 761 ** mtu - attribute MTU size.. 762 ** 763 ** Returns GATT_SUCCESS if command started successfully. 764 ** 765 *******************************************************************************/ 766 tGATT_STATUS GATTC_ConfigureMTU (UINT16 conn_id, UINT16 mtu) 767 { 768 UINT8 ret = GATT_NO_RESOURCES; 769 tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); 770 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); 771 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); 772 tGATT_REG *p_reg = gatt_get_regcb(gatt_if); 773 774 tGATT_CLCB *p_clcb; 775 776 GATT_TRACE_API2 ("GATTC_ConfigureMTU conn_id=%d mtu=%d", conn_id, mtu ); 777 778 // Validate that the link is BLE, not BR/EDR 779 // ???? 780 781 if ( (p_tcb == NULL) || (p_reg==NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) || (mtu > GATT_MAX_MTU_SIZE)) 782 { 783 return GATT_ILLEGAL_PARAMETER; 784 } 785 786 if (gatt_is_clcb_allocated(conn_id)) 787 { 788 GATT_TRACE_ERROR1("GATTC_ConfigureMTU GATT_BUSY conn_id = %d", conn_id); 789 return GATT_BUSY; 790 } 791 792 if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL) 793 { 794 p_clcb->p_tcb->payload_size = mtu; 795 p_clcb->operation = GATTC_OPTYPE_CONFIG; 796 797 ret = attp_send_cl_msg (p_clcb->p_tcb, p_clcb->clcb_idx, GATT_REQ_MTU, (tGATT_CL_MSG *)&mtu); 798 } 799 800 return ret; 801 } 802 803 /******************************************************************************* 804 ** 805 ** Function GATTC_Discover 806 ** 807 ** Description This function is called to do a discovery procedure on ATT server. 808 ** 809 ** Parameters conn_id: connection identifier. 810 ** disc_type:discovery type. 811 ** p_param: parameters of discovery requirement. 812 ** 813 ** Returns GATT_SUCCESS if command received/sent successfully. 814 ** 815 *******************************************************************************/ 816 tGATT_STATUS GATTC_Discover (UINT16 conn_id, tGATT_DISC_TYPE disc_type, 817 tGATT_DISC_PARAM *p_param) 818 { 819 tGATT_STATUS status = GATT_SUCCESS; 820 tGATT_CLCB *p_clcb; 821 tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); 822 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); 823 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); 824 tGATT_REG *p_reg = gatt_get_regcb(gatt_if); 825 826 827 GATT_TRACE_API2 ("GATTC_Discover conn_id=%d disc_type=%d",conn_id, disc_type); 828 829 if ( (p_tcb == NULL) || (p_reg==NULL) ||(p_param == NULL) || 830 (disc_type >= GATT_DISC_MAX)) 831 { 832 GATT_TRACE_ERROR2("GATTC_Discover Illegal param: disc_type %d conn_id = %d", disc_type, conn_id); 833 return GATT_ILLEGAL_PARAMETER; 834 } 835 836 837 if (gatt_is_clcb_allocated(conn_id)) 838 { 839 GATT_TRACE_ERROR1("GATTC_Discover GATT_BUSY conn_id = %d", conn_id); 840 return GATT_BUSY; 841 } 842 843 844 if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL ) 845 { 846 if (!GATT_HANDLE_IS_VALID(p_param->s_handle) || 847 !GATT_HANDLE_IS_VALID(p_param->e_handle) || 848 /* search by type does not have a valid UUID param */ 849 (disc_type == GATT_DISC_SRVC_BY_UUID && 850 p_param->service.len == 0)) 851 { 852 gatt_clcb_dealloc(p_clcb); 853 return GATT_ILLEGAL_PARAMETER; 854 } 855 856 p_clcb->operation = GATTC_OPTYPE_DISCOVERY; 857 p_clcb->op_subtype = disc_type; 858 p_clcb->s_handle = p_param->s_handle; 859 p_clcb->e_handle = p_param->e_handle; 860 p_clcb->uuid = p_param->service; 861 862 gatt_act_discovery(p_clcb); 863 } 864 else 865 { 866 status = GATT_NO_RESOURCES; 867 } 868 return status; 869 } 870 871 /******************************************************************************* 872 ** 873 ** Function GATTC_Read 874 ** 875 ** Description This function is called to read the value of an attribute from 876 ** the server. 877 ** 878 ** Parameters conn_id: connection identifier. 879 ** type - attribute read type. 880 ** p_read - read operation parameters. 881 ** 882 ** Returns GATT_SUCCESS if command started successfully. 883 ** 884 *******************************************************************************/ 885 tGATT_STATUS GATTC_Read (UINT16 conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read) 886 { 887 tGATT_STATUS status = GATT_SUCCESS; 888 tGATT_CLCB *p_clcb; 889 tGATT_READ_MULTI *p_read_multi; 890 tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); 891 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); 892 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); 893 tGATT_REG *p_reg = gatt_get_regcb(gatt_if); 894 895 896 GATT_TRACE_API2 ("GATTC_Read conn_id=%d type=%d", conn_id, type); 897 898 if ( (p_tcb == NULL) || (p_reg==NULL) || (p_read == NULL) || ((type >= GATT_READ_MAX) || (type == 0))) 899 { 900 GATT_TRACE_ERROR2("GATT_Read Illegal param: conn_id %d, type 0%d,", conn_id, type); 901 return GATT_ILLEGAL_PARAMETER; 902 } 903 904 if (gatt_is_clcb_allocated(conn_id)) 905 { 906 GATT_TRACE_ERROR1("GATTC_Read GATT_BUSY conn_id = %d", conn_id); 907 return GATT_BUSY; 908 } 909 910 if ( (p_clcb = gatt_clcb_alloc(conn_id)) != NULL ) 911 { 912 p_clcb->operation = GATTC_OPTYPE_READ; 913 p_clcb->op_subtype = type; 914 p_clcb->auth_req = p_read->by_handle.auth_req; 915 p_clcb->counter = 0; 916 917 switch (type) 918 { 919 case GATT_READ_BY_TYPE: 920 case GATT_READ_CHAR_VALUE: 921 p_clcb->s_handle = p_read->service.s_handle; 922 p_clcb->e_handle = p_read->service.e_handle; 923 memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID)); 924 break; 925 case GATT_READ_MULTIPLE: 926 p_clcb->s_handle = 0; 927 /* copy multiple handles in CB */ 928 p_read_multi = (tGATT_READ_MULTI *)GKI_getbuf(sizeof(tGATT_READ_MULTI)); 929 p_clcb->p_attr_buf = (UINT8*)p_read_multi; 930 memcpy (p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI)); 931 case GATT_READ_BY_HANDLE: 932 case GATT_READ_PARTIAL: 933 memset(&p_clcb->uuid, 0, sizeof(tBT_UUID)); 934 p_clcb->s_handle = p_read->by_handle.handle; 935 936 if (type == GATT_READ_PARTIAL) 937 { 938 p_clcb->counter = p_read->partial.offset; 939 } 940 941 break; 942 default: 943 break; 944 } 945 /* start security check */ 946 if (gatt_security_check_start(p_clcb) == FALSE) 947 { 948 status = GATT_NO_RESOURCES; 949 gatt_clcb_dealloc(p_clcb); 950 } 951 } 952 else 953 { 954 status = GATT_NO_RESOURCES; 955 } 956 return status; 957 } 958 959 /******************************************************************************* 960 ** 961 ** Function GATTC_Write 962 ** 963 ** Description This function is called to write the value of an attribute to 964 ** the server. 965 ** 966 ** Parameters conn_id: connection identifier. 967 ** type - attribute write type. 968 ** p_write - write operation parameters. 969 ** 970 ** Returns GATT_SUCCESS if command started successfully. 971 ** 972 *******************************************************************************/ 973 tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write) 974 { 975 tGATT_STATUS status = GATT_SUCCESS; 976 tGATT_CLCB *p_clcb; 977 tGATT_VALUE *p; 978 tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); 979 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); 980 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); 981 tGATT_REG *p_reg = gatt_get_regcb(gatt_if); 982 983 if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) || 984 ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) ) 985 { 986 GATT_TRACE_ERROR2("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type); 987 return GATT_ILLEGAL_PARAMETER; 988 } 989 990 if (gatt_is_clcb_allocated(conn_id)) 991 { 992 GATT_TRACE_ERROR1("GATTC_Write GATT_BUSY conn_id = %d", conn_id); 993 return GATT_BUSY; 994 } 995 996 if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL ) 997 { 998 p_clcb->operation = GATTC_OPTYPE_WRITE; 999 p_clcb->op_subtype = type; 1000 p_clcb->auth_req = p_write->auth_req; 1001 1002 if (( p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL) 1003 { 1004 memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE)); 1005 1006 p = (tGATT_VALUE *)p_clcb->p_attr_buf; 1007 if (type == GATT_WRITE_PREPARE) 1008 { 1009 p_clcb->start_offset = p_write->offset; 1010 p->offset = 0; 1011 } 1012 1013 if (gatt_security_check_start(p_clcb) == FALSE) 1014 { 1015 status = GATT_NO_RESOURCES; 1016 } 1017 } 1018 else 1019 { 1020 status = GATT_NO_RESOURCES; 1021 } 1022 1023 if (status == GATT_NO_RESOURCES) 1024 gatt_clcb_dealloc(p_clcb); 1025 } 1026 else 1027 { 1028 status = GATT_NO_RESOURCES; 1029 } 1030 return status; 1031 } 1032 1033 1034 /******************************************************************************* 1035 ** 1036 ** Function GATTC_ExecuteWrite 1037 ** 1038 ** Description This function is called to send an Execute write request to 1039 ** the server. 1040 ** 1041 ** Parameters conn_id: connection identifier. 1042 ** is_execute - to execute or cancel the prepare write requet(s) 1043 ** 1044 ** Returns GATT_SUCCESS if command started successfully. 1045 ** 1046 *******************************************************************************/ 1047 tGATT_STATUS GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute) 1048 { 1049 tGATT_STATUS status = GATT_SUCCESS; 1050 tGATT_CLCB *p_clcb; 1051 tGATT_EXEC_FLAG flag; 1052 tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); 1053 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); 1054 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx); 1055 tGATT_REG *p_reg = gatt_get_regcb(gatt_if); 1056 1057 GATT_TRACE_API2 ("GATTC_ExecuteWrite conn_id=%d is_execute=%d", conn_id, is_execute); 1058 1059 if ( (p_tcb == NULL) || (p_reg==NULL) ) 1060 { 1061 GATT_TRACE_ERROR1("GATTC_ExecuteWrite Illegal param: conn_id %d", conn_id); 1062 return GATT_ILLEGAL_PARAMETER; 1063 } 1064 1065 if (gatt_is_clcb_allocated(conn_id)) 1066 { 1067 GATT_TRACE_ERROR1("GATTC_Write GATT_BUSY conn_id = %d", conn_id); 1068 return GATT_BUSY; 1069 } 1070 1071 if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL) 1072 { 1073 p_clcb->operation = GATTC_OPTYPE_EXE_WRITE; 1074 flag = is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL; 1075 gatt_send_queue_write_cancel (p_clcb->p_tcb, p_clcb, flag); 1076 } 1077 else 1078 { 1079 GATT_TRACE_ERROR1("Unable to allocate client CB for conn_id %d ", conn_id); 1080 status = GATT_NO_RESOURCES; 1081 } 1082 return status; 1083 } 1084 1085 /******************************************************************************* 1086 ** 1087 ** Function GATTC_SendHandleValueConfirm 1088 ** 1089 ** Description This function is called to send a handle value confirmation 1090 ** as response to a handle value notification from server. 1091 ** 1092 ** Parameters conn_id: connection identifier. 1093 ** handle: the handle of the attribute confirmation. 1094 ** 1095 ** Returns GATT_SUCCESS if command started successfully. 1096 ** 1097 *******************************************************************************/ 1098 tGATT_STATUS GATTC_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle) 1099 { 1100 tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER; 1101 tGATT_TCB *p_tcb=gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id)); 1102 1103 GATT_TRACE_API2 ("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id, handle); 1104 1105 if (p_tcb) 1106 { 1107 if (p_tcb->ind_count > 0 ) 1108 { 1109 btu_stop_timer (&p_tcb->ind_ack_timer_ent); 1110 1111 GATT_TRACE_DEBUG1 ("notif_count=%d ", p_tcb->ind_count); 1112 /* send confirmation now */ 1113 ret = attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, (tGATT_CL_MSG *)&handle); 1114 1115 p_tcb->ind_count = 0; 1116 1117 } 1118 else 1119 { 1120 GATT_TRACE_DEBUG1 ("GATTC_SendHandleValueConfirm - conn_id: %u - ignored not waiting for indicaiton ack", conn_id); 1121 ret = GATT_SUCCESS; 1122 } 1123 } 1124 else 1125 { 1126 GATT_TRACE_ERROR1 ("GATTC_SendHandleValueConfirm - Unknown conn_id: %u", conn_id); 1127 } 1128 return ret; 1129 } 1130 1131 1132 /*******************************************************************************/ 1133 /* */ 1134 /* GATT APIs */ 1135 /* */ 1136 /*******************************************************************************/ 1137 /******************************************************************************* 1138 ** 1139 ** Function GATT_SetIdleTimeout 1140 ** 1141 ** Description This function (common to both client and server) sets the idle 1142 ** timeout for a tansport connection 1143 ** 1144 ** Parameter bd_addr: target device bd address. 1145 ** idle_tout: timeout value in seconds. 1146 ** 1147 ** Returns void 1148 ** 1149 *******************************************************************************/ 1150 void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout) 1151 { 1152 tGATT_TCB *p_tcb; 1153 BOOLEAN status = FALSE; 1154 1155 if ((p_tcb = gatt_find_tcb_by_addr (bd_addr)) != NULL) 1156 { 1157 if (p_tcb->att_lcid == L2CAP_ATT_CID) 1158 { 1159 status = L2CA_SetFixedChannelTout (bd_addr, L2CAP_ATT_CID, idle_tout); 1160 } 1161 else 1162 { 1163 status = L2CA_SetIdleTimeout (p_tcb->att_lcid, idle_tout, FALSE); 1164 } 1165 } 1166 1167 GATT_TRACE_API2 ("GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)", 1168 idle_tout, status); 1169 } 1170 1171 1172 /******************************************************************************* 1173 ** 1174 ** Function GATT_Register 1175 ** 1176 ** Description This function is called to register an application 1177 ** with GATT 1178 ** 1179 ** Parameter p_app_uuid128: Application UUID 1180 ** p_cb_info: callback functions. 1181 ** 1182 ** Returns 0 for error, otherwise the index of the client registered with GATT 1183 ** 1184 *******************************************************************************/ 1185 tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info) 1186 { 1187 tGATT_REG *p_reg; 1188 UINT8 i_gatt_if=0; 1189 tGATT_IF gatt_if=0; 1190 1191 GATT_TRACE_API0 ("GATT_Register"); 1192 gatt_dbg_display_uuid(*p_app_uuid128); 1193 1194 for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++) 1195 { 1196 if (p_reg->in_use && !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128, LEN_UUID_128)) 1197 { 1198 GATT_TRACE_ERROR0("application already registered."); 1199 return 0; 1200 } 1201 } 1202 1203 for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++) 1204 { 1205 if (!p_reg->in_use) 1206 { 1207 memset(p_reg, 0 , sizeof(tGATT_REG)); 1208 i_gatt_if++; /* one based number */ 1209 p_reg->app_uuid128 = *p_app_uuid128; 1210 gatt_if = 1211 p_reg->gatt_if = (tGATT_IF)i_gatt_if; 1212 p_reg->app_cb = *p_cb_info; 1213 p_reg->in_use = TRUE; 1214 1215 break; 1216 } 1217 } 1218 GATT_TRACE_API1 ("allocated gatt_if=%d", gatt_if); 1219 return gatt_if; 1220 } 1221 1222 1223 /******************************************************************************* 1224 ** 1225 ** Function GATT_Deregister 1226 ** 1227 ** Description This function deregistered the application from GATT. 1228 ** 1229 ** Parameters gatt_if: applicaiton interface. 1230 ** 1231 ** Returns None. 1232 ** 1233 *******************************************************************************/ 1234 void GATT_Deregister (tGATT_IF gatt_if) 1235 { 1236 tGATT_REG *p_reg = gatt_get_regcb(gatt_if); 1237 tGATT_TCB *p_tcb; 1238 tGATT_CLCB *p_clcb; 1239 UINT8 i, ii, j; 1240 tGATT_SR_REG *p_sreg; 1241 1242 GATT_TRACE_API1 ("GATT_Deregister gatt_if=%d", gatt_if); 1243 /* Index 0 is GAP and is never deregistered */ 1244 if ( (gatt_if == 0) || (p_reg == NULL) ) 1245 { 1246 GATT_TRACE_ERROR1 ("GATT_Deregister with invalid gatt_if: %u", gatt_if); 1247 return; 1248 } 1249 1250 /* stop all services */ 1251 /* todo an applcaiton can not be deregistered if its services is also used by other application 1252 deregisteration need to bed performed in an orderly fashion 1253 no check for now */ 1254 1255 for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++) 1256 { 1257 if (p_sreg->in_use && (p_sreg->gatt_if == gatt_if)) 1258 { 1259 GATTS_StopService(p_sreg->s_hdl); 1260 } 1261 } 1262 1263 /* free all services db buffers if owned by this application */ 1264 gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128); 1265 1266 /* When an application deregisters, check remove the link associated with the app */ 1267 1268 for (i=0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++) 1269 { 1270 if (p_tcb->in_use) 1271 { 1272 if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE) 1273 { 1274 gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE); 1275 if (!gatt_num_apps_hold_link(p_tcb)) 1276 { 1277 /* this will disconnect the link or cancel the pending connect request at lower layer*/ 1278 gatt_disconnect(p_tcb->peer_bda); 1279 } 1280 } 1281 1282 for (j = 0, p_clcb= &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++) 1283 { 1284 if (p_clcb->in_use && 1285 (p_clcb->p_reg->gatt_if == gatt_if) && 1286 (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx)) 1287 { 1288 gatt_clcb_dealloc (p_clcb); 1289 break; 1290 } 1291 } 1292 } 1293 } 1294 1295 gatt_deregister_bgdev_list(gatt_if); 1296 /* update the listen mode */ 1297 #ifdef BLE_PERIPHERAL_MODE_SUPPORT 1298 GATT_Listen(gatt_if, FALSE, NULL); 1299 #endif 1300 1301 memset (p_reg, 0, sizeof(tGATT_REG)); 1302 } 1303 1304 1305 /******************************************************************************* 1306 ** 1307 ** Function GATT_StartIf 1308 ** 1309 ** Description This function is called after registration to start receiving 1310 ** callbacks for registered interface. Function may call back 1311 ** with connection status and queued notifications 1312 ** 1313 ** Parameter gatt_if: applicaiton interface. 1314 ** 1315 ** Returns 0 for error, otherwise the index of the client registered with GATT 1316 ** 1317 *******************************************************************************/ 1318 void GATT_StartIf (tGATT_IF gatt_if) 1319 { 1320 tGATT_REG *p_reg; 1321 tGATT_TCB *p_tcb; 1322 BD_ADDR bda; 1323 UINT8 start_idx, found_idx; 1324 UINT16 conn_id; 1325 1326 GATT_TRACE_API1 ("GATT_StartIf gatt_if=%d", gatt_if); 1327 if ((p_reg = gatt_get_regcb(gatt_if)) != NULL) 1328 { 1329 p_reg = &gatt_cb.cl_rcb[gatt_if - 1]; 1330 start_idx = 0; 1331 while (gatt_find_the_connected_bda(start_idx, bda, &found_idx)) 1332 { 1333 p_tcb = gatt_find_tcb_by_addr(bda); 1334 if (p_reg->app_cb.p_conn_cb && p_tcb) 1335 { 1336 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if); 1337 (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0); 1338 } 1339 start_idx = ++found_idx; 1340 } 1341 } 1342 } 1343 1344 1345 /******************************************************************************* 1346 ** 1347 ** Function GATT_Connect 1348 ** 1349 ** Description This function initiate a connecttion to a remote device on GATT 1350 ** channel. 1351 ** 1352 ** Parameters gatt_if: applicaiton interface 1353 ** bd_addr: peer device address. 1354 ** is_direct: is a direct conenection or a background auto connection 1355 ** 1356 ** Returns TRUE if connection started; FALSE if connection start failure. 1357 ** 1358 *******************************************************************************/ 1359 BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){ 1360 tGATT_REG *p_reg; 1361 BOOLEAN status; 1362 1363 GATT_TRACE_API1 ("GATT_Connect gatt_if=%d", gatt_if); 1364 1365 /* Make sure app is registered */ 1366 if ((p_reg = gatt_get_regcb(gatt_if)) == NULL) 1367 { 1368 GATT_TRACE_ERROR1("GATT_Connect - gatt_if =%d is not registered", gatt_if); 1369 return(FALSE); 1370 } 1371 1372 if (is_direct) 1373 status = gatt_act_connect (p_reg, bd_addr); 1374 else 1375 status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr, TRUE); 1376 1377 return status; 1378 1379 } 1380 1381 /******************************************************************************* 1382 ** 1383 ** Function GATT_CancelConnect 1384 ** 1385 ** Description This function terminate the connection initaition to a remote 1386 ** device on GATT channel. 1387 ** 1388 ** Parameters gatt_if: client interface. If 0 used as unconditionally disconnect, 1389 ** typically used for direct connection cancellation. 1390 ** bd_addr: peer device address. 1391 ** 1392 ** Returns TRUE if connection started; FALSE if connection start failure. 1393 ** 1394 *******************************************************************************/ 1395 BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){ 1396 tGATT_REG *p_reg; 1397 tGATT_TCB *p_tcb; 1398 BOOLEAN status = TRUE; 1399 tGATT_IF temp_gatt_if; 1400 UINT8 start_idx, found_idx; 1401 1402 GATT_TRACE_API1 ("GATT_CancelConnect gatt_if=%d", gatt_if); 1403 1404 if ((gatt_if != 0) && ((p_reg = gatt_get_regcb(gatt_if)) == NULL)) 1405 { 1406 GATT_TRACE_ERROR1("GATT_CancelConnect - gatt_if =%d is not registered", gatt_if); 1407 return(FALSE); 1408 } 1409 1410 if (is_direct) 1411 { 1412 if (!gatt_if) 1413 { 1414 GATT_TRACE_DEBUG0("GATT_CancelConnect - unconditional"); 1415 start_idx = 0; 1416 p_tcb = gatt_find_tcb_by_addr(bd_addr); 1417 if (p_tcb && gatt_num_apps_hold_link(p_tcb)) 1418 { 1419 while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx, &temp_gatt_if)) 1420 { 1421 status = gatt_cancel_open(temp_gatt_if, bd_addr); 1422 start_idx = ++found_idx; 1423 } 1424 } 1425 else 1426 { 1427 GATT_TRACE_ERROR0("GATT_CancelConnect - no app found"); 1428 status = FALSE; 1429 } 1430 } 1431 else 1432 { 1433 status = gatt_cancel_open(gatt_if, bd_addr); 1434 } 1435 } 1436 else 1437 { 1438 if (!gatt_if) 1439 { 1440 if (gatt_get_num_apps_for_bg_dev(bd_addr)) 1441 { 1442 while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if)) 1443 gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr); 1444 } 1445 else 1446 { 1447 GATT_TRACE_ERROR0("GATT_CancelConnect -no app associated with the bg device for unconditional removal"); 1448 status = FALSE; 1449 } 1450 } 1451 else 1452 { 1453 status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr); 1454 } 1455 } 1456 1457 return status; 1458 } 1459 1460 /******************************************************************************* 1461 ** 1462 ** Function GATT_Disconnect 1463 ** 1464 ** Description This function disconnect the GATT channel for this registered 1465 ** application. 1466 ** 1467 ** Parameters conn_id: connection identifier. 1468 ** 1469 ** Returns GATT_SUCCESS if disconnected. 1470 ** 1471 *******************************************************************************/ 1472 tGATT_STATUS GATT_Disconnect (UINT16 conn_id) 1473 { 1474 tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER; 1475 tGATT_TCB *p_tcb=NULL; 1476 tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id); 1477 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); 1478 1479 GATT_TRACE_API1 ("GATT_Disconnect conn_id=%d ", conn_id); 1480 1481 p_tcb = gatt_get_tcb_by_idx(tcb_idx); 1482 1483 if (p_tcb) 1484 { 1485 gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE); 1486 if (!gatt_num_apps_hold_link(p_tcb)) 1487 { 1488 gatt_disconnect(p_tcb->peer_bda); 1489 } 1490 ret = GATT_SUCCESS; 1491 } 1492 return ret; 1493 } 1494 1495 1496 /******************************************************************************* 1497 ** 1498 ** Function GATT_GetConnectionInfor 1499 ** 1500 ** Description This function use conn_id to find its associated BD address and applciation 1501 ** interface 1502 ** 1503 ** Parameters conn_id: connection id (input) 1504 ** p_gatt_if: applicaiton interface (output) 1505 ** bd_addr: peer device address. (output) 1506 ** 1507 ** Returns TRUE the ligical link information is found for conn_id 1508 ** 1509 *******************************************************************************/ 1510 BOOLEAN GATT_GetConnectionInfor(UINT16 conn_id, tGATT_IF *p_gatt_if, BD_ADDR bd_addr) 1511 { 1512 1513 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id); 1514 tGATT_REG *p_reg = gatt_get_regcb(gatt_if); 1515 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id); 1516 tGATT_TCB *p_tcb= gatt_get_tcb_by_idx(tcb_idx); 1517 BOOLEAN status=FALSE; 1518 1519 GATT_TRACE_API1 ("GATT_GetConnectionInfor conn_id=%d", conn_id); 1520 1521 if (p_tcb && p_reg ) 1522 { 1523 memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN); 1524 *p_gatt_if = gatt_if; 1525 status = TRUE; 1526 } 1527 return status; 1528 } 1529 1530 1531 /******************************************************************************* 1532 ** 1533 ** Function GATT_GetConnIdIfConnected 1534 ** 1535 ** Description This function find the conn_id if the logical link for BD address 1536 ** and applciation interface is connected 1537 ** 1538 ** Parameters gatt_if: applicaiton interface (input) 1539 ** bd_addr: peer device address. (input) 1540 ** p_conn_id: connection id (output) 1541 ** 1542 ** Returns TRUE the logical link is connected 1543 ** 1544 *******************************************************************************/ 1545 BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_conn_id) 1546 { 1547 tGATT_REG *p_reg = gatt_get_regcb(gatt_if); 1548 tGATT_TCB *p_tcb= gatt_find_tcb_by_addr(bd_addr); 1549 BOOLEAN status=FALSE; 1550 1551 if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) ) 1552 { 1553 *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if); 1554 status = TRUE; 1555 } 1556 1557 GATT_TRACE_API1 ("GATT_GetConnIdIfConnected status=%d", status); 1558 return status; 1559 } 1560 1561 1562 /******************************************************************************* 1563 ** 1564 ** Function GATT_Listen 1565 ** 1566 ** Description This function start or stop LE advertisement and listen for 1567 ** connection. 1568 ** 1569 ** Parameters gatt_if: applicaiton interface 1570 ** p_bd_addr: listen for specific address connection, or NULL for 1571 ** listen to all device connection. 1572 ** start: start or stop listening. 1573 ** 1574 ** Returns TRUE if advertisement is started; FALSE if adv start failure. 1575 ** 1576 *******************************************************************************/ 1577 BOOLEAN GATT_Listen (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr) 1578 { 1579 tGATT_REG *p_reg; 1580 BOOLEAN status = TRUE; 1581 1582 GATT_TRACE_API1 ("GATT_Listen gatt_if=%d", gatt_if); 1583 1584 /* Make sure app is registered */ 1585 if ((p_reg = gatt_get_regcb(gatt_if)) == NULL) 1586 { 1587 GATT_TRACE_ERROR1("GATT_Listen - gatt_if =%d is not registered", gatt_if); 1588 return(FALSE); 1589 } 1590 1591 if (bd_addr != NULL) 1592 { 1593 status = gatt_update_auto_connect_dev(gatt_if,start, bd_addr, FALSE); 1594 } 1595 else 1596 { 1597 p_reg->listening = start ? GATT_LISTEN_TO_ALL : GATT_LISTEN_TO_NONE; 1598 } 1599 1600 gatt_update_listen_mode(); 1601 1602 return status; 1603 1604 } 1605 1606 #endif 1607 1608