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*******************************************************************************/
58UINT8 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
84BOOLEAN 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*******************************************************************************/
111BOOLEAN  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*******************************************************************************/
141UINT16 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_API ("GATTS_CreateService" );
155
156    if (p_reg == NULL)
157    {
158        GATT_TRACE_ERROR ("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_DEBUG ("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_ERROR ("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_ERROR ("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_ERROR ("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_DEBUG ("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_ERROR ("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_DEBUG ("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*******************************************************************************/
277UINT16 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_DEBUG("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_DEBUG("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*******************************************************************************/
315UINT16 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_DEBUG("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_DEBUG("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*******************************************************************************/
357UINT16 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_DEBUG("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         && p_descr_uuid->len !=  LEN_UUID_32))
371    {
372        GATT_TRACE_DEBUG("Illegal parameter");
373        return 0;
374    }
375
376    return gatts_add_char_descr(&p_decl->svc_db,
377                                perm,
378                                p_descr_uuid);
379
380}
381/*******************************************************************************
382**
383** Function         GATTS_DeleteService
384**
385** Description      This function is called to delete a service.
386**
387** Parameter        gatt_if       : application interface
388**                  p_svc_uuid    : service UUID
389**                  svc_inst      : instance of the service inside the application
390**
391** Returns          TRUE if operation succeed, FALSE if handle block was not found.
392**
393*******************************************************************************/
394BOOLEAN GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, UINT16 svc_inst)
395{
396
397    tGATT_HDL_LIST_INFO             *p_list_info= &gatt_cb.hdl_list_info;
398    tGATT_HDL_LIST_ELEM             *p_list=NULL;
399    UINT8                           i_sreg;
400    tGATTS_PENDING_NEW_SRV_START    *p_buf;
401    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
402    tBT_UUID *p_app_uuid128;
403
404    GATT_TRACE_DEBUG ("GATTS_DeleteService");
405
406    if (p_reg == NULL)
407    {
408        GATT_TRACE_ERROR ("Applicaiton not foud");
409        return(FALSE);
410    }
411    p_app_uuid128 = &p_reg->app_uuid128;
412
413    if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) == NULL)
414    {
415        GATT_TRACE_ERROR ("No Service found");
416        return(FALSE);
417    }
418
419    if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128,
420                                         &p_list->asgn_range.svc_uuid,
421                                         p_list->asgn_range.svc_inst)) != NULL)
422    {
423        GATT_TRACE_DEBUG ("Delete a new service changed item - the service has not yet started");
424        GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf));
425    }
426    else
427    {
428        gatt_proc_srv_chg();
429    }
430
431    if ((i_sreg = gatt_sr_find_i_rcb_by_app_id (p_app_uuid128,
432                                                p_svc_uuid,
433                                                svc_inst)) != GATT_MAX_SR_PROFILES)
434    {
435        GATTS_StopService(gatt_cb.sr_reg[i_sreg].s_hdl);
436    }
437
438    GATT_TRACE_DEBUG ("released handles s_hdl=%u e_hdl=%u",
439                       p_list->asgn_range.s_handle , p_list->asgn_range.e_handle  );
440
441    if ( (p_list->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl)
442         && gatt_cb.cb_info.p_nv_save_callback)
443        (*gatt_cb.cb_info.p_nv_save_callback)(FALSE, &p_list->asgn_range);
444
445    gatt_remove_an_item_from_list(p_list_info, p_list);
446    gatt_free_hdl_buffer(p_list);
447
448    return(TRUE);
449}
450
451/*******************************************************************************
452**
453** Function         GATTS_StartService
454**
455** Description      This function is called to start a service with GATT
456**
457** Parameter        gatt_if : service handle.
458**                  p_cback       : application service callback functions.
459**                  sup_transport : supported transport(s) for this primary service
460**
461** return           GATT_SUCCESS if sucessfully started; otherwise error code.
462**
463*******************************************************************************/
464tGATT_STATUS GATTS_StartService (tGATT_IF gatt_if, UINT16 service_handle,
465                                 tGATT_TRANSPORT sup_transport)
466{
467    tGATT_SR_REG            *p_sreg;
468    tGATT_HDL_LIST_ELEM      *p_list=NULL;
469    UINT8                    i_sreg;
470    tBT_UUID                *p_uuid;
471    tGATT_REG              *p_reg = gatt_get_regcb(gatt_if);
472
473    tGATTS_PENDING_NEW_SRV_START *p_buf;
474
475    GATT_TRACE_API ("GATTS_StartService");
476
477    if (p_reg == NULL)
478    {
479        /* Not found  */
480        GATT_TRACE_ERROR ("Applicaiton not found ");
481        return GATT_NOT_FOUND;
482    }
483
484    if ((p_list = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
485    {
486        /* Not found  */
487        GATT_TRACE_ERROR ("no service found");
488        return GATT_NOT_FOUND;
489    }
490
491    if (gatt_sr_find_i_rcb_by_app_id (&p_list->asgn_range.app_uuid128,
492                                      &p_list->asgn_range.svc_uuid,
493                                      p_list->asgn_range.svc_inst) != GATT_MAX_SR_PROFILES)
494    {
495        GATT_TRACE_ERROR ("Duplicate Service start - Service already started");
496        return GATT_SERVICE_STARTED;
497    }
498
499    /*this is a new application servoce start */
500    if ((i_sreg = gatt_sr_alloc_rcb(p_list)) ==  GATT_MAX_SR_PROFILES)
501    {
502        GATT_TRACE_ERROR ("GATTS_StartService: no free server registration block");
503        return GATT_NO_RESOURCES;
504    }
505
506    p_sreg = &gatt_cb.sr_reg[i_sreg];
507    p_sreg->gatt_if = gatt_if;
508
509    switch (sup_transport)
510    {
511        case GATT_TRANSPORT_BR_EDR:
512        case GATT_TRANSPORT_LE_BR_EDR:
513            if (p_sreg->type == GATT_UUID_PRI_SERVICE)
514            {
515                p_uuid = gatts_get_service_uuid (p_sreg->p_db);
516
517                p_sreg->sdp_handle = gatt_add_sdp_record(p_uuid, p_sreg->s_hdl, p_sreg->e_hdl);
518            }
519            break;
520        default:
521            break;
522    }
523
524    gatts_update_srv_list_elem(i_sreg, p_sreg->s_hdl,
525                               p_list->asgn_range.is_primary);
526
527    gatt_add_a_srv_to_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[i_sreg]);
528
529    GATT_TRACE_DEBUG ("allocated i_sreg=%d ",i_sreg);
530
531    GATT_TRACE_DEBUG ("s_hdl=%d e_hdl=%d type=0x%x svc_inst=%d sdp_hdl=0x%x",
532                       p_sreg->s_hdl,p_sreg->e_hdl,
533                       p_sreg->type,  p_sreg->service_instance,
534                       p_sreg->sdp_handle);
535
536
537    if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128,
538                                         &p_list->asgn_range.svc_uuid,
539                                         p_list->asgn_range.svc_inst)) != NULL)
540    {
541        gatt_proc_srv_chg();
542        /* remove the new service element after the srv changed processing is completed*/
543
544        GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf));
545    }
546    return GATT_SUCCESS;
547}
548
549/*******************************************************************************
550**
551** Function         GATTS_StopService
552**
553** Description      This function is called to stop a service
554**
555** Parameter         service_handle : this is the start handle of a service
556**
557** Returns          None.
558**
559*******************************************************************************/
560void GATTS_StopService (UINT16 service_handle)
561{
562    UINT8           ii = gatt_sr_find_i_rcb_by_handle(service_handle);
563
564    GATT_TRACE_API("GATTS_StopService %u", service_handle);
565
566    /* Index 0 is reserved for GATT, and is never stopped */
567    if ( (ii > 0) && (ii < GATT_MAX_SR_PROFILES) && (gatt_cb.sr_reg[ii].in_use) )
568    {
569        if (gatt_cb.sr_reg[ii].sdp_handle)
570        {
571            SDP_DeleteRecord(gatt_cb.sr_reg[ii].sdp_handle);
572        }
573        gatt_remove_a_srv_from_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[ii]);
574        gatt_cb.srv_list[ii].in_use = FALSE;
575        memset (&gatt_cb.sr_reg[ii], 0, sizeof(tGATT_SR_REG));
576    }
577    else
578    {
579        GATT_TRACE_ERROR("GATTS_StopService service_handle: %u is not in use", service_handle);
580    }
581}
582/*******************************************************************************
583**
584** Function         GATTs_HandleValueIndication
585**
586** Description      This function sends a handle value indication to a client.
587**
588** Parameter        conn_id: connection identifier.
589**                  attr_handle: Attribute handle of this handle value indication.
590**                  val_len: Length of the indicated attribute value.
591**                  p_val: Pointer to the indicated attribute value data.
592**
593** Returns          GATT_SUCCESS if sucessfully sent or queued; otherwise error code.
594**
595*******************************************************************************/
596tGATT_STATUS GATTS_HandleValueIndication (UINT16 conn_id,  UINT16 attr_handle, UINT16 val_len, UINT8 *p_val)
597{
598    tGATT_STATUS    cmd_status = GATT_NO_RESOURCES;
599
600    tGATT_VALUE      indication;
601    BT_HDR          *p_msg;
602    tGATT_VALUE     *p_buf;
603    tGATT_IF         gatt_if = GATT_GET_GATT_IF(conn_id);
604    UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
605    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
606    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
607
608
609    GATT_TRACE_API ("GATTS_HandleValueIndication");
610    if ( (p_reg == NULL) || (p_tcb == NULL))
611    {
612        GATT_TRACE_ERROR ("GATTS_HandleValueIndication Unknown  conn_id: %u ", conn_id);
613        return(tGATT_STATUS) GATT_INVALID_CONN_ID;
614    }
615
616    if (! GATT_HANDLE_IS_VALID (attr_handle))
617        return GATT_ILLEGAL_PARAMETER;
618
619    indication.conn_id  = conn_id;
620    indication.handle   = attr_handle;
621    indication.len      = val_len;
622    memcpy (indication.value, p_val, val_len);
623    indication.auth_req = GATT_AUTH_REQ_NONE;
624
625    if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle))
626    {
627        GATT_TRACE_DEBUG ("Add a pending indication");
628        if ((p_buf = gatt_add_pending_ind(p_tcb, &indication)) !=NULL)
629        {
630            cmd_status = GATT_SUCCESS;
631        }
632        else
633        {
634            cmd_status = GATT_NO_RESOURCES;
635        }
636    }
637    else
638    {
639
640        if ( (p_msg = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_IND, (tGATT_SR_MSG *)&indication)) != NULL)
641        {
642            cmd_status = attp_send_sr_msg (p_tcb, p_msg);
643
644            if (cmd_status == GATT_SUCCESS || cmd_status == GATT_CONGESTED)
645            {
646                p_tcb->indicate_handle = indication.handle;
647                gatt_start_conf_timer(p_tcb);
648            }
649        }
650    }
651    return cmd_status;
652}
653
654/*******************************************************************************
655**
656** Function         GATTS_HandleValueNotification
657**
658** Description      This function sends a handle value notification to a client.
659**
660** Parameter        conn_id: connection identifier.
661**                  attr_handle: Attribute handle of this handle value indication.
662**                  val_len: Length of the indicated attribute value.
663**                  p_val: Pointer to the indicated attribute value data.
664**
665** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
666**
667*******************************************************************************/
668tGATT_STATUS GATTS_HandleValueNotification (UINT16 conn_id, UINT16 attr_handle,
669                                            UINT16 val_len, UINT8 *p_val)
670{
671    tGATT_STATUS    cmd_sent = GATT_ILLEGAL_PARAMETER;
672    BT_HDR          *p_buf;
673    tGATT_VALUE     notif;
674    tGATT_IF         gatt_if = GATT_GET_GATT_IF(conn_id);
675    UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
676    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
677    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
678
679    GATT_TRACE_API ("GATTS_HandleValueNotification");
680
681    if ( (p_reg == NULL) || (p_tcb == NULL))
682    {
683        GATT_TRACE_ERROR ("GATTS_HandleValueNotification Unknown  conn_id: %u ", conn_id);
684        return(tGATT_STATUS) GATT_INVALID_CONN_ID;
685    }
686
687    if (GATT_HANDLE_IS_VALID (attr_handle))
688    {
689        notif.handle    = attr_handle;
690        notif.len       = val_len;
691        memcpy (notif.value, p_val, val_len);
692        notif.auth_req = GATT_AUTH_REQ_NONE;;
693
694        if ((p_buf = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_NOTIF, (tGATT_SR_MSG *)&notif))
695                   != NULL)
696        {
697            cmd_sent = attp_send_sr_msg (p_tcb, p_buf);
698        }
699        else
700            cmd_sent = GATT_NO_RESOURCES;
701    }
702    return cmd_sent;
703}
704
705/*******************************************************************************
706**
707** Function         GATTS_SendRsp
708**
709** Description      This function sends the server response to client.
710**
711** Parameter        conn_id: connection identifier.
712**                  trans_id: transaction id
713**                  status: response status
714**                  p_msg: pointer to message parameters structure.
715**
716** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
717**
718*******************************************************************************/
719tGATT_STATUS GATTS_SendRsp (UINT16 conn_id,  UINT32 trans_id,
720                            tGATT_STATUS status, tGATTS_RSP *p_msg)
721{
722    tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
723    tGATT_IF         gatt_if = GATT_GET_GATT_IF(conn_id);
724    UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
725    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
726    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
727
728    GATT_TRACE_API ("GATTS_SendRsp: conn_id: %u  trans_id: %u  Status: 0x%04x",
729                     conn_id, trans_id, status);
730
731    if ( (p_reg == NULL) || (p_tcb == NULL))
732    {
733        GATT_TRACE_ERROR ("GATTS_SendRsp Unknown  conn_id: %u ", conn_id);
734        return(tGATT_STATUS) GATT_INVALID_CONN_ID;
735    }
736
737    if (p_tcb->sr_cmd.trans_id != trans_id)
738    {
739        GATT_TRACE_ERROR ("GATTS_SendRsp conn_id: %u  waiting for op_code = %02x",
740                           conn_id, p_tcb->sr_cmd.op_code);
741
742        return(GATT_WRONG_STATE);
743    }
744    /* Process App response */
745    cmd_sent = gatt_sr_process_app_rsp (p_tcb,  gatt_if, trans_id, p_tcb->sr_cmd.op_code, status, p_msg);
746
747    return cmd_sent;
748}
749
750/*******************************************************************************/
751/* GATT Profile Srvr Functions */
752/*******************************************************************************/
753
754/*******************************************************************************/
755/*                                                                             */
756/*                   GATT CLIENT APIs                                          */
757/*                                                                             */
758/*******************************************************************************/
759
760
761/*******************************************************************************
762**
763** Function         GATTC_ConfigureMTU
764**
765** Description      This function is called to configure the ATT MTU size.
766**
767** Parameters       conn_id: connection identifier.
768**                  mtu    - attribute MTU size..
769**
770** Returns          GATT_SUCCESS if command started successfully.
771**
772*******************************************************************************/
773tGATT_STATUS GATTC_ConfigureMTU (UINT16 conn_id, UINT16 mtu)
774{
775    UINT8           ret = GATT_NO_RESOURCES;
776    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
777    UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
778    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
779    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
780
781    tGATT_CLCB    *p_clcb;
782
783    GATT_TRACE_API ("GATTC_ConfigureMTU conn_id=%d mtu=%d", conn_id, mtu );
784
785    /* Validate that the link is BLE, not BR/EDR */
786    if (p_tcb->transport != BT_TRANSPORT_LE)
787    {
788        return GATT_ERROR;
789    }
790
791    if ( (p_tcb == NULL) || (p_reg==NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) || (mtu > GATT_MAX_MTU_SIZE))
792    {
793        return GATT_ILLEGAL_PARAMETER;
794    }
795
796    if (gatt_is_clcb_allocated(conn_id))
797    {
798        GATT_TRACE_ERROR("GATTC_ConfigureMTU GATT_BUSY conn_id = %d", conn_id);
799        return GATT_BUSY;
800    }
801
802    if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL)
803    {
804        p_clcb->p_tcb->payload_size = mtu;
805        p_clcb->operation = GATTC_OPTYPE_CONFIG;
806
807        ret = attp_send_cl_msg (p_clcb->p_tcb, p_clcb->clcb_idx, GATT_REQ_MTU, (tGATT_CL_MSG *)&mtu);
808    }
809
810    return ret;
811}
812
813/*******************************************************************************
814**
815** Function         GATTC_Discover
816**
817** Description      This function is called to do a discovery procedure on ATT server.
818**
819** Parameters       conn_id: connection identifier.
820**                  disc_type:discovery type.
821**                  p_param: parameters of discovery requirement.
822**
823** Returns          GATT_SUCCESS if command received/sent successfully.
824**
825*******************************************************************************/
826tGATT_STATUS GATTC_Discover (UINT16 conn_id, tGATT_DISC_TYPE disc_type,
827                             tGATT_DISC_PARAM *p_param)
828{
829    tGATT_STATUS    status = GATT_SUCCESS;
830    tGATT_CLCB      *p_clcb;
831    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
832    UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
833    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
834    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
835
836
837    GATT_TRACE_API ("GATTC_Discover conn_id=%d disc_type=%d",conn_id, disc_type);
838
839    if ( (p_tcb == NULL) || (p_reg==NULL) ||(p_param == NULL) ||
840         (disc_type >= GATT_DISC_MAX))
841    {
842        GATT_TRACE_ERROR("GATTC_Discover Illegal param: disc_type %d conn_id = %d", disc_type, conn_id);
843        return GATT_ILLEGAL_PARAMETER;
844    }
845
846
847    if (gatt_is_clcb_allocated(conn_id))
848    {
849        GATT_TRACE_ERROR("GATTC_Discover GATT_BUSY conn_id = %d", conn_id);
850        return GATT_BUSY;
851    }
852
853
854    if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
855    {
856        if (!GATT_HANDLE_IS_VALID(p_param->s_handle) ||
857            !GATT_HANDLE_IS_VALID(p_param->e_handle) ||
858            /* search by type does not have a valid UUID param */
859            (disc_type == GATT_DISC_SRVC_BY_UUID &&
860             p_param->service.len == 0))
861        {
862            gatt_clcb_dealloc(p_clcb);
863            return GATT_ILLEGAL_PARAMETER;
864        }
865
866        p_clcb->operation  = GATTC_OPTYPE_DISCOVERY;
867        p_clcb->op_subtype = disc_type;
868        p_clcb->s_handle   = p_param->s_handle;
869        p_clcb->e_handle   = p_param->e_handle;
870        p_clcb->uuid       = p_param->service;
871
872        gatt_act_discovery(p_clcb);
873    }
874    else
875    {
876        status = GATT_NO_RESOURCES;
877    }
878    return status;
879}
880
881/*******************************************************************************
882**
883** Function         GATTC_Read
884**
885** Description      This function is called to read the value of an attribute from
886**                  the server.
887**
888** Parameters       conn_id: connection identifier.
889**                  type    - attribute read type.
890**                  p_read  - read operation parameters.
891**
892** Returns          GATT_SUCCESS if command started successfully.
893**
894*******************************************************************************/
895tGATT_STATUS GATTC_Read (UINT16 conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read)
896{
897    tGATT_STATUS status = GATT_SUCCESS;
898    tGATT_CLCB          *p_clcb;
899    tGATT_READ_MULTI    *p_read_multi;
900    tGATT_IF            gatt_if=GATT_GET_GATT_IF(conn_id);
901    UINT8               tcb_idx = GATT_GET_TCB_IDX(conn_id);
902    tGATT_TCB           *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
903    tGATT_REG           *p_reg = gatt_get_regcb(gatt_if);
904
905
906    GATT_TRACE_API ("GATTC_Read conn_id=%d type=%d", conn_id, type);
907
908    if ( (p_tcb == NULL) || (p_reg==NULL) || (p_read == NULL) || ((type >= GATT_READ_MAX) || (type == 0)))
909    {
910        GATT_TRACE_ERROR("GATT_Read Illegal param: conn_id %d, type 0%d,", conn_id, type);
911        return GATT_ILLEGAL_PARAMETER;
912    }
913
914    if (gatt_is_clcb_allocated(conn_id))
915    {
916        GATT_TRACE_ERROR("GATTC_Read GATT_BUSY conn_id = %d", conn_id);
917        return GATT_BUSY;
918    }
919
920    if ( (p_clcb = gatt_clcb_alloc(conn_id)) != NULL  )
921    {
922        p_clcb->operation = GATTC_OPTYPE_READ;
923        p_clcb->op_subtype = type;
924        p_clcb->auth_req = p_read->by_handle.auth_req;
925        p_clcb->counter = 0;
926
927        switch (type)
928        {
929            case GATT_READ_BY_TYPE:
930            case GATT_READ_CHAR_VALUE:
931                p_clcb->s_handle = p_read->service.s_handle;
932                p_clcb->e_handle = p_read->service.e_handle;
933                memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID));
934                break;
935            case GATT_READ_MULTIPLE:
936                p_clcb->s_handle = 0;
937                /* copy multiple handles in CB */
938                p_read_multi = (tGATT_READ_MULTI *)GKI_getbuf(sizeof(tGATT_READ_MULTI));
939                p_clcb->p_attr_buf = (UINT8*)p_read_multi;
940                memcpy (p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI));
941            case GATT_READ_BY_HANDLE:
942            case GATT_READ_PARTIAL:
943                memset(&p_clcb->uuid, 0, sizeof(tBT_UUID));
944                p_clcb->s_handle = p_read->by_handle.handle;
945
946                if (type == GATT_READ_PARTIAL)
947                {
948                    p_clcb->counter = p_read->partial.offset;
949                }
950
951                break;
952            default:
953                break;
954        }
955        /* start security check */
956        if (gatt_security_check_start(p_clcb) == FALSE)
957        {
958            status = GATT_NO_RESOURCES;
959            gatt_clcb_dealloc(p_clcb);
960        }
961    }
962    else
963    {
964        status = GATT_NO_RESOURCES;
965    }
966    return status;
967}
968
969/*******************************************************************************
970**
971** Function         GATTC_Write
972**
973** Description      This function is called to write the value of an attribute to
974**                  the server.
975**
976** Parameters       conn_id: connection identifier.
977**                  type    - attribute write type.
978**                  p_write  - write operation parameters.
979**
980** Returns          GATT_SUCCESS if command started successfully.
981**
982*******************************************************************************/
983tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
984{
985    tGATT_STATUS status = GATT_SUCCESS;
986    tGATT_CLCB      *p_clcb;
987    tGATT_VALUE     *p;
988    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
989    UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
990    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
991    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
992
993    if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) ||
994         ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) )
995    {
996        GATT_TRACE_ERROR("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type);
997        return GATT_ILLEGAL_PARAMETER;
998    }
999
1000    if (gatt_is_clcb_allocated(conn_id))
1001    {
1002        GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
1003        return GATT_BUSY;
1004    }
1005
1006    if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
1007    {
1008        p_clcb->operation  = GATTC_OPTYPE_WRITE;
1009        p_clcb->op_subtype = type;
1010        p_clcb->auth_req = p_write->auth_req;
1011
1012        if (( p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL)
1013        {
1014            memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));
1015
1016            p =  (tGATT_VALUE *)p_clcb->p_attr_buf;
1017            if (type == GATT_WRITE_PREPARE)
1018            {
1019                p_clcb->start_offset = p_write->offset;
1020                p->offset = 0;
1021            }
1022
1023            if (gatt_security_check_start(p_clcb) == FALSE)
1024            {
1025                status = GATT_NO_RESOURCES;
1026            }
1027        }
1028        else
1029        {
1030            status = GATT_NO_RESOURCES;
1031        }
1032
1033        if (status == GATT_NO_RESOURCES)
1034            gatt_clcb_dealloc(p_clcb);
1035    }
1036    else
1037    {
1038        status = GATT_NO_RESOURCES;
1039    }
1040    return status;
1041}
1042
1043
1044/*******************************************************************************
1045**
1046** Function         GATTC_ExecuteWrite
1047**
1048** Description      This function is called to send an Execute write request to
1049**                  the server.
1050**
1051** Parameters       conn_id: connection identifier.
1052**                  is_execute - to execute or cancel the prepare write requet(s)
1053**
1054** Returns          GATT_SUCCESS if command started successfully.
1055**
1056*******************************************************************************/
1057tGATT_STATUS GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute)
1058{
1059    tGATT_STATUS status = GATT_SUCCESS;
1060    tGATT_CLCB      *p_clcb;
1061    tGATT_EXEC_FLAG flag;
1062    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
1063    UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
1064    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1065    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
1066
1067    GATT_TRACE_API ("GATTC_ExecuteWrite conn_id=%d is_execute=%d", conn_id, is_execute);
1068
1069    if ( (p_tcb == NULL) || (p_reg==NULL) )
1070    {
1071        GATT_TRACE_ERROR("GATTC_ExecuteWrite Illegal param: conn_id %d", conn_id);
1072        return GATT_ILLEGAL_PARAMETER;
1073    }
1074
1075    if (gatt_is_clcb_allocated(conn_id))
1076    {
1077        GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
1078        return GATT_BUSY;
1079    }
1080
1081    if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL)
1082    {
1083        p_clcb->operation  = GATTC_OPTYPE_EXE_WRITE;
1084        flag = is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL;
1085        gatt_send_queue_write_cancel (p_clcb->p_tcb, p_clcb, flag);
1086    }
1087    else
1088    {
1089        GATT_TRACE_ERROR("Unable to allocate client CB for conn_id %d ", conn_id);
1090        status = GATT_NO_RESOURCES;
1091    }
1092    return status;
1093}
1094
1095/*******************************************************************************
1096**
1097** Function         GATTC_SendHandleValueConfirm
1098**
1099** Description      This function is called to send a handle value confirmation
1100**                  as response to a handle value notification from server.
1101**
1102** Parameters       conn_id: connection identifier.
1103**                  handle: the handle of the attribute confirmation.
1104**
1105** Returns          GATT_SUCCESS if command started successfully.
1106**
1107*******************************************************************************/
1108tGATT_STATUS GATTC_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle)
1109{
1110    tGATT_STATUS    ret = GATT_ILLEGAL_PARAMETER;
1111    tGATT_TCB     *p_tcb=gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id));
1112
1113    GATT_TRACE_API ("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id, handle);
1114
1115    if (p_tcb)
1116    {
1117        if (p_tcb->ind_count > 0 )
1118        {
1119            btu_stop_timer (&p_tcb->ind_ack_timer_ent);
1120
1121            GATT_TRACE_DEBUG ("notif_count=%d ", p_tcb->ind_count);
1122            /* send confirmation now */
1123            ret = attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, (tGATT_CL_MSG *)&handle);
1124
1125            p_tcb->ind_count = 0;
1126
1127        }
1128        else
1129        {
1130            GATT_TRACE_DEBUG ("GATTC_SendHandleValueConfirm - conn_id: %u - ignored not waiting for indicaiton ack", conn_id);
1131            ret = GATT_SUCCESS;
1132        }
1133    }
1134    else
1135    {
1136        GATT_TRACE_ERROR ("GATTC_SendHandleValueConfirm - Unknown conn_id: %u", conn_id);
1137    }
1138    return ret;
1139}
1140
1141
1142/*******************************************************************************/
1143/*                                                                             */
1144/*                   GATT  APIs                                                */
1145/*                                                                             */
1146/*******************************************************************************/
1147/*******************************************************************************
1148**
1149** Function         GATT_SetIdleTimeout
1150**
1151** Description      This function (common to both client and server) sets the idle
1152**                  timeout for a tansport connection
1153**
1154** Parameter        bd_addr:   target device bd address.
1155**                  idle_tout: timeout value in seconds.
1156**
1157** Returns          void
1158**
1159*******************************************************************************/
1160void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout, tBT_TRANSPORT transport)
1161{
1162    tGATT_TCB       *p_tcb;
1163    BOOLEAN         status = FALSE;
1164
1165    if ((p_tcb = gatt_find_tcb_by_addr (bd_addr, transport)) != NULL)
1166    {
1167        if (p_tcb->att_lcid == L2CAP_ATT_CID)
1168        {
1169            status = L2CA_SetFixedChannelTout (bd_addr, L2CAP_ATT_CID, idle_tout);
1170
1171            if (idle_tout == GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP)
1172                L2CA_SetIdleTimeoutByBdAddr(p_tcb->peer_bda,
1173                                            GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP, BT_TRANSPORT_LE);
1174        }
1175        else
1176        {
1177            status = L2CA_SetIdleTimeout (p_tcb->att_lcid, idle_tout, FALSE);
1178        }
1179    }
1180
1181    GATT_TRACE_API ("GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)",
1182                    idle_tout, status);
1183}
1184
1185
1186/*******************************************************************************
1187**
1188** Function         GATT_Register
1189**
1190** Description      This function is called to register an  application
1191**                  with GATT
1192**
1193** Parameter        p_app_uuid128: Application UUID
1194**                  p_cb_info: callback functions.
1195**
1196** Returns          0 for error, otherwise the index of the client registered with GATT
1197**
1198*******************************************************************************/
1199tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info)
1200{
1201    tGATT_REG    *p_reg;
1202    UINT8        i_gatt_if=0;
1203    tGATT_IF     gatt_if=0;
1204
1205    GATT_TRACE_API ("GATT_Register");
1206    gatt_dbg_display_uuid(*p_app_uuid128);
1207
1208    for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
1209    {
1210        if (p_reg->in_use  && !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128, LEN_UUID_128))
1211        {
1212            GATT_TRACE_ERROR("application already registered.");
1213            return 0;
1214        }
1215    }
1216
1217    for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
1218    {
1219        if (!p_reg->in_use)
1220        {
1221            memset(p_reg, 0 , sizeof(tGATT_REG));
1222            i_gatt_if++;              /* one based number */
1223            p_reg->app_uuid128 =  *p_app_uuid128;
1224            gatt_if            =
1225            p_reg->gatt_if     = (tGATT_IF)i_gatt_if;
1226            p_reg->app_cb      = *p_cb_info;
1227            p_reg->in_use      = TRUE;
1228
1229            break;
1230        }
1231    }
1232    GATT_TRACE_API ("allocated gatt_if=%d", gatt_if);
1233    return gatt_if;
1234}
1235
1236
1237/*******************************************************************************
1238**
1239** Function         GATT_Deregister
1240**
1241** Description      This function deregistered the application from GATT.
1242**
1243** Parameters       gatt_if: applicaiton interface.
1244**
1245** Returns          None.
1246**
1247*******************************************************************************/
1248void GATT_Deregister (tGATT_IF gatt_if)
1249{
1250    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
1251    tGATT_TCB       *p_tcb;
1252    tGATT_CLCB       *p_clcb;
1253    UINT8           i, ii, j;
1254    tGATT_SR_REG    *p_sreg;
1255
1256    GATT_TRACE_API ("GATT_Deregister gatt_if=%d", gatt_if);
1257    /* Index 0 is GAP and is never deregistered */
1258    if ( (gatt_if == 0) || (p_reg == NULL) )
1259    {
1260        GATT_TRACE_ERROR ("GATT_Deregister with invalid gatt_if: %u", gatt_if);
1261        return;
1262    }
1263
1264    /* stop all services  */
1265    /* todo an applcaiton can not be deregistered if its services is also used by other application
1266      deregisteration need to bed performed in an orderly fashion
1267      no check for now */
1268
1269    for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++)
1270    {
1271        if (p_sreg->in_use && (p_sreg->gatt_if == gatt_if))
1272        {
1273            GATTS_StopService(p_sreg->s_hdl);
1274        }
1275    }
1276
1277    /* free all services db buffers if owned by this application */
1278    gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128);
1279
1280    /* When an application deregisters, check remove the link associated with the app */
1281
1282    for (i=0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++)
1283    {
1284        if (p_tcb->in_use)
1285        {
1286            if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE)
1287            {
1288                gatt_update_app_use_link_flag(gatt_if, p_tcb,  FALSE, FALSE);
1289                if (!gatt_num_apps_hold_link(p_tcb))
1290                {
1291                    /* this will disconnect the link or cancel the pending connect request at lower layer*/
1292                    gatt_disconnect(p_tcb);
1293                }
1294            }
1295
1296            for (j = 0, p_clcb= &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++)
1297            {
1298                if (p_clcb->in_use &&
1299                    (p_clcb->p_reg->gatt_if == gatt_if) &&
1300                    (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx))
1301                {
1302                    btu_stop_timer(&p_clcb->rsp_timer_ent);
1303                    gatt_clcb_dealloc (p_clcb);
1304                    break;
1305                }
1306            }
1307        }
1308    }
1309
1310    gatt_deregister_bgdev_list(gatt_if);
1311    /* update the listen mode */
1312#if (defined(BLE_PERIPHERAL_MODE_SUPPORT) && (BLE_PERIPHERAL_MODE_SUPPORT == TRUE))
1313    GATT_Listen(gatt_if, FALSE, NULL);
1314#endif
1315
1316    memset (p_reg, 0, sizeof(tGATT_REG));
1317}
1318
1319
1320/*******************************************************************************
1321**
1322** Function         GATT_StartIf
1323**
1324** Description      This function is called after registration to start receiving
1325**                  callbacks for registered interface.  Function may call back
1326**                  with connection status and queued notifications
1327**
1328** Parameter        gatt_if: applicaiton interface.
1329**
1330** Returns          None.
1331**
1332*******************************************************************************/
1333void GATT_StartIf (tGATT_IF gatt_if)
1334{
1335    tGATT_REG   *p_reg;
1336    tGATT_TCB   *p_tcb;
1337    BD_ADDR     bda;
1338    UINT8       start_idx, found_idx;
1339    UINT16      conn_id;
1340    tGATT_TRANSPORT transport ;
1341
1342    GATT_TRACE_API ("GATT_StartIf gatt_if=%d", gatt_if);
1343    if ((p_reg = gatt_get_regcb(gatt_if)) != NULL)
1344    {
1345        start_idx = 0;
1346        while (gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport))
1347        {
1348            p_tcb = gatt_find_tcb_by_addr(bda, transport);
1349            if (p_reg->app_cb.p_conn_cb && p_tcb)
1350            {
1351                conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
1352                (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0, transport);
1353            }
1354            start_idx = ++found_idx;
1355        }
1356    }
1357}
1358
1359
1360/*******************************************************************************
1361**
1362** Function         GATT_Connect
1363**
1364** Description      This function initiate a connecttion to a remote device on GATT
1365**                  channel.
1366**
1367** Parameters       gatt_if: applicaiton interface
1368**                  bd_addr: peer device address.
1369**                  is_direct: is a direct conenection or a background auto connection
1370**
1371** Returns          TRUE if connection started; FALSE if connection start failure.
1372**
1373*******************************************************************************/
1374BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct, tBT_TRANSPORT transport)
1375{
1376    tGATT_REG    *p_reg;
1377    BOOLEAN status = FALSE;
1378
1379    GATT_TRACE_API ("GATT_Connect gatt_if=%d", gatt_if);
1380
1381    /* Make sure app is registered */
1382    if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
1383    {
1384        GATT_TRACE_ERROR("GATT_Connect - gatt_if =%d is not registered", gatt_if);
1385        return(FALSE);
1386    }
1387
1388    if (is_direct)
1389        status = gatt_act_connect (p_reg, bd_addr, transport);
1390    else
1391    {
1392        if (transport == BT_TRANSPORT_LE)
1393        status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr, TRUE);
1394        else
1395        {
1396            GATT_TRACE_ERROR("Unsupported transport for background connection");
1397        }
1398    }
1399
1400    return status;
1401
1402}
1403
1404/*******************************************************************************
1405**
1406** Function         GATT_CancelConnect
1407**
1408** Description      This function terminate the connection initaition to a remote
1409**                  device on GATT channel.
1410**
1411** Parameters       gatt_if: client interface. If 0 used as unconditionally disconnect,
1412**                          typically used for direct connection cancellation.
1413**                  bd_addr: peer device address.
1414**
1415** Returns          TRUE if connection started; FALSE if connection start failure.
1416**
1417*******************************************************************************/
1418BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){
1419    tGATT_REG     *p_reg;
1420    tGATT_TCB     *p_tcb;
1421    BOOLEAN       status = TRUE;
1422    tGATT_IF      temp_gatt_if;
1423    UINT8         start_idx, found_idx;
1424
1425    GATT_TRACE_API ("GATT_CancelConnect gatt_if=%d", gatt_if);
1426
1427    if ((gatt_if != 0) && ((p_reg = gatt_get_regcb(gatt_if)) == NULL))
1428    {
1429        GATT_TRACE_ERROR("GATT_CancelConnect - gatt_if =%d is not registered", gatt_if);
1430        return(FALSE);
1431    }
1432
1433    if (is_direct)
1434    {
1435        if (!gatt_if)
1436        {
1437            GATT_TRACE_DEBUG("GATT_CancelConnect - unconditional");
1438            start_idx = 0;
1439            /* only LE connection can be cancelled */
1440            p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
1441            if (p_tcb && gatt_num_apps_hold_link(p_tcb))
1442            {
1443                while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx, &temp_gatt_if))
1444                {
1445                    status = gatt_cancel_open(temp_gatt_if, bd_addr);
1446                    start_idx = ++found_idx;
1447                }
1448            }
1449            else
1450            {
1451                GATT_TRACE_ERROR("GATT_CancelConnect - no app found");
1452                status = FALSE;
1453            }
1454        }
1455        else
1456        {
1457            status = gatt_cancel_open(gatt_if, bd_addr);
1458        }
1459    }
1460    else
1461    {
1462        if (!gatt_if)
1463        {
1464            if (gatt_get_num_apps_for_bg_dev(bd_addr))
1465            {
1466                while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if))
1467                    gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr);
1468            }
1469            else
1470            {
1471                GATT_TRACE_ERROR("GATT_CancelConnect -no app associated with the bg device for unconditional removal");
1472                status = FALSE;
1473            }
1474        }
1475        else
1476        {
1477            status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
1478        }
1479    }
1480
1481    return status;
1482}
1483
1484/*******************************************************************************
1485**
1486** Function         GATT_Disconnect
1487**
1488** Description      This function disconnect the GATT channel for this registered
1489**                  application.
1490**
1491** Parameters       conn_id: connection identifier.
1492**
1493** Returns          GATT_SUCCESS if disconnected.
1494**
1495*******************************************************************************/
1496tGATT_STATUS GATT_Disconnect (UINT16 conn_id)
1497{
1498    tGATT_STATUS    ret = GATT_ILLEGAL_PARAMETER;
1499    tGATT_TCB       *p_tcb=NULL;
1500    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
1501    UINT8          tcb_idx = GATT_GET_TCB_IDX(conn_id);
1502
1503    GATT_TRACE_API ("GATT_Disconnect conn_id=%d ", conn_id);
1504
1505    p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1506
1507    if (p_tcb)
1508    {
1509        gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE);
1510        if (!gatt_num_apps_hold_link(p_tcb))
1511        {
1512            gatt_disconnect(p_tcb);
1513        }
1514        ret = GATT_SUCCESS;
1515    }
1516    return ret;
1517}
1518
1519
1520/*******************************************************************************
1521**
1522** Function         GATT_GetConnectionInfor
1523**
1524** Description      This function use conn_id to find its associated BD address and applciation
1525**                  interface
1526**
1527** Parameters        conn_id: connection id  (input)
1528**                   p_gatt_if: applicaiton interface (output)
1529**                   bd_addr: peer device address. (output)
1530**
1531** Returns          TRUE the ligical link information is found for conn_id
1532**
1533*******************************************************************************/
1534BOOLEAN GATT_GetConnectionInfor(UINT16 conn_id, tGATT_IF *p_gatt_if, BD_ADDR bd_addr,
1535                                tBT_TRANSPORT *p_transport)
1536{
1537
1538    tGATT_IF        gatt_if = GATT_GET_GATT_IF(conn_id);
1539    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
1540    UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
1541    tGATT_TCB       *p_tcb= gatt_get_tcb_by_idx(tcb_idx);
1542    BOOLEAN         status=FALSE;
1543
1544    GATT_TRACE_API ("GATT_GetConnectionInfor conn_id=%d", conn_id);
1545
1546    if (p_tcb && p_reg )
1547    {
1548        memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN);
1549        *p_gatt_if = gatt_if;
1550        *p_transport = p_tcb->transport;
1551        status = TRUE;
1552    }
1553    return status;
1554}
1555
1556
1557/*******************************************************************************
1558**
1559** Function         GATT_GetConnIdIfConnected
1560**
1561** Description      This function find the conn_id if the logical link for BD address
1562**                  and applciation interface is connected
1563**
1564** Parameters        gatt_if: applicaiton interface (input)
1565**                   bd_addr: peer device address. (input)
1566**                   p_conn_id: connection id  (output)
1567**                   transport: transport option
1568**
1569** Returns          TRUE the logical link is connected
1570**
1571*******************************************************************************/
1572BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_conn_id,
1573                                  tBT_TRANSPORT transport)
1574{
1575    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
1576    tGATT_TCB       *p_tcb= gatt_find_tcb_by_addr(bd_addr, transport);
1577    BOOLEAN         status=FALSE;
1578
1579    if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) )
1580    {
1581        *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
1582        status = TRUE;
1583    }
1584
1585    GATT_TRACE_API ("GATT_GetConnIdIfConnected status=%d", status);
1586    return status;
1587}
1588
1589
1590/*******************************************************************************
1591**
1592** Function         GATT_Listen
1593**
1594** Description      This function start or stop LE advertisement and listen for
1595**                  connection.
1596**
1597** Parameters       gatt_if: applicaiton interface
1598**                  p_bd_addr: listen for specific address connection, or NULL for
1599**                             listen to all device connection.
1600**                  start: start or stop listening.
1601**
1602** Returns          TRUE if advertisement is started; FALSE if adv start failure.
1603**
1604*******************************************************************************/
1605BOOLEAN GATT_Listen (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr)
1606{
1607    tGATT_REG    *p_reg;
1608
1609    GATT_TRACE_API ("GATT_Listen gatt_if=%d", gatt_if);
1610
1611    /* Make sure app is registered */
1612    if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
1613    {
1614        GATT_TRACE_ERROR("GATT_Listen - gatt_if =%d is not registered", gatt_if);
1615        return(FALSE);
1616    }
1617
1618    if (bd_addr != NULL)
1619    {
1620        gatt_update_auto_connect_dev(gatt_if,start, bd_addr, FALSE);
1621    }
1622    else
1623    {
1624        p_reg->listening = start ? GATT_LISTEN_TO_ALL : GATT_LISTEN_TO_NONE;
1625    }
1626
1627    return gatt_update_listen_mode();
1628}
1629
1630#endif
1631
1632