OSDN Git Service

am 51d14a76: am 89ba148d: Disable opening network debug ports for security reasons
[android-x86/system-bt.git] / stack / gatt / gatt_api.c
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 "bt_common.h"
30 #include <stdio.h>
31 #include <string.h>
32 #include "gatt_api.h"
33 #include "gatt_int.h"
34 #include "l2c_api.h"
35 #include "btm_int.h"
36
37
38 /*******************************************************************************
39 **
40 ** Function         GATT_SetTraceLevel
41 **
42 ** Description      This function sets the trace level.  If called with
43 **                  a value of 0xFF, it simply returns the current trace level.
44 **
45 **                  Input Parameters:
46 **                      level:  The level to set the GATT tracing to:
47 **                      0xff-returns the current setting.
48 **                      0-turns off tracing.
49 **                      >= 1-Errors.
50 **                      >= 2-Warnings.
51 **                      >= 3-APIs.
52 **                      >= 4-Events.
53 **                      >= 5-Debug.
54 **
55 ** Returns          The new or current trace level
56 **
57 *******************************************************************************/
58 UINT8 GATT_SetTraceLevel (UINT8 new_level)
59 {
60     if (new_level != 0xFF)
61         gatt_cb.trace_level = new_level;
62
63     return(gatt_cb.trace_level);
64 }
65
66 /*****************************************************************************
67 **
68 **                  GATT SERVER API
69 **
70 ******************************************************************************/
71 /*******************************************************************************
72 **
73 ** Function         GATTS_AddHandleRange
74 **
75 ** Description      This function add the allocated handles range for the specifed
76 **                  application UUID, service UUID and service instance
77 **
78 ** Parameter        p_hndl_range:   pointer to allocated handles information
79 **
80 ** Returns          TRUE if handle range is added sucessfully; otherwise FALSE.
81 **
82 *******************************************************************************/
83
84 BOOLEAN GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range)
85 {
86     tGATT_HDL_LIST_ELEM *p_buf;
87     BOOLEAN status= FALSE;
88
89     if ((p_buf = gatt_alloc_hdl_buffer()) != NULL)
90     {
91         p_buf->asgn_range = *p_hndl_range;
92         status  = gatt_add_an_item_to_list(&gatt_cb.hdl_list_info, p_buf);
93     }
94     return status;
95 }
96
97
98 /*******************************************************************************
99 **
100 ** Function         GATTS_NVRegister
101 **
102 ** Description      Application manager calls this function to register for
103 **                  NV save callback function.  There can be one and only one
104 **                  NV save callback function.
105 **
106 ** Parameter        p_cb_info : callback informaiton
107 **
108 ** Returns          TRUE if registered OK, else FALSE
109 **
110 *******************************************************************************/
111 BOOLEAN  GATTS_NVRegister (tGATT_APPL_INFO *p_cb_info)
112 {
113     BOOLEAN status= FALSE;
114     if (p_cb_info)
115     {
116         gatt_cb.cb_info = *p_cb_info;
117         status = TRUE;
118         gatt_init_srv_chg();
119     }
120
121     return status;
122 }
123
124 /*******************************************************************************
125 **
126 ** Function         GATTS_CreateService
127 **
128 ** Description      This function is called to reserve a block of handles for a service.
129 **
130 **                  *** It should be called only once per service instance  ***
131 **
132 ** Parameter        gatt_if       : application if
133 **                  p_svc_uuid    : service UUID
134 **                  svc_inst      : instance of the service inside the application
135 **                  num_handles   : number of handles needed by the service.
136 **                  is_pri        : is a primary service or not.
137 **
138 ** Returns          service handle if sucessful, otherwise 0.
139 **
140 *******************************************************************************/
141 UINT16 GATTS_CreateService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid,
142                             UINT16 svc_inst, UINT16 num_handles, BOOLEAN is_pri)
143 {
144
145     tGATT_HDL_LIST_INFO     *p_list_info= &gatt_cb.hdl_list_info;
146     tGATT_HDL_LIST_ELEM     *p_list=NULL;
147     UINT16                  s_hdl=0;
148     BOOLEAN                 save_hdl=FALSE;
149     tGATTS_PENDING_NEW_SRV_START      *p_buf=NULL;
150     tGATT_REG              *p_reg = gatt_get_regcb(gatt_if);
151     tBT_UUID     *p_app_uuid128;
152
153
154     GATT_TRACE_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             osi_freebuf(fixed_queue_try_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 *******************************************************************************/
277 UINT16 GATTS_AddIncludeService (UINT16 service_handle, UINT16 include_svc_handle)
278
279 {
280     tGATT_HDL_LIST_ELEM  *p_decl, *p_incl_decl;
281
282     if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
283     {
284         GATT_TRACE_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 *******************************************************************************/
315 UINT16 GATTS_AddCharacteristic (UINT16 service_handle, tBT_UUID *p_char_uuid,
316                                 tGATT_PERM perm,tGATT_CHAR_PROP property)
317 {
318     tGATT_HDL_LIST_ELEM  *p_decl;
319
320     if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
321     {
322         GATT_TRACE_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 *******************************************************************************/
357 UINT16 GATTS_AddCharDescriptor (UINT16 service_handle,
358                                  tGATT_PERM perm,
359                                  tBT_UUID  * p_descr_uuid)
360 {
361     tGATT_HDL_LIST_ELEM  *p_decl;
362
363     if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
364     {
365         GATT_TRACE_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 *******************************************************************************/
394 BOOLEAN 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         osi_freebuf(fixed_queue_try_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 *******************************************************************************/
464 tGATT_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         osi_freebuf(fixed_queue_try_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 *******************************************************************************/
560 void 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 *******************************************************************************/
596 tGATT_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 *******************************************************************************/
668 tGATT_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 *******************************************************************************/
719 tGATT_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 *******************************************************************************/
773 tGATT_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 *******************************************************************************/
826 tGATT_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 *******************************************************************************/
895 tGATT_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 *)osi_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 *******************************************************************************/
983 tGATT_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 *)osi_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 *******************************************************************************/
1057 tGATT_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 *******************************************************************************/
1108 tGATT_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 *******************************************************************************/
1160 void 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 *******************************************************************************/
1199 tGATT_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 *******************************************************************************/
1248 void 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 *******************************************************************************/
1333 void 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 *******************************************************************************/
1374 BOOLEAN 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 *******************************************************************************/
1418 BOOLEAN 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 *******************************************************************************/
1496 tGATT_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 *******************************************************************************/
1534 BOOLEAN 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 *******************************************************************************/
1572 BOOLEAN 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 *******************************************************************************/
1605 BOOLEAN 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