Home | History | Annotate | Download | only in src
      1 /******************************************************************************
      2  *
      3  *  Copyright (C) 2009-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 
     20 /************************************************************************************
     21  *
     22  *  Filename:      btif_gatt_server.c
     23  *
     24  *  Description:   GATT server implementation
     25  *
     26  ***********************************************************************************/
     27 
     28 #include <hardware/bluetooth.h>
     29 #include <hardware/bt_gatt.h>
     30 #include <stdio.h>
     31 #include <stdlib.h>
     32 #include <errno.h>
     33 #include <string.h>
     34 
     35 #define LOG_TAG "BtGatt.btif"
     36 
     37 #include "btif_common.h"
     38 #include "btif_util.h"
     39 
     40 #if (defined(BLE_INCLUDED) && (BLE_INCLUDED == TRUE))
     41 
     42 #include "gki.h"
     43 #include "bta_api.h"
     44 #include "bta_gatt_api.h"
     45 #include "bd.h"
     46 #include "btif_dm.h"
     47 #include "btif_storage.h"
     48 
     49 #include "btif_gatt.h"
     50 #include "btif_gatt_util.h"
     51 
     52 /************************************************************************************
     53 **  Constants & Macros
     54 ************************************************************************************/
     55 
     56 #define CHECK_BTGATT_INIT() if (bt_gatt_callbacks == NULL)\
     57     {\
     58         ALOGW("%s: BTGATT not initialized", __FUNCTION__);\
     59         return BT_STATUS_NOT_READY;\
     60     } else {\
     61         ALOGD("%s", __FUNCTION__);\
     62     }
     63 
     64 
     65 typedef enum {
     66     BTIF_GATTS_REGISTER_APP = 2000,
     67     BTIF_GATTS_UNREGISTER_APP,
     68     BTIF_GATTS_OPEN,
     69     BTIF_GATTS_CLOSE,
     70     BTIF_GATTS_CREATE_SERVICE,
     71     BTIF_GATTS_ADD_INCLUDED_SERVICE,
     72     BTIF_GATTS_ADD_CHARACTERISTIC,
     73     BTIF_GATTS_ADD_DESCRIPTOR,
     74     BTIF_GATTS_START_SERVICE,
     75     BTIF_GATTS_STOP_SERVICE,
     76     BTIF_GATTS_DELETE_SERVICE,
     77     BTIF_GATTS_SEND_INDICATION,
     78     BTIF_GATTS_SEND_RESPONSE
     79 } btif_gatts_event_t;
     80 
     81 /************************************************************************************
     82 **  Local type definitions
     83 ************************************************************************************/
     84 
     85 typedef struct
     86 {
     87     uint8_t             value[BTGATT_MAX_ATTR_LEN];
     88     btgatt_response_t   response;
     89     btgatt_srvc_id_t    srvc_id;
     90     bt_bdaddr_t         bd_addr;
     91     bt_uuid_t           uuid;
     92     uint32_t            trans_id;
     93     uint16_t            conn_id;
     94     uint16_t            srvc_handle;
     95     uint16_t            incl_handle;
     96     uint16_t            attr_handle;
     97     uint16_t            permissions;
     98     uint16_t            len;
     99     uint8_t             server_if;
    100     uint8_t             is_direct;
    101     uint8_t             num_handles;
    102     uint8_t             properties;
    103     uint8_t             transport;
    104     uint8_t             confirm;
    105     uint8_t             status;
    106 } __attribute__((packed)) btif_gatts_cb_t;
    107 
    108 
    109 /************************************************************************************
    110 **  Static variables
    111 ************************************************************************************/
    112 
    113 extern const btgatt_callbacks_t *bt_gatt_callbacks;
    114 
    115 
    116 /************************************************************************************
    117 **  Static functions
    118 ************************************************************************************/
    119 
    120 static void btapp_gatts_copy_req_data(UINT16 event, char *p_dest, char *p_src)
    121 {
    122     tBTA_GATTS *p_dest_data = (tBTA_GATTS*) p_dest;
    123     tBTA_GATTS *p_src_data = (tBTA_GATTS*) p_src;
    124 
    125     if (!p_src_data || !p_dest_data)
    126         return;
    127 
    128     // Copy basic structure first
    129     memcpy(p_dest_data, p_src_data, sizeof(tBTA_GATTS));
    130 
    131     // Allocate buffer for request data if necessary
    132     switch (event)
    133     {
    134         case BTA_GATTS_READ_EVT:
    135         case BTA_GATTS_WRITE_EVT:
    136         case BTA_GATTS_EXEC_WRITE_EVT:
    137         case BTA_GATTS_MTU_EVT:
    138             p_dest_data->req_data.p_data = GKI_getbuf(sizeof(tBTA_GATTS_REQ_DATA));
    139             if (p_dest_data->req_data.p_data != NULL)
    140             {
    141                 memcpy(p_dest_data->req_data.p_data, p_src_data->req_data.p_data,
    142                     sizeof(tBTA_GATTS_REQ_DATA));
    143             }
    144             break;
    145 
    146         default:
    147             break;
    148     }
    149 }
    150 
    151 static void btapp_gatts_free_req_data(UINT16 event, tBTA_GATTS *p_data)
    152 {
    153     switch (event)
    154     {
    155         case BTA_GATTS_READ_EVT:
    156         case BTA_GATTS_WRITE_EVT:
    157         case BTA_GATTS_EXEC_WRITE_EVT:
    158         case BTA_GATTS_MTU_EVT:
    159             if (p_data && p_data->req_data.p_data)
    160                 GKI_freebuf(p_data->req_data.p_data);
    161             break;
    162 
    163         default:
    164             break;
    165     }
    166 }
    167 
    168 static void btapp_gatts_handle_cback(uint16_t event, char* p_param)
    169 {
    170     ALOGD("%s: Event %d", __FUNCTION__, event);
    171 
    172     tBTA_GATTS *p_data = (tBTA_GATTS*)p_param;
    173     switch (event)
    174     {
    175         case BTA_GATTS_REG_EVT:
    176         {
    177             bt_uuid_t app_uuid;
    178             bta_to_btif_uuid(&app_uuid, &p_data->reg_oper.uuid);
    179             HAL_CBACK(bt_gatt_callbacks, server->register_server_cb
    180                 , p_data->reg_oper.status
    181                 , p_data->reg_oper.server_if
    182                 , &app_uuid
    183             );
    184             break;
    185         }
    186 
    187         case BTA_GATTS_DEREG_EVT:
    188             break;
    189 
    190         case BTA_GATTS_CONNECT_EVT:
    191         {
    192             bt_bdaddr_t bda;
    193             bdcpy(bda.address, p_data->conn.remote_bda);
    194 
    195             btif_gatt_check_encrypted_link(p_data->conn.remote_bda);
    196 
    197             HAL_CBACK(bt_gatt_callbacks, server->connection_cb,
    198                       p_data->conn.conn_id, p_data->conn.server_if, TRUE, &bda);
    199             break;
    200         }
    201 
    202         case BTA_GATTS_DISCONNECT_EVT:
    203         {
    204             bt_bdaddr_t bda;
    205             bdcpy(bda.address, p_data->conn.remote_bda);
    206 
    207             HAL_CBACK(bt_gatt_callbacks, server->connection_cb,
    208                       p_data->conn.conn_id, p_data->conn.server_if, FALSE, &bda);
    209             break;
    210         }
    211 
    212         case BTA_GATTS_CREATE_EVT:
    213         {
    214             btgatt_srvc_id_t srvc_id;
    215             srvc_id.is_primary = p_data->create.is_primary;
    216             srvc_id.id.inst_id = p_data->create.svc_instance;
    217             bta_to_btif_uuid(&srvc_id.id.uuid, &p_data->create.uuid);
    218 
    219             HAL_CBACK(bt_gatt_callbacks, server->service_added_cb,
    220                       p_data->create.status, p_data->create.server_if, &srvc_id,
    221                       p_data->create.service_id
    222             );
    223         }
    224         break;
    225 
    226         case BTA_GATTS_ADD_INCL_SRVC_EVT:
    227             HAL_CBACK(bt_gatt_callbacks, server->included_service_added_cb,
    228                       p_data->add_result.status,
    229                       p_data->add_result.server_if,
    230                       p_data->add_result.service_id,
    231                       p_data->add_result.attr_id);
    232             break;
    233 
    234         case BTA_GATTS_ADD_CHAR_EVT:
    235         {
    236             bt_uuid_t uuid;
    237             bta_to_btif_uuid(&uuid, &p_data->add_result.char_uuid);
    238 
    239             HAL_CBACK(bt_gatt_callbacks, server->characteristic_added_cb,
    240                       p_data->add_result.status,
    241                       p_data->add_result.server_if,
    242                       &uuid,
    243                       p_data->add_result.service_id,
    244                       p_data->add_result.attr_id);
    245             break;
    246         }
    247 
    248         case BTA_GATTS_ADD_CHAR_DESCR_EVT:
    249         {
    250             bt_uuid_t uuid;
    251             bta_to_btif_uuid(&uuid, &p_data->add_result.char_uuid);
    252 
    253             HAL_CBACK(bt_gatt_callbacks, server->descriptor_added_cb,
    254                       p_data->add_result.status,
    255                       p_data->add_result.server_if,
    256                       &uuid,
    257                       p_data->add_result.service_id,
    258                       p_data->add_result.attr_id);
    259             break;
    260         }
    261 
    262         case BTA_GATTS_START_EVT:
    263             HAL_CBACK(bt_gatt_callbacks, server->service_started_cb,
    264                       p_data->srvc_oper.status,
    265                       p_data->srvc_oper.server_if,
    266                       p_data->srvc_oper.service_id);
    267             break;
    268 
    269         case BTA_GATTS_STOP_EVT:
    270             HAL_CBACK(bt_gatt_callbacks, server->service_stopped_cb,
    271                       p_data->srvc_oper.status,
    272                       p_data->srvc_oper.server_if,
    273                       p_data->srvc_oper.service_id);
    274             break;
    275 
    276         case BTA_GATTS_DELELTE_EVT:
    277             HAL_CBACK(bt_gatt_callbacks, server->service_deleted_cb,
    278                       p_data->srvc_oper.status,
    279                       p_data->srvc_oper.server_if,
    280                       p_data->srvc_oper.service_id);
    281             break;
    282 
    283         case BTA_GATTS_READ_EVT:
    284         {
    285             bt_bdaddr_t bda;
    286             bdcpy(bda.address, p_data->req_data.remote_bda);
    287 
    288             HAL_CBACK(bt_gatt_callbacks, server->request_read_cb,
    289                       p_data->req_data.conn_id,p_data->req_data.trans_id, &bda,
    290                       p_data->req_data.p_data->read_req.handle,
    291                       p_data->req_data.p_data->read_req.offset,
    292                       p_data->req_data.p_data->read_req.is_long);
    293             break;
    294         }
    295 
    296         case BTA_GATTS_WRITE_EVT:
    297         {
    298             bt_bdaddr_t bda;
    299             bdcpy(bda.address, p_data->req_data.remote_bda);
    300 
    301             HAL_CBACK(bt_gatt_callbacks, server->request_write_cb,
    302                       p_data->req_data.conn_id,p_data->req_data.trans_id, &bda,
    303                       p_data->req_data.p_data->write_req.handle,
    304                       p_data->req_data.p_data->write_req.offset,
    305                       p_data->req_data.p_data->write_req.len,
    306                       p_data->req_data.p_data->write_req.need_rsp,
    307                       p_data->req_data.p_data->write_req.is_prep,
    308                       p_data->req_data.p_data->write_req.value);
    309             break;
    310         }
    311 
    312         case BTA_GATTS_EXEC_WRITE_EVT:
    313         {
    314             bt_bdaddr_t bda;
    315             bdcpy(bda.address, p_data->req_data.remote_bda);
    316 
    317             HAL_CBACK(bt_gatt_callbacks, server->request_exec_write_cb,
    318                       p_data->req_data.conn_id,p_data->req_data.trans_id, &bda,
    319                       p_data->req_data.p_data->exec_write);
    320             break;
    321         }
    322 
    323         case BTA_GATTS_MTU_EVT:
    324         case BTA_GATTS_OPEN_EVT:
    325         case BTA_GATTS_CANCEL_OPEN_EVT:
    326         case BTA_GATTS_CLOSE_EVT:
    327             ALOGD("%s: Empty event (%d)!", __FUNCTION__, event);
    328             break;
    329 
    330         default:
    331             ALOGE("%s: Unhandled event (%d)!", __FUNCTION__, event);
    332             break;
    333     }
    334 
    335     btapp_gatts_free_req_data(event, p_data);
    336 }
    337 
    338 static void btapp_gatts_cback(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
    339 {
    340     bt_status_t status;
    341     status = btif_transfer_context(btapp_gatts_handle_cback, (uint16_t) event,
    342         (void*)p_data, sizeof(tBTA_GATTS), btapp_gatts_copy_req_data);
    343     ASSERTC(status == BT_STATUS_SUCCESS, "Context transfer failed!", status);
    344 }
    345 
    346 static void btgatts_handle_event(uint16_t event, char* p_param)
    347 {
    348     btif_gatts_cb_t* p_cb = (btif_gatts_cb_t*)p_param;
    349     if (!p_cb) return;
    350 
    351     ALOGD("%s: Event %d", __FUNCTION__, event);
    352 
    353     switch (event)
    354     {
    355         case BTIF_GATTS_REGISTER_APP:
    356         {
    357             tBT_UUID uuid;
    358             btif_to_bta_uuid(&uuid, &p_cb->uuid);
    359             BTA_GATTS_AppRegister(&uuid, btapp_gatts_cback);
    360             break;
    361         }
    362 
    363         case BTIF_GATTS_UNREGISTER_APP:
    364             BTA_GATTS_AppDeregister(p_cb->server_if);
    365             break;
    366 
    367         case BTIF_GATTS_OPEN:
    368             if (!p_cb->is_direct)
    369                 BTA_DmBleSetBgConnType(BTM_BLE_CONN_AUTO, NULL);
    370             BTA_GATTS_Open(p_cb->server_if, p_cb->bd_addr.address,
    371                            p_cb->is_direct);
    372             break;
    373 
    374         case BTIF_GATTS_CLOSE:
    375             // Cancel pending foreground/background connections
    376             BTA_GATTS_CancelOpen(p_cb->server_if, p_cb->bd_addr.address, TRUE);
    377             BTA_GATTS_CancelOpen(p_cb->server_if, p_cb->bd_addr.address, FALSE);
    378 
    379             // Close active connection
    380             if (p_cb->conn_id != 0)
    381                 BTA_GATTS_Close(p_cb->conn_id);
    382             break;
    383 
    384         case BTIF_GATTS_CREATE_SERVICE:
    385         {
    386             tBTA_GATT_SRVC_ID srvc_id;
    387             btif_to_bta_srvc_id(&srvc_id, &p_cb->srvc_id);
    388             BTA_GATTS_CreateService(p_cb->server_if, &srvc_id.id.uuid,
    389                                     srvc_id.id.inst_id, p_cb->num_handles,
    390                                     srvc_id.is_primary);
    391             break;
    392         }
    393 
    394         case BTIF_GATTS_ADD_INCLUDED_SERVICE:
    395             BTA_GATTS_AddIncludeService(p_cb->srvc_handle, p_cb->incl_handle);
    396             break;
    397 
    398         case BTIF_GATTS_ADD_CHARACTERISTIC:
    399         {
    400             tBT_UUID uuid;
    401             btif_to_bta_uuid(&uuid, &p_cb->uuid);
    402 
    403             BTA_GATTS_AddCharacteristic(p_cb->srvc_handle, &uuid,
    404                                         p_cb->permissions, p_cb->properties);
    405             break;
    406         }
    407 
    408         case BTIF_GATTS_ADD_DESCRIPTOR:
    409         {
    410             tBT_UUID uuid;
    411             btif_to_bta_uuid(&uuid, &p_cb->uuid);
    412 
    413             BTA_GATTS_AddCharDescriptor(p_cb->srvc_handle, p_cb->permissions,
    414                                          &uuid);
    415             break;
    416         }
    417 
    418         case BTIF_GATTS_START_SERVICE:
    419             BTA_GATTS_StartService(p_cb->srvc_handle, p_cb->transport);
    420             break;
    421 
    422         case BTIF_GATTS_STOP_SERVICE:
    423             BTA_GATTS_StopService(p_cb->srvc_handle);
    424             break;
    425 
    426         case BTIF_GATTS_DELETE_SERVICE:
    427             BTA_GATTS_DeleteService(p_cb->srvc_handle);
    428             break;
    429 
    430         case BTIF_GATTS_SEND_INDICATION:
    431             BTA_GATTS_HandleValueIndication(p_cb->conn_id, p_cb->attr_handle,
    432                                         p_cb->len, p_cb->value, p_cb->confirm);
    433             // TODO: Might need to send an ACK if handle value indication is
    434             //       invoked without need for confirmation.
    435             break;
    436 
    437         case BTIF_GATTS_SEND_RESPONSE:
    438         {
    439             tBTA_GATTS_RSP rsp_struct;
    440             btgatt_response_t *p_rsp = &p_cb->response;
    441             btif_to_bta_response(&rsp_struct, p_rsp);
    442 
    443             BTA_GATTS_SendRsp(p_cb->conn_id, p_cb->trans_id,
    444                               p_cb->status, &rsp_struct);
    445 
    446             HAL_CBACK(bt_gatt_callbacks, server->response_confirmation_cb,
    447                       0, rsp_struct.attr_value.handle);
    448             break;
    449         }
    450 
    451         default:
    452             ALOGE("%s: Unknown event (%d)!", __FUNCTION__, event);
    453             break;
    454     }
    455 }
    456 
    457 /************************************************************************************
    458 **  Server API Functions
    459 ************************************************************************************/
    460 
    461 static bt_status_t btif_gatts_register_app(bt_uuid_t *uuid)
    462 {
    463     CHECK_BTGATT_INIT();
    464     btif_gatts_cb_t btif_cb;
    465     memcpy(&btif_cb.uuid, uuid, sizeof(bt_uuid_t));
    466     return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_REGISTER_APP,
    467                                  (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL);
    468 }
    469 
    470 static bt_status_t btif_gatts_unregister_app( int server_if )
    471 {
    472     CHECK_BTGATT_INIT();
    473     btif_gatts_cb_t btif_cb;
    474     btif_cb.server_if = (uint8_t) server_if;
    475     return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_UNREGISTER_APP,
    476                                  (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL);
    477 }
    478 
    479 static bt_status_t btif_gatts_open( int server_if, const bt_bdaddr_t *bd_addr, bool is_direct )
    480 {
    481     CHECK_BTGATT_INIT();
    482     btif_gatts_cb_t btif_cb;
    483     btif_cb.server_if = (uint8_t) server_if;
    484     btif_cb.is_direct = is_direct ? 1 : 0;
    485     bdcpy(btif_cb.bd_addr.address, bd_addr->address);
    486     return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_OPEN,
    487                                  (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL);
    488 }
    489 
    490 static bt_status_t btif_gatts_close(int server_if, const bt_bdaddr_t *bd_addr, int conn_id)
    491 {
    492     CHECK_BTGATT_INIT();
    493     btif_gatts_cb_t btif_cb;
    494     btif_cb.server_if = (uint8_t) server_if;
    495     btif_cb.conn_id = (uint16_t) conn_id;
    496     bdcpy(btif_cb.bd_addr.address, bd_addr->address);
    497     return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_CLOSE,
    498                                  (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL);
    499 }
    500 
    501 static bt_status_t btif_gatts_add_service(int server_if, btgatt_srvc_id_t *srvc_id,
    502                                           int num_handles)
    503 {
    504     CHECK_BTGATT_INIT();
    505     btif_gatts_cb_t btif_cb;
    506     btif_cb.server_if = (uint8_t) server_if;
    507     btif_cb.num_handles = (uint8_t) num_handles;
    508     memcpy(&btif_cb.srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
    509     return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_CREATE_SERVICE,
    510                                  (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL);
    511 }
    512 
    513 static bt_status_t btif_gatts_add_included_service(int server_if, int service_handle,
    514                                                    int included_handle)
    515 {
    516     CHECK_BTGATT_INIT();
    517     btif_gatts_cb_t btif_cb;
    518     btif_cb.server_if = (uint8_t) server_if;
    519     btif_cb.srvc_handle = (uint16_t) service_handle;
    520     btif_cb.incl_handle = (uint16_t) included_handle;
    521     return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_ADD_INCLUDED_SERVICE,
    522                                  (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL);
    523 }
    524 
    525 static bt_status_t btif_gatts_add_characteristic(int server_if, int service_handle,
    526                                                  bt_uuid_t *uuid, int properties,
    527                                                  int permissions)
    528 {
    529     CHECK_BTGATT_INIT();
    530     btif_gatts_cb_t btif_cb;
    531     btif_cb.server_if = (uint8_t) server_if;
    532     btif_cb.srvc_handle = (uint16_t) service_handle;
    533     btif_cb.properties = (uint8_t) properties;
    534     btif_cb.permissions = (uint16_t) permissions;
    535     memcpy(&btif_cb.uuid, uuid, sizeof(bt_uuid_t));
    536     return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_ADD_CHARACTERISTIC,
    537                                  (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL);
    538 }
    539 
    540 static bt_status_t btif_gatts_add_descriptor(int server_if, int service_handle, bt_uuid_t *uuid,
    541                                              int permissions)
    542 {
    543     CHECK_BTGATT_INIT();
    544     btif_gatts_cb_t btif_cb;
    545     btif_cb.server_if = (uint8_t) server_if;
    546     btif_cb.srvc_handle = (uint16_t) service_handle;
    547     btif_cb.permissions = (uint16_t) permissions;
    548     memcpy(&btif_cb.uuid, uuid, sizeof(bt_uuid_t));
    549     return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_ADD_DESCRIPTOR,
    550                                  (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL);
    551 }
    552 
    553 static bt_status_t btif_gatts_start_service(int server_if, int service_handle, int transport)
    554 {
    555     CHECK_BTGATT_INIT();
    556     btif_gatts_cb_t btif_cb;
    557     btif_cb.server_if = (uint8_t) server_if;
    558     btif_cb.srvc_handle = (uint16_t) service_handle;
    559     btif_cb.transport = (uint8_t) transport;
    560     return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_START_SERVICE,
    561                                  (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL);
    562 }
    563 
    564 static bt_status_t btif_gatts_stop_service(int server_if, int service_handle)
    565 {
    566     CHECK_BTGATT_INIT();
    567     btif_gatts_cb_t btif_cb;
    568     btif_cb.server_if = (uint8_t) server_if;
    569     btif_cb.srvc_handle = (uint16_t) service_handle;
    570     return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_STOP_SERVICE,
    571                                  (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL);
    572 }
    573 
    574 static bt_status_t btif_gatts_delete_service(int server_if, int service_handle)
    575 {
    576     CHECK_BTGATT_INIT();
    577     btif_gatts_cb_t btif_cb;
    578     btif_cb.server_if = (uint8_t) server_if;
    579     btif_cb.srvc_handle = (uint16_t) service_handle;
    580     return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_DELETE_SERVICE,
    581                                  (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL);
    582 }
    583 
    584 static bt_status_t btif_gatts_send_indication(int server_if, int attribute_handle, int conn_id,
    585                                               int len, int confirm, char* p_value)
    586 {
    587     CHECK_BTGATT_INIT();
    588     btif_gatts_cb_t btif_cb;
    589     btif_cb.server_if = (uint8_t) server_if;
    590     btif_cb.conn_id = (uint16_t) conn_id;
    591     btif_cb.attr_handle = attribute_handle;
    592     btif_cb.confirm = confirm;
    593     btif_cb.len = len;
    594     memcpy(btif_cb.value, p_value, len > BTGATT_MAX_ATTR_LEN ? BTGATT_MAX_ATTR_LEN : len);
    595     return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_SEND_INDICATION,
    596                                  (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL);
    597 }
    598 
    599 static bt_status_t btif_gatts_send_response(int conn_id, int trans_id,
    600                                             int status, btgatt_response_t *response)
    601 {
    602     CHECK_BTGATT_INIT();
    603     btif_gatts_cb_t btif_cb;
    604     btif_cb.conn_id = (uint16_t) conn_id;
    605     btif_cb.trans_id = (uint32_t) trans_id;
    606     btif_cb.status = (uint8_t) status;
    607     memcpy(&btif_cb.response, response, sizeof(btgatt_response_t));
    608     return btif_transfer_context(btgatts_handle_event, BTIF_GATTS_SEND_RESPONSE,
    609                                  (char*) &btif_cb, sizeof(btif_gatts_cb_t), NULL);
    610 }
    611 
    612 const btgatt_server_interface_t btgattServerInterface = {
    613     btif_gatts_register_app,
    614     btif_gatts_unregister_app,
    615     btif_gatts_open,
    616     btif_gatts_close,
    617     btif_gatts_add_service,
    618     btif_gatts_add_included_service,
    619     btif_gatts_add_characteristic,
    620     btif_gatts_add_descriptor,
    621     btif_gatts_start_service,
    622     btif_gatts_stop_service,
    623     btif_gatts_delete_service,
    624     btif_gatts_send_indication,
    625     btif_gatts_send_response
    626 };
    627 
    628 #endif
    629