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_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*******************************************************************************/
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_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*******************************************************************************/
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_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*******************************************************************************/
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_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*******************************************************************************/
393BOOLEAN 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*******************************************************************************/
463tGATT_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*******************************************************************************/
559void 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*******************************************************************************/
595tGATT_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*******************************************************************************/
666tGATT_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 *)&notif);
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*******************************************************************************/
712tGATT_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*******************************************************************************/
766tGATT_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*******************************************************************************/
816tGATT_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            return GATT_ILLEGAL_PARAMETER;
853        }
854
855        p_clcb->operation  = GATTC_OPTYPE_DISCOVERY;
856        p_clcb->op_subtype = disc_type;
857        p_clcb->s_handle   = p_param->s_handle;
858        p_clcb->e_handle   = p_param->e_handle;
859        p_clcb->uuid       = p_param->service;
860
861        gatt_act_discovery(p_clcb);
862    }
863    else
864    {
865        status = GATT_NO_RESOURCES;
866    }
867    return status;
868}
869
870/*******************************************************************************
871**
872** Function         GATTC_Read
873**
874** Description      This function is called to read the value of an attribute from
875**                  the server.
876**
877** Parameters       conn_id: connection identifier.
878**                  type    - attribute read type.
879**                  p_read  - read operation parameters.
880**
881** Returns          GATT_SUCCESS if command started successfully.
882**
883*******************************************************************************/
884tGATT_STATUS GATTC_Read (UINT16 conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read)
885{
886    tGATT_STATUS status = GATT_SUCCESS;
887    tGATT_CLCB          *p_clcb;
888    tGATT_READ_MULTI    *p_read_multi;
889    tGATT_IF            gatt_if=GATT_GET_GATT_IF(conn_id);
890    UINT8               tcb_idx = GATT_GET_TCB_IDX(conn_id);
891    tGATT_TCB           *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
892    tGATT_REG           *p_reg = gatt_get_regcb(gatt_if);
893
894
895    GATT_TRACE_API2 ("GATTC_Read conn_id=%d type=%d", conn_id, type);
896
897    if ( (p_tcb == NULL) || (p_reg==NULL) || (p_read == NULL) || ((type >= GATT_READ_MAX) || (type == 0)))
898    {
899        GATT_TRACE_ERROR2("GATT_Read Illegal param: conn_id %d, type 0%d,", conn_id, type);
900        return GATT_ILLEGAL_PARAMETER;
901    }
902
903    if (gatt_is_clcb_allocated(conn_id))
904    {
905        GATT_TRACE_ERROR1("GATTC_Read GATT_BUSY conn_id = %d", conn_id);
906        return GATT_BUSY;
907    }
908
909    if ( (p_clcb = gatt_clcb_alloc(conn_id)) != NULL  )
910    {
911        p_clcb->operation = GATTC_OPTYPE_READ;
912        p_clcb->op_subtype = type;
913        p_clcb->auth_req = p_read->by_handle.auth_req;
914        p_clcb->counter = 0;
915
916        switch (type)
917        {
918            case GATT_READ_BY_TYPE:
919            case GATT_READ_CHAR_VALUE:
920                p_clcb->s_handle = p_read->service.s_handle;
921                p_clcb->e_handle = p_read->service.e_handle;
922                memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID));
923                break;
924            case GATT_READ_MULTIPLE:
925                p_clcb->s_handle = 0;
926                /* copy multiple handles in CB */
927                p_read_multi = (tGATT_READ_MULTI *)GKI_getbuf(sizeof(tGATT_READ_MULTI));
928                p_clcb->p_attr_buf = (UINT8*)p_read_multi;
929                memcpy (p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI));
930            case GATT_READ_BY_HANDLE:
931            case GATT_READ_PARTIAL:
932                memset(&p_clcb->uuid, 0, sizeof(tBT_UUID));
933                p_clcb->s_handle = p_read->by_handle.handle;
934
935                if (type == GATT_READ_PARTIAL)
936                {
937                    p_clcb->counter = p_read->partial.offset;
938                }
939
940                break;
941            default:
942                break;
943        }
944        /* start security check */
945        if (gatt_security_check_start(p_clcb) == FALSE)
946        {
947            status = GATT_NO_RESOURCES;
948            gatt_clcb_dealloc(p_clcb);
949        }
950    }
951    else
952    {
953        status = GATT_NO_RESOURCES;
954    }
955    return status;
956}
957
958/*******************************************************************************
959**
960** Function         GATTC_Write
961**
962** Description      This function is called to write the value of an attribute to
963**                  the server.
964**
965** Parameters       conn_id: connection identifier.
966**                  type    - attribute write type.
967**                  p_write  - write operation parameters.
968**
969** Returns          GATT_SUCCESS if command started successfully.
970**
971*******************************************************************************/
972tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
973{
974    tGATT_STATUS status = GATT_SUCCESS;
975    tGATT_CLCB      *p_clcb;
976    tGATT_VALUE     *p;
977    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
978    UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
979    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
980    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
981
982    if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) ||
983         ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) )
984    {
985        GATT_TRACE_ERROR2("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type);
986        return GATT_ILLEGAL_PARAMETER;
987    }
988
989    if (gatt_is_clcb_allocated(conn_id))
990    {
991        GATT_TRACE_ERROR1("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
992        return GATT_BUSY;
993    }
994
995    if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
996    {
997        p_clcb->operation  = GATTC_OPTYPE_WRITE;
998        p_clcb->op_subtype = type;
999        p_clcb->auth_req = p_write->auth_req;
1000
1001        if (( p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL)
1002        {
1003            memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));
1004
1005            p =  (tGATT_VALUE *)p_clcb->p_attr_buf;
1006            if (type == GATT_WRITE_PREPARE)
1007            {
1008                p_clcb->start_offset = p_write->offset;
1009                p->offset = 0;
1010            }
1011
1012            if (gatt_security_check_start(p_clcb) == FALSE)
1013            {
1014                status = GATT_NO_RESOURCES;
1015            }
1016        }
1017        else
1018        {
1019            status = GATT_NO_RESOURCES;
1020        }
1021
1022        if (status == GATT_NO_RESOURCES)
1023            gatt_clcb_dealloc(p_clcb);
1024    }
1025    else
1026    {
1027        status = GATT_NO_RESOURCES;
1028    }
1029    return status;
1030}
1031
1032
1033/*******************************************************************************
1034**
1035** Function         GATTC_ExecuteWrite
1036**
1037** Description      This function is called to send an Execute write request to
1038**                  the server.
1039**
1040** Parameters       conn_id: connection identifier.
1041**                  is_execute - to execute or cancel the prepare write requet(s)
1042**
1043** Returns          GATT_SUCCESS if command started successfully.
1044**
1045*******************************************************************************/
1046tGATT_STATUS GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute)
1047{
1048    tGATT_STATUS status = GATT_SUCCESS;
1049    tGATT_CLCB      *p_clcb;
1050    tGATT_EXEC_FLAG flag;
1051    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
1052    UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
1053    tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1054    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
1055
1056    GATT_TRACE_API2 ("GATTC_ExecuteWrite conn_id=%d is_execute=%d", conn_id, is_execute);
1057
1058    if ( (p_tcb == NULL) || (p_reg==NULL) )
1059    {
1060        GATT_TRACE_ERROR1("GATTC_ExecuteWrite Illegal param: conn_id %d", conn_id);
1061        return GATT_ILLEGAL_PARAMETER;
1062    }
1063
1064    if (gatt_is_clcb_allocated(conn_id))
1065    {
1066        GATT_TRACE_ERROR1("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
1067        return GATT_BUSY;
1068    }
1069
1070    if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL)
1071    {
1072        p_clcb->operation  = GATTC_OPTYPE_EXE_WRITE;
1073        flag = is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL;
1074        gatt_send_queue_write_cancel (p_clcb->p_tcb, p_clcb, flag);
1075    }
1076    else
1077    {
1078        GATT_TRACE_ERROR1("Unable to allocate client CB for conn_id %d ", conn_id);
1079        status = GATT_NO_RESOURCES;
1080    }
1081    return status;
1082}
1083
1084/*******************************************************************************
1085**
1086** Function         GATTC_SendHandleValueConfirm
1087**
1088** Description      This function is called to send a handle value confirmation
1089**                  as response to a handle value notification from server.
1090**
1091** Parameters       conn_id: connection identifier.
1092**                  handle: the handle of the attribute confirmation.
1093**
1094** Returns          GATT_SUCCESS if command started successfully.
1095**
1096*******************************************************************************/
1097tGATT_STATUS GATTC_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle)
1098{
1099    tGATT_STATUS    ret = GATT_ILLEGAL_PARAMETER;
1100    tGATT_TCB     *p_tcb=gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id));
1101
1102    GATT_TRACE_API2 ("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id, handle);
1103
1104    if (p_tcb)
1105    {
1106        if (p_tcb->ind_count > 0 )
1107        {
1108            btu_stop_timer (&p_tcb->ind_ack_timer_ent);
1109
1110            GATT_TRACE_DEBUG1 ("notif_count=%d ", p_tcb->ind_count);
1111            /* send confirmation now */
1112            ret = attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, (tGATT_CL_MSG *)&handle);
1113
1114            p_tcb->ind_count = 0;
1115
1116        }
1117        else
1118        {
1119            GATT_TRACE_DEBUG1 ("GATTC_SendHandleValueConfirm - conn_id: %u - ignored not waiting for indicaiton ack", conn_id);
1120            ret = GATT_SUCCESS;
1121        }
1122    }
1123    else
1124    {
1125        GATT_TRACE_ERROR1 ("GATTC_SendHandleValueConfirm - Unknown conn_id: %u", conn_id);
1126    }
1127    return ret;
1128}
1129
1130
1131/*******************************************************************************/
1132/*                                                                             */
1133/*                   GATT  APIs                                                */
1134/*                                                                             */
1135/*******************************************************************************/
1136/*******************************************************************************
1137**
1138** Function         GATT_SetIdleTimeout
1139**
1140** Description      This function (common to both client and server) sets the idle
1141**                  timeout for a tansport connection
1142**
1143** Parameter        bd_addr:   target device bd address.
1144**                  idle_tout: timeout value in seconds.
1145**
1146** Returns          void
1147**
1148*******************************************************************************/
1149void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout)
1150{
1151    tGATT_TCB       *p_tcb;
1152    BOOLEAN         status = FALSE;
1153
1154    if ((p_tcb = gatt_find_tcb_by_addr (bd_addr)) != NULL)
1155    {
1156        if (p_tcb->att_lcid == L2CAP_ATT_CID)
1157        {
1158            status = L2CA_SetFixedChannelTout (bd_addr, L2CAP_ATT_CID, idle_tout);
1159        }
1160        else
1161        {
1162            status = L2CA_SetIdleTimeout (p_tcb->att_lcid, idle_tout, FALSE);
1163        }
1164    }
1165
1166    GATT_TRACE_API2 ("GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)",
1167                    idle_tout, status);
1168}
1169
1170
1171/*******************************************************************************
1172**
1173** Function         GATT_Register
1174**
1175** Description      This function is called to register an  application
1176**                  with GATT
1177**
1178** Parameter        p_app_uuid128: Application UUID
1179**                  p_cb_info: callback functions.
1180**
1181** Returns          0 for error, otherwise the index of the client registered with GATT
1182**
1183*******************************************************************************/
1184tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info)
1185{
1186    tGATT_REG    *p_reg;
1187    UINT8        i_gatt_if=0;
1188    tGATT_IF     gatt_if=0;
1189
1190    GATT_TRACE_API0 ("GATT_Register");
1191    gatt_dbg_display_uuid(*p_app_uuid128);
1192
1193    for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
1194    {
1195        if (p_reg->in_use  && !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128, LEN_UUID_128))
1196        {
1197            GATT_TRACE_ERROR0("application already registered.");
1198            return 0;
1199        }
1200    }
1201
1202    for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
1203    {
1204        if (!p_reg->in_use)
1205        {
1206            memset(p_reg, 0 , sizeof(tGATT_REG));
1207            i_gatt_if++;              /* one based number */
1208            p_reg->app_uuid128 =  *p_app_uuid128;
1209            gatt_if            =
1210            p_reg->gatt_if     = (tGATT_IF)i_gatt_if;
1211            p_reg->app_cb      = *p_cb_info;
1212            p_reg->in_use      = TRUE;
1213
1214            break;
1215        }
1216    }
1217    GATT_TRACE_API1 ("allocated gatt_if=%d", gatt_if);
1218    return gatt_if;
1219}
1220
1221
1222/*******************************************************************************
1223**
1224** Function         GATT_Deregister
1225**
1226** Description      This function deregistered the application from GATT.
1227**
1228** Parameters       gatt_if: applicaiton interface.
1229**
1230** Returns          None.
1231**
1232*******************************************************************************/
1233void GATT_Deregister (tGATT_IF gatt_if)
1234{
1235    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
1236    tGATT_TCB       *p_tcb;
1237    tGATT_CLCB       *p_clcb;
1238    UINT8           i, ii, j;
1239    tGATT_SR_REG    *p_sreg;
1240
1241    GATT_TRACE_API1 ("GATT_Deregister gatt_if=%d", gatt_if);
1242    /* Index 0 is GAP and is never deregistered */
1243    if ( (gatt_if == 0) || (p_reg == NULL) )
1244    {
1245        GATT_TRACE_ERROR1 ("GATT_Deregister with invalid gatt_if: %u", gatt_if);
1246        return;
1247    }
1248
1249    /* stop all services  */
1250    /* todo an applcaiton can not be deregistered if its services is also used by other application
1251      deregisteration need to bed performed in an orderly fashion
1252      no check for now */
1253
1254    for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++)
1255    {
1256        if (p_sreg->in_use && (p_sreg->gatt_if == gatt_if))
1257        {
1258            GATTS_StopService(p_sreg->s_hdl);
1259        }
1260    }
1261
1262    /* free all services db buffers if owned by this application */
1263    gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128);
1264
1265    /* When an application deregisters, check remove the link associated with the app */
1266
1267    for (i=0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++)
1268    {
1269        if (p_tcb->in_use)
1270        {
1271            if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE)
1272            {
1273                gatt_update_app_use_link_flag(gatt_if, p_tcb,  FALSE, FALSE);
1274                if (!gatt_num_apps_hold_link(p_tcb))
1275                {
1276                    /* this will disconnect the link or cancel the pending connect request at lower layer*/
1277                    gatt_disconnect(p_tcb->peer_bda);
1278                }
1279            }
1280
1281            for (j = 0, p_clcb= &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++)
1282            {
1283                if (p_clcb->in_use &&
1284                    (p_clcb->p_reg->gatt_if == gatt_if) &&
1285                    (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx))
1286                {
1287                    gatt_clcb_dealloc (p_clcb);
1288                    break;
1289                }
1290            }
1291        }
1292    }
1293
1294    gatt_deregister_bgdev_list(gatt_if);
1295    memset (p_reg, 0, sizeof(tGATT_REG));
1296}
1297
1298
1299/*******************************************************************************
1300**
1301** Function         GATT_StartIf
1302**
1303** Description      This function is called after registration to start receiving
1304**                  callbacks for registered interface.  Function may call back
1305**                  with connection status and queued notifications
1306**
1307** Parameter        gatt_if: applicaiton interface.
1308**
1309** Returns          0 for error, otherwise the index of the client registered with GATT
1310**
1311*******************************************************************************/
1312void GATT_StartIf (tGATT_IF gatt_if)
1313{
1314    tGATT_REG   *p_reg;
1315    tGATT_TCB   *p_tcb;
1316    //tGATT_CLCB   *p_clcb;
1317    BD_ADDR     bda;
1318    UINT8       start_idx, found_idx;
1319    UINT16      conn_id;
1320
1321    GATT_TRACE_API1 ("GATT_StartIf gatt_if=%d", gatt_if);
1322    if ((p_reg = gatt_get_regcb(gatt_if)) != NULL)
1323    {
1324        p_reg = &gatt_cb.cl_rcb[gatt_if - 1];
1325        start_idx = 0;
1326        while (gatt_find_the_connected_bda(start_idx, bda, &found_idx))
1327        {
1328            p_tcb = gatt_find_tcb_by_addr(bda);
1329            if (p_reg->app_cb.p_conn_cb)
1330            {
1331                conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
1332                (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0);
1333            }
1334            start_idx = ++found_idx;
1335        }
1336    }
1337}
1338
1339
1340/*******************************************************************************
1341**
1342** Function         GATT_Connect
1343**
1344** Description      This function initiate a connecttion to a ATT server.
1345**
1346** Parameters       gatt_if: applicaiton interface
1347**                  bd_addr: peer device address.
1348**                  is_direct: is a direct conenection or a background auto connection
1349**
1350** Returns          TRUE if connection started; FALSE if connection start failure.
1351**
1352*******************************************************************************/
1353BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){
1354    tGATT_REG    *p_reg;
1355    BOOLEAN status;
1356
1357    GATT_TRACE_API1 ("GATT_Connect gatt_if=%d", gatt_if);
1358
1359    /* Make sure app is registered */
1360    if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
1361    {
1362        GATT_TRACE_ERROR1("GATT_Connect - gatt_if =%d is not registered", gatt_if);
1363        return(FALSE);
1364    }
1365
1366    if (is_direct)
1367        status = gatt_act_connect (p_reg, bd_addr);
1368    else
1369        status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr);
1370
1371    return status;
1372
1373}
1374
1375/*******************************************************************************
1376**
1377** Function         GATT_CancelConnect
1378**
1379** Description      This function initiate a connecttion to a ATT server.
1380**
1381** Parameters       gatt_if: client interface. If 0 used as unconditionally disconnect,
1382**                          typically used for direct connection cancellation.
1383**                  bd_addr: peer device address.
1384**
1385** Returns          TRUE if connection started; FALSE if connection start failure.
1386**
1387*******************************************************************************/
1388BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){
1389    tGATT_REG     *p_reg;
1390    tGATT_TCB     *p_tcb;
1391    BOOLEAN       status = TRUE;
1392    tGATT_IF      temp_gatt_if;
1393    UINT8         start_idx, found_idx;
1394
1395    GATT_TRACE_API1 ("GATT_CancelConnect gatt_if=%d", gatt_if);
1396
1397    if ((gatt_if != 0) && ((p_reg = gatt_get_regcb(gatt_if)) == NULL))
1398    {
1399        GATT_TRACE_ERROR1("GATT_CancelConnect - gatt_if =%d is not registered", gatt_if);
1400        return(FALSE);
1401    }
1402
1403    if (is_direct)
1404    {
1405        if (!gatt_if)
1406        {
1407            GATT_TRACE_DEBUG0("GATT_CancelConnect - unconditional");
1408            start_idx = 0;
1409            p_tcb = gatt_find_tcb_by_addr(bd_addr);
1410            if (p_tcb && gatt_num_apps_hold_link(p_tcb))
1411            {
1412                while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx, &temp_gatt_if))
1413                {
1414                    status = gatt_cancel_open(temp_gatt_if, bd_addr);
1415                    start_idx = ++found_idx;
1416                }
1417            }
1418            else
1419            {
1420                GATT_TRACE_ERROR0("GATT_CancelConnect - no app found");
1421                status = FALSE;
1422            }
1423        }
1424        else
1425        {
1426            status = gatt_cancel_open(gatt_if, bd_addr);
1427        }
1428    }
1429    else
1430    {
1431        if (!gatt_if)
1432        {
1433            if (gatt_get_num_apps_for_bg_dev(bd_addr))
1434            {
1435                while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if))
1436                    gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr);
1437            }
1438            else
1439            {
1440                GATT_TRACE_ERROR0("GATT_CancelConnect -no app associated with the bg device for unconditional removal");
1441                status = FALSE;
1442            }
1443        }
1444        else
1445        {
1446            status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
1447        }
1448    }
1449
1450    return status;
1451}
1452
1453/*******************************************************************************
1454**
1455** Function         GATT_Disconnect
1456**
1457** Description      This function disconnect a logic channel.
1458**
1459** Parameters       conn_id: connection identifier.
1460**
1461** Returns          GATT_SUCCESS if disconnected.
1462**
1463*******************************************************************************/
1464tGATT_STATUS GATT_Disconnect (UINT16 conn_id)
1465{
1466    tGATT_STATUS    ret = GATT_ILLEGAL_PARAMETER;
1467    tGATT_TCB       *p_tcb=NULL;
1468    tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
1469    UINT8          tcb_idx = GATT_GET_TCB_IDX(conn_id);
1470
1471    GATT_TRACE_API1 ("GATT_Disconnect conn_id=%d ", conn_id);
1472
1473    p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1474
1475    if (p_tcb)
1476    {
1477        gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE);
1478        if (!gatt_num_apps_hold_link(p_tcb))
1479        {
1480            gatt_disconnect(p_tcb->peer_bda);
1481        }
1482        ret = GATT_SUCCESS;
1483    }
1484    return ret;
1485}
1486
1487
1488/*******************************************************************************
1489**
1490** Function         GATT_GetConnectionInfor
1491**
1492** Description      This function use conn_id to find its associated BD address and applciation
1493**                  interface
1494**
1495** Parameters        conn_id: connection id  (input)
1496**                   p_gatt_if: applicaiton interface (output)
1497**                   bd_addr: peer device address. (output)
1498**
1499** Returns          TRUE the ligical link information is found for conn_id
1500**
1501*******************************************************************************/
1502BOOLEAN GATT_GetConnectionInfor(UINT16 conn_id, tGATT_IF *p_gatt_if, BD_ADDR bd_addr)
1503{
1504
1505    tGATT_IF        gatt_if = GATT_GET_GATT_IF(conn_id);
1506    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
1507    UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
1508    tGATT_TCB       *p_tcb= gatt_get_tcb_by_idx(tcb_idx);
1509    BOOLEAN         status=FALSE;
1510
1511    GATT_TRACE_API1 ("GATT_GetConnectionInfor conn_id=%d", conn_id);
1512
1513    if (p_tcb && p_reg )
1514    {
1515        memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN);
1516        *p_gatt_if = gatt_if;
1517        status = TRUE;
1518    }
1519    return status;
1520}
1521
1522
1523/*******************************************************************************
1524**
1525** Function         GATT_GetConnIdIfConnected
1526**
1527** Description      This function find the conn_id if the logical link for BD address
1528**                  and applciation interface is connected
1529**
1530** Parameters        gatt_if: applicaiton interface (input)
1531**                   bd_addr: peer device address. (input)
1532**                   p_conn_id: connection id  (output)
1533**
1534** Returns          TRUE the ligical link is connected
1535**
1536*******************************************************************************/
1537BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_conn_id)
1538{
1539    tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
1540    tGATT_TCB       *p_tcb= gatt_find_tcb_by_addr(bd_addr);
1541    BOOLEAN         status=FALSE;
1542
1543    if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) )
1544    {
1545        *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
1546        status = TRUE;
1547    }
1548
1549    GATT_TRACE_API1 ("GATT_GetConnIdIfConnected status=%d", status);
1550    return status;
1551}
1552
1553#endif
1554
1555
1556