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 ** Function         GATT_SetTraceLevel
40 **
41 ** Description      This function sets the trace level.  If called with
42 **                  a value of 0xFF, it simply returns the current trace level.
43 **
44 **                  Input Parameters:
45 **                      level:  The level to set the GATT tracing to:
46 **                      0xff-returns the current setting.
47 **                      0-turns off tracing.
48 **                      >= 1-Errors.
49 **                      >= 2-Warnings.
50 **                      >= 3-APIs.
51 **                      >= 4-Events.
52 **                      >= 5-Debug.
53 **
54 ** Returns          The new or current trace level
55 **
56 *******************************************************************************/
GATT_SetTraceLevel(UINT8 new_level)57 UINT8 GATT_SetTraceLevel (UINT8 new_level)
58 {
59     if (new_level != 0xFF)
60         gatt_cb.trace_level = new_level;
61 
62     return(gatt_cb.trace_level);
63 }
64 
65 /*****************************************************************************
66 **
67 **                  GATT SERVER API
68 **
69 ******************************************************************************/
70 /*******************************************************************************
71 **
72 ** Function         GATTS_AddHandleRange
73 **
74 ** Description      This function add the allocated handles range for the specifed
75 **                  application UUID, service UUID and service instance
76 **
77 ** Parameter        p_hndl_range:   pointer to allocated handles information
78 **
79 ** Returns          TRUE if handle range is added sucessfully; otherwise FALSE.
80 **
81 *******************************************************************************/
82 
GATTS_AddHandleRange(tGATTS_HNDL_RANGE * p_hndl_range)83 BOOLEAN GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range)
84 {
85     tGATT_HDL_LIST_ELEM *p_buf;
86     BOOLEAN status= FALSE;
87 
88     if ((p_buf = gatt_alloc_hdl_buffer()) != NULL)
89     {
90         p_buf->asgn_range = *p_hndl_range;
91         status  = gatt_add_an_item_to_list(&gatt_cb.hdl_list_info, p_buf);
92     }
93     return status;
94 }
95 
96 
97 /*******************************************************************************
98 **
99 ** Function         GATTS_NVRegister
100 **
101 ** Description      Application manager calls this function to register for
102 **                  NV save callback function.  There can be one and only one
103 **                  NV save callback function.
104 **
105 ** Parameter        p_cb_info : callback informaiton
106 **
107 ** Returns          TRUE if registered OK, else FALSE
108 **
109 *******************************************************************************/
GATTS_NVRegister(tGATT_APPL_INFO * p_cb_info)110 BOOLEAN  GATTS_NVRegister (tGATT_APPL_INFO *p_cb_info)
111 {
112     BOOLEAN status= FALSE;
113     if (p_cb_info)
114     {
115         gatt_cb.cb_info = *p_cb_info;
116         status = TRUE;
117         gatt_init_srv_chg();
118     }
119 
120     return status;
121 }
122 
123 /*******************************************************************************
124 **
125 ** Function         GATTS_CreateService
126 **
127 ** Description      This function is called to reserve a block of handles for a service.
128 **
129 **                  *** It should be called only once per service instance  ***
130 **
131 ** Parameter        gatt_if       : application if
132 **                  p_svc_uuid    : service UUID
133 **                  svc_inst      : instance of the service inside the application
134 **                  num_handles   : number of handles needed by the service.
135 **                  is_pri        : is a primary service or not.
136 **
137 ** Returns          service handle if sucessful, otherwise 0.
138 **
139 *******************************************************************************/
GATTS_CreateService(tGATT_IF gatt_if,tBT_UUID * p_svc_uuid,UINT16 svc_inst,UINT16 num_handles,BOOLEAN is_pri)140 UINT16 GATTS_CreateService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid,
141                             UINT16 svc_inst, UINT16 num_handles, BOOLEAN is_pri)
142 {
143 
144     tGATT_HDL_LIST_INFO     *p_list_info= &gatt_cb.hdl_list_info;
145     tGATT_HDL_LIST_ELEM     *p_list=NULL;
146     UINT16                  s_hdl=0;
147     BOOLEAN                 save_hdl=FALSE;
148     tGATTS_PENDING_NEW_SRV_START      *p_buf=NULL;
149     tGATT_REG              *p_reg = gatt_get_regcb(gatt_if);
150     tBT_UUID     *p_app_uuid128;
151 
152 
153     GATT_TRACE_API ("GATTS_CreateService" );
154 
155     if (p_reg == NULL)
156     {
157         GATT_TRACE_ERROR ("Inavlid gatt_if=%d", gatt_if);
158         return(0);
159     }
160 
161     p_app_uuid128 = &p_reg->app_uuid128;
162 
163     if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) != NULL)
164     {
165         s_hdl = p_list->asgn_range.s_handle;
166         GATT_TRACE_DEBUG ("Service already been created!!");
167     }
168     else
169     {
170         if ( (p_svc_uuid->len == LEN_UUID_16) && (p_svc_uuid->uu.uuid16 == UUID_SERVCLASS_GATT_SERVER))
171         {
172             s_hdl=  gatt_cb.hdl_cfg.gatt_start_hdl;
173         }
174         else if ((p_svc_uuid->len == LEN_UUID_16) && (p_svc_uuid->uu.uuid16 == UUID_SERVCLASS_GAP_SERVER))
175         {
176             s_hdl= gatt_cb.hdl_cfg.gap_start_hdl;
177         }
178         else
179         {
180             p_list = p_list_info->p_first;
181 
182             if (p_list)
183             {
184                 s_hdl = p_list->asgn_range.e_handle + 1;
185             }
186 
187             if (s_hdl < gatt_cb.hdl_cfg.app_start_hdl)
188             {
189 
190                 s_hdl= gatt_cb.hdl_cfg.app_start_hdl;
191             }
192             save_hdl = TRUE;
193         }
194 
195         /* check for space */
196         if (num_handles > (0xFFFF - s_hdl + 1))
197         {
198             GATT_TRACE_ERROR ("GATTS_ReserveHandles: no handles, s_hdl: %u  needed: %u", s_hdl, num_handles);
199             return(0);
200         }
201 
202         if ( (p_list = gatt_alloc_hdl_buffer()) == NULL)
203         {
204             /* No free entry */
205             GATT_TRACE_ERROR ("GATTS_ReserveHandles: no free handle blocks");
206             return(0);
207         }
208 
209         p_list->asgn_range.app_uuid128 = *p_app_uuid128;
210         p_list->asgn_range.svc_uuid    = *p_svc_uuid;
211         p_list->asgn_range.svc_inst    = svc_inst;
212         p_list->asgn_range.s_handle    = s_hdl;
213         p_list->asgn_range.e_handle    = s_hdl+num_handles-1;
214         p_list->asgn_range.is_primary  = is_pri;
215 
216         gatt_add_an_item_to_list(p_list_info, p_list);
217 
218         if (save_hdl)
219         {
220             if (gatt_cb.cb_info.p_nv_save_callback)
221                 (*gatt_cb.cb_info.p_nv_save_callback)(TRUE, &p_list->asgn_range);
222             /* add a pending new  service change item to the list */
223             if ( (p_buf = gatt_add_pending_new_srv_start(&p_list->asgn_range)) == NULL)
224             {
225                 /* No free entry */
226                 GATT_TRACE_ERROR ("gatt_add_pending_new_srv_start: no free blocks");
227 
228                 if (p_list)
229                 {
230                     gatt_remove_an_item_from_list(p_list_info, p_list);
231                     gatt_free_hdl_buffer(p_list);
232                 }
233                 return(0);
234             }
235 
236             GATT_TRACE_DEBUG ("Add a new srv chg item");
237         }
238     }
239 
240     if (!gatts_init_service_db(&p_list->svc_db, p_svc_uuid, is_pri, s_hdl , num_handles))
241     {
242         GATT_TRACE_ERROR ("GATTS_ReserveHandles: service DB initialization failed");
243         if (p_list)
244         {
245             gatt_remove_an_item_from_list(p_list_info, p_list);
246             gatt_free_hdl_buffer(p_list);
247         }
248 
249         if (p_buf)
250             osi_free(fixed_queue_try_remove_from_queue(gatt_cb.pending_new_srv_start_q, p_buf));
251         return(0);
252     }
253 
254     GATT_TRACE_DEBUG ("GATTS_CreateService(success): handles needed:%u s_hdl=%u e_hdl=%u %s[%x] is_primary=%d",
255                        num_handles, p_list->asgn_range.s_handle , p_list->asgn_range.e_handle,
256                        ((p_list->asgn_range.svc_uuid.len == 2) ? "uuid16": "uuid128" ),
257                        p_list->asgn_range.svc_uuid.uu.uuid16,
258                        p_list->asgn_range.is_primary);
259 
260     return(s_hdl);
261 }
262 
263 /*******************************************************************************
264 **
265 ** Function         GATTS_AddIncludeService
266 **
267 ** Description      This function is called to add an included service.
268 **
269 ** Parameter        service_handle : To which service this included service is added to.
270 **                  include_svc_handle    : included service handle.
271 **
272 ** Returns          included service attribute handle. If 0, add included service
273 **                  fail.
274 **
275 *******************************************************************************/
GATTS_AddIncludeService(UINT16 service_handle,UINT16 include_svc_handle)276 UINT16 GATTS_AddIncludeService (UINT16 service_handle, UINT16 include_svc_handle)
277 
278 {
279     tGATT_HDL_LIST_ELEM  *p_decl, *p_incl_decl;
280 
281     if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
282     {
283         GATT_TRACE_DEBUG("Service not created");
284         return 0;
285     }
286     if ((p_incl_decl = gatt_find_hdl_buffer_by_handle(include_svc_handle)) == NULL)
287     {
288         GATT_TRACE_DEBUG("Included Service not created");
289         return 0;
290     }
291 
292     return gatts_add_included_service(&p_decl->svc_db,
293                                       p_incl_decl->asgn_range.s_handle,
294                                       p_incl_decl->asgn_range.e_handle,
295                                       p_incl_decl->asgn_range.svc_uuid);
296 }
297 /*******************************************************************************
298 **
299 ** Function         GATTS_AddCharacteristic
300 **
301 ** Description      This function is called to add a characteristic into a service.
302 **                  It will add a characteristic declaration and characteristic
303 **                  value declaration into the service database identified by the
304 **                  service handle.
305 **
306 ** Parameter        service_handle : To which service this included service is added to.
307 **                  char_uuid : Characteristic UUID.
308 **                  perm      : Characteristic value declaration attribute permission.
309 **                  property  : Characteristic Properties
310 **
311 ** Returns          Characteristic value declaration attribute handle. 0 if failed.
312 **
313 *******************************************************************************/
GATTS_AddCharacteristic(UINT16 service_handle,tBT_UUID * p_char_uuid,tGATT_PERM perm,tGATT_CHAR_PROP property)314 UINT16 GATTS_AddCharacteristic (UINT16 service_handle, tBT_UUID *p_char_uuid,
315                                 tGATT_PERM perm,tGATT_CHAR_PROP property)
316 {
317     tGATT_HDL_LIST_ELEM  *p_decl;
318 
319     if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
320     {
321         GATT_TRACE_DEBUG("Service not created");
322         return 0;
323     }
324     /* data validity checking */
325     if (  ((property & GATT_CHAR_PROP_BIT_AUTH) && !(perm & GATT_WRITE_SIGNED_PERM)) ||
326           ((perm & GATT_WRITE_SIGNED_PERM) && !(property & GATT_CHAR_PROP_BIT_AUTH)) )
327     {
328         GATT_TRACE_DEBUG("Invalid configuration property=0x%x perm=0x%x ", property, perm);
329         return 0;
330     }
331 
332     return gatts_add_characteristic(&p_decl->svc_db,
333                                     perm,
334                                     property,
335                                     p_char_uuid);
336 }
337 /*******************************************************************************
338 **
339 ** Function         GATTS_AddCharDescriptor
340 **
341 ** Description      This function is called to add a characteristic descriptor
342 **                  into a service database. Add descriptor should follow add char
343 **                  to which it belongs, and next add char should be done only
344 **                  after all add descriptors for the previous char.
345 **
346 ** Parameter        service_handle  : To which service this characteristic descriptor
347 **                                    is added to.
348 **                  perm            : Characteristic value declaration attribute
349 **                                    permission.
350 **                  p_descr_uuid    : Characteristic descriptor UUID
351 **
352 ** Returns         Characteristic descriptor attribute handle. 0 if add
353 **                 characteristic descriptor failed.
354 **
355 *******************************************************************************/
GATTS_AddCharDescriptor(UINT16 service_handle,tGATT_PERM perm,tBT_UUID * p_descr_uuid)356 UINT16 GATTS_AddCharDescriptor (UINT16 service_handle,
357                                  tGATT_PERM perm,
358                                  tBT_UUID  * p_descr_uuid)
359 {
360     tGATT_HDL_LIST_ELEM  *p_decl;
361 
362     if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
363     {
364         GATT_TRACE_DEBUG("Service not created");
365         return 0;
366     }
367     if (p_descr_uuid == NULL ||
368         (p_descr_uuid->len != LEN_UUID_128 && p_descr_uuid->len !=  LEN_UUID_16
369          && p_descr_uuid->len !=  LEN_UUID_32))
370     {
371         GATT_TRACE_DEBUG("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 *******************************************************************************/
GATTS_DeleteService(tGATT_IF gatt_if,tBT_UUID * p_svc_uuid,UINT16 svc_inst)393 BOOLEAN GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, UINT16 svc_inst)
394 {
395 
396     tGATT_HDL_LIST_INFO             *p_list_info= &gatt_cb.hdl_list_info;
397     tGATT_HDL_LIST_ELEM             *p_list=NULL;
398     UINT8                           i_sreg;
399     tGATTS_PENDING_NEW_SRV_START    *p_buf;
400     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
401     tBT_UUID *p_app_uuid128;
402 
403     GATT_TRACE_DEBUG ("GATTS_DeleteService");
404 
405     if (p_reg == NULL)
406     {
407         GATT_TRACE_ERROR ("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_ERROR ("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_DEBUG ("Delete a new service changed item - the service has not yet started");
423         osi_free(fixed_queue_try_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_DEBUG ("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 *******************************************************************************/
GATTS_StartService(tGATT_IF gatt_if,UINT16 service_handle,tGATT_TRANSPORT sup_transport)463 tGATT_STATUS GATTS_StartService (tGATT_IF gatt_if, UINT16 service_handle,
464                                  tGATT_TRANSPORT sup_transport)
465 {
466     tGATT_SR_REG            *p_sreg;
467     tGATT_HDL_LIST_ELEM      *p_list=NULL;
468     UINT8                    i_sreg;
469     tBT_UUID                *p_uuid;
470     tGATT_REG              *p_reg = gatt_get_regcb(gatt_if);
471 
472     tGATTS_PENDING_NEW_SRV_START *p_buf;
473 
474     GATT_TRACE_API ("GATTS_StartService");
475 
476     if (p_reg == NULL)
477     {
478         /* Not found  */
479         GATT_TRACE_ERROR ("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_ERROR ("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_ERROR ("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_ERROR ("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_DEBUG ("allocated i_sreg=%d ",i_sreg);
529 
530     GATT_TRACE_DEBUG ("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         osi_free(fixed_queue_try_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 *******************************************************************************/
GATTS_StopService(UINT16 service_handle)559 void GATTS_StopService (UINT16 service_handle)
560 {
561     UINT8           ii = gatt_sr_find_i_rcb_by_handle(service_handle);
562 
563     GATT_TRACE_API("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_ERROR("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 *******************************************************************************/
GATTS_HandleValueIndication(UINT16 conn_id,UINT16 attr_handle,UINT16 val_len,UINT8 * p_val)595 tGATT_STATUS GATTS_HandleValueIndication (UINT16 conn_id,  UINT16 attr_handle, UINT16 val_len, UINT8 *p_val)
596 {
597     tGATT_STATUS    cmd_status = GATT_NO_RESOURCES;
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_API ("GATTS_HandleValueIndication");
609     if ( (p_reg == NULL) || (p_tcb == NULL))
610     {
611         GATT_TRACE_ERROR ("GATTS_HandleValueIndication Unknown  conn_id: %u ", conn_id);
612         return(tGATT_STATUS) GATT_INVALID_CONN_ID;
613     }
614 
615     if (! GATT_HANDLE_IS_VALID (attr_handle))
616         return GATT_ILLEGAL_PARAMETER;
617 
618     indication.conn_id  = conn_id;
619     indication.handle   = attr_handle;
620     indication.len      = val_len;
621     memcpy (indication.value, p_val, val_len);
622     indication.auth_req = GATT_AUTH_REQ_NONE;
623 
624     if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle))
625     {
626         GATT_TRACE_DEBUG ("Add a pending indication");
627         if ((p_buf = gatt_add_pending_ind(p_tcb, &indication)) !=NULL)
628         {
629             cmd_status = GATT_SUCCESS;
630         }
631         else
632         {
633             cmd_status = GATT_NO_RESOURCES;
634         }
635     }
636     else
637     {
638 
639         if ( (p_msg = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_IND, (tGATT_SR_MSG *)&indication)) != NULL)
640         {
641             cmd_status = attp_send_sr_msg (p_tcb, p_msg);
642 
643             if (cmd_status == GATT_SUCCESS || cmd_status == GATT_CONGESTED)
644             {
645                 p_tcb->indicate_handle = indication.handle;
646                 gatt_start_conf_timer(p_tcb);
647             }
648         }
649     }
650     return cmd_status;
651 }
652 
653 /*******************************************************************************
654 **
655 ** Function         GATTS_HandleValueNotification
656 **
657 ** Description      This function sends a handle value notification to a client.
658 **
659 ** Parameter        conn_id: connection identifier.
660 **                  attr_handle: Attribute handle of this handle value indication.
661 **                  val_len: Length of the indicated attribute value.
662 **                  p_val: Pointer to the indicated attribute value data.
663 **
664 ** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
665 **
666 *******************************************************************************/
GATTS_HandleValueNotification(UINT16 conn_id,UINT16 attr_handle,UINT16 val_len,UINT8 * p_val)667 tGATT_STATUS GATTS_HandleValueNotification (UINT16 conn_id, UINT16 attr_handle,
668                                             UINT16 val_len, UINT8 *p_val)
669 {
670     tGATT_STATUS    cmd_sent = GATT_ILLEGAL_PARAMETER;
671     BT_HDR          *p_buf;
672     tGATT_VALUE     notif;
673     tGATT_IF         gatt_if = GATT_GET_GATT_IF(conn_id);
674     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
675     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
676     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
677 
678     GATT_TRACE_API ("GATTS_HandleValueNotification");
679 
680     if ( (p_reg == NULL) || (p_tcb == NULL))
681     {
682         GATT_TRACE_ERROR ("GATTS_HandleValueNotification Unknown  conn_id: %u ", conn_id);
683         return(tGATT_STATUS) GATT_INVALID_CONN_ID;
684     }
685 
686     if (GATT_HANDLE_IS_VALID (attr_handle))
687     {
688         notif.handle    = attr_handle;
689         notif.len       = val_len;
690         memcpy (notif.value, p_val, val_len);
691         notif.auth_req = GATT_AUTH_REQ_NONE;;
692 
693         if ((p_buf = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_NOTIF, (tGATT_SR_MSG *)&notif))
694                    != NULL)
695         {
696             cmd_sent = attp_send_sr_msg (p_tcb, p_buf);
697         }
698         else
699             cmd_sent = GATT_NO_RESOURCES;
700     }
701     return cmd_sent;
702 }
703 
704 /*******************************************************************************
705 **
706 ** Function         GATTS_SendRsp
707 **
708 ** Description      This function sends the server response to client.
709 **
710 ** Parameter        conn_id: connection identifier.
711 **                  trans_id: transaction id
712 **                  status: response status
713 **                  p_msg: pointer to message parameters structure.
714 **
715 ** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
716 **
717 *******************************************************************************/
GATTS_SendRsp(UINT16 conn_id,UINT32 trans_id,tGATT_STATUS status,tGATTS_RSP * p_msg)718 tGATT_STATUS GATTS_SendRsp (UINT16 conn_id,  UINT32 trans_id,
719                             tGATT_STATUS status, tGATTS_RSP *p_msg)
720 {
721     tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
722     tGATT_IF         gatt_if = GATT_GET_GATT_IF(conn_id);
723     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
724     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
725     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
726 
727     GATT_TRACE_API ("GATTS_SendRsp: conn_id: %u  trans_id: %u  Status: 0x%04x",
728                      conn_id, trans_id, status);
729 
730     if ( (p_reg == NULL) || (p_tcb == NULL))
731     {
732         GATT_TRACE_ERROR ("GATTS_SendRsp Unknown  conn_id: %u ", conn_id);
733         return(tGATT_STATUS) GATT_INVALID_CONN_ID;
734     }
735 
736     if (p_tcb->sr_cmd.trans_id != trans_id)
737     {
738         GATT_TRACE_ERROR ("GATTS_SendRsp conn_id: %u  waiting for op_code = %02x",
739                            conn_id, p_tcb->sr_cmd.op_code);
740 
741         return(GATT_WRONG_STATE);
742     }
743     /* Process App response */
744     cmd_sent = gatt_sr_process_app_rsp (p_tcb,  gatt_if, trans_id, p_tcb->sr_cmd.op_code, status, p_msg);
745 
746     return cmd_sent;
747 }
748 
749 /*******************************************************************************/
750 /* GATT Profile Srvr Functions */
751 /*******************************************************************************/
752 
753 /*******************************************************************************/
754 /*                                                                             */
755 /*                   GATT CLIENT APIs                                          */
756 /*                                                                             */
757 /*******************************************************************************/
758 
759 
760 /*******************************************************************************
761 **
762 ** Function         GATTC_ConfigureMTU
763 **
764 ** Description      This function is called to configure the ATT MTU size.
765 **
766 ** Parameters       conn_id: connection identifier.
767 **                  mtu    - attribute MTU size..
768 **
769 ** Returns          GATT_SUCCESS if command started successfully.
770 **
771 *******************************************************************************/
GATTC_ConfigureMTU(UINT16 conn_id,UINT16 mtu)772 tGATT_STATUS GATTC_ConfigureMTU (UINT16 conn_id, UINT16 mtu)
773 {
774     UINT8           ret = GATT_NO_RESOURCES;
775     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
776     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
777     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
778     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
779 
780     tGATT_CLCB    *p_clcb;
781 
782     GATT_TRACE_API ("GATTC_ConfigureMTU conn_id=%d mtu=%d", conn_id, mtu );
783 
784     /* Validate that the link is BLE, not BR/EDR */
785     if (p_tcb->transport != BT_TRANSPORT_LE)
786     {
787         return GATT_ERROR;
788     }
789 
790     if ( (p_tcb == NULL) || (p_reg==NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) || (mtu > GATT_MAX_MTU_SIZE))
791     {
792         return GATT_ILLEGAL_PARAMETER;
793     }
794 
795     if (gatt_is_clcb_allocated(conn_id))
796     {
797         GATT_TRACE_ERROR("GATTC_ConfigureMTU GATT_BUSY conn_id = %d", conn_id);
798         return GATT_BUSY;
799     }
800 
801     if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL)
802     {
803         p_clcb->p_tcb->payload_size = mtu;
804         p_clcb->operation = GATTC_OPTYPE_CONFIG;
805 
806         ret = attp_send_cl_msg (p_clcb->p_tcb, p_clcb->clcb_idx, GATT_REQ_MTU, (tGATT_CL_MSG *)&mtu);
807     }
808 
809     return ret;
810 }
811 
812 /*******************************************************************************
813 **
814 ** Function         GATTC_Discover
815 **
816 ** Description      This function is called to do a discovery procedure on ATT server.
817 **
818 ** Parameters       conn_id: connection identifier.
819 **                  disc_type:discovery type.
820 **                  p_param: parameters of discovery requirement.
821 **
822 ** Returns          GATT_SUCCESS if command received/sent successfully.
823 **
824 *******************************************************************************/
GATTC_Discover(UINT16 conn_id,tGATT_DISC_TYPE disc_type,tGATT_DISC_PARAM * p_param)825 tGATT_STATUS GATTC_Discover (UINT16 conn_id, tGATT_DISC_TYPE disc_type,
826                              tGATT_DISC_PARAM *p_param)
827 {
828     tGATT_STATUS    status = GATT_SUCCESS;
829     tGATT_CLCB      *p_clcb;
830     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
831     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
832     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
833     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
834 
835 
836     GATT_TRACE_API ("GATTC_Discover conn_id=%d disc_type=%d",conn_id, disc_type);
837 
838     if ( (p_tcb == NULL) || (p_reg==NULL) ||(p_param == NULL) ||
839          (disc_type >= GATT_DISC_MAX))
840     {
841         GATT_TRACE_ERROR("GATTC_Discover Illegal param: disc_type %d conn_id = %d", disc_type, conn_id);
842         return GATT_ILLEGAL_PARAMETER;
843     }
844 
845 
846     if (gatt_is_clcb_allocated(conn_id))
847     {
848         GATT_TRACE_ERROR("GATTC_Discover GATT_BUSY conn_id = %d", conn_id);
849         return GATT_BUSY;
850     }
851 
852 
853     if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
854     {
855         if (!GATT_HANDLE_IS_VALID(p_param->s_handle) ||
856             !GATT_HANDLE_IS_VALID(p_param->e_handle) ||
857             /* search by type does not have a valid UUID param */
858             (disc_type == GATT_DISC_SRVC_BY_UUID &&
859              p_param->service.len == 0))
860         {
861             gatt_clcb_dealloc(p_clcb);
862             return GATT_ILLEGAL_PARAMETER;
863         }
864 
865         p_clcb->operation  = GATTC_OPTYPE_DISCOVERY;
866         p_clcb->op_subtype = disc_type;
867         p_clcb->s_handle   = p_param->s_handle;
868         p_clcb->e_handle   = p_param->e_handle;
869         p_clcb->uuid       = p_param->service;
870 
871         gatt_act_discovery(p_clcb);
872     }
873     else
874     {
875         status = GATT_NO_RESOURCES;
876     }
877     return status;
878 }
879 
880 /*******************************************************************************
881 **
882 ** Function         GATTC_Read
883 **
884 ** Description      This function is called to read the value of an attribute from
885 **                  the server.
886 **
887 ** Parameters       conn_id: connection identifier.
888 **                  type    - attribute read type.
889 **                  p_read  - read operation parameters.
890 **
891 ** Returns          GATT_SUCCESS if command started successfully.
892 **
893 *******************************************************************************/
GATTC_Read(UINT16 conn_id,tGATT_READ_TYPE type,tGATT_READ_PARAM * p_read)894 tGATT_STATUS GATTC_Read (UINT16 conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read)
895 {
896     tGATT_STATUS status = GATT_SUCCESS;
897     tGATT_CLCB          *p_clcb;
898     tGATT_IF            gatt_if=GATT_GET_GATT_IF(conn_id);
899     UINT8               tcb_idx = GATT_GET_TCB_IDX(conn_id);
900     tGATT_TCB           *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
901     tGATT_REG           *p_reg = gatt_get_regcb(gatt_if);
902 
903 
904     GATT_TRACE_API ("GATTC_Read conn_id=%d type=%d", conn_id, type);
905 
906     if ( (p_tcb == NULL) || (p_reg==NULL) || (p_read == NULL) || ((type >= GATT_READ_MAX) || (type == 0)))
907     {
908         GATT_TRACE_ERROR("GATT_Read Illegal param: conn_id %d, type 0%d,", conn_id, type);
909         return GATT_ILLEGAL_PARAMETER;
910     }
911 
912     if (gatt_is_clcb_allocated(conn_id))
913     {
914         GATT_TRACE_ERROR("GATTC_Read GATT_BUSY conn_id = %d", conn_id);
915         return GATT_BUSY;
916     }
917 
918     if ( (p_clcb = gatt_clcb_alloc(conn_id)) != NULL  )
919     {
920         p_clcb->operation = GATTC_OPTYPE_READ;
921         p_clcb->op_subtype = type;
922         p_clcb->auth_req = p_read->by_handle.auth_req;
923         p_clcb->counter = 0;
924 
925         switch (type)
926         {
927             case GATT_READ_BY_TYPE:
928             case GATT_READ_CHAR_VALUE:
929                 p_clcb->s_handle = p_read->service.s_handle;
930                 p_clcb->e_handle = p_read->service.e_handle;
931                 memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID));
932                 break;
933             case GATT_READ_MULTIPLE:
934                 p_clcb->s_handle = 0;
935                 /* copy multiple handles in CB */
936                 tGATT_READ_MULTI *p_read_multi =
937                     (tGATT_READ_MULTI *)osi_malloc(sizeof(tGATT_READ_MULTI));
938                 p_clcb->p_attr_buf = (UINT8*)p_read_multi;
939                 memcpy(p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI));
940             case GATT_READ_BY_HANDLE:
941             case GATT_READ_PARTIAL:
942                 memset(&p_clcb->uuid, 0, sizeof(tBT_UUID));
943                 p_clcb->s_handle = p_read->by_handle.handle;
944 
945                 if (type == GATT_READ_PARTIAL)
946                 {
947                     p_clcb->counter = p_read->partial.offset;
948                 }
949 
950                 break;
951             default:
952                 break;
953         }
954         /* start security check */
955         if (gatt_security_check_start(p_clcb) == FALSE)
956         {
957             status = GATT_NO_RESOURCES;
958             gatt_clcb_dealloc(p_clcb);
959         }
960     }
961     else
962     {
963         status = GATT_NO_RESOURCES;
964     }
965     return status;
966 }
967 
968 /*******************************************************************************
969 **
970 ** Function         GATTC_Write
971 **
972 ** Description      This function is called to write the value of an attribute to
973 **                  the server.
974 **
975 ** Parameters       conn_id: connection identifier.
976 **                  type    - attribute write type.
977 **                  p_write  - write operation parameters.
978 **
979 ** Returns          GATT_SUCCESS if command started successfully.
980 **
981 *******************************************************************************/
GATTC_Write(UINT16 conn_id,tGATT_WRITE_TYPE type,tGATT_VALUE * p_write)982 tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
983 {
984     tGATT_STATUS status = GATT_SUCCESS;
985     tGATT_CLCB      *p_clcb;
986     tGATT_VALUE     *p;
987     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
988     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
989     tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
990     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
991 
992     if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) ||
993          ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) )
994     {
995         GATT_TRACE_ERROR("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type);
996         return GATT_ILLEGAL_PARAMETER;
997     }
998 
999     if (gatt_is_clcb_allocated(conn_id))
1000     {
1001         GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
1002         return GATT_BUSY;
1003     }
1004 
1005     if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
1006     {
1007         p_clcb->operation  = GATTC_OPTYPE_WRITE;
1008         p_clcb->op_subtype = type;
1009         p_clcb->auth_req = p_write->auth_req;
1010 
1011         p_clcb->p_attr_buf = (UINT8 *)osi_malloc(sizeof(tGATT_VALUE));
1012         memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));
1013 
1014         p = (tGATT_VALUE *)p_clcb->p_attr_buf;
1015         if (type == GATT_WRITE_PREPARE) {
1016             p_clcb->start_offset = p_write->offset;
1017             p->offset = 0;
1018         }
1019 
1020         if (gatt_security_check_start(p_clcb) == FALSE) {
1021             status = GATT_NO_RESOURCES;
1022         }
1023 
1024         if (status == GATT_NO_RESOURCES)
1025             gatt_clcb_dealloc(p_clcb);
1026     } else {
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 *******************************************************************************/
GATTC_ExecuteWrite(UINT16 conn_id,BOOLEAN is_execute)1046 tGATT_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_API ("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_ERROR("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_ERROR("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_ERROR("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 *******************************************************************************/
GATTC_SendHandleValueConfirm(UINT16 conn_id,UINT16 handle)1097 tGATT_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_API ("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             alarm_cancel(p_tcb->ind_ack_timer);
1109 
1110             GATT_TRACE_DEBUG ("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_DEBUG ("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_ERROR ("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 *******************************************************************************/
GATT_SetIdleTimeout(BD_ADDR bd_addr,UINT16 idle_tout,tBT_TRANSPORT transport)1149 void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout, tBT_TRANSPORT transport)
1150 {
1151     tGATT_TCB       *p_tcb;
1152     BOOLEAN         status = FALSE;
1153 
1154     if ((p_tcb = gatt_find_tcb_by_addr (bd_addr, transport)) != 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             if (idle_tout == GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP)
1161                 L2CA_SetIdleTimeoutByBdAddr(p_tcb->peer_bda,
1162                                             GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP, BT_TRANSPORT_LE);
1163         }
1164         else
1165         {
1166             status = L2CA_SetIdleTimeout (p_tcb->att_lcid, idle_tout, FALSE);
1167         }
1168     }
1169 
1170     GATT_TRACE_API ("GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)",
1171                     idle_tout, status);
1172 }
1173 
1174 
1175 /*******************************************************************************
1176 **
1177 ** Function         GATT_Register
1178 **
1179 ** Description      This function is called to register an  application
1180 **                  with GATT
1181 **
1182 ** Parameter        p_app_uuid128: Application UUID
1183 **                  p_cb_info: callback functions.
1184 **
1185 ** Returns          0 for error, otherwise the index of the client registered with GATT
1186 **
1187 *******************************************************************************/
GATT_Register(tBT_UUID * p_app_uuid128,tGATT_CBACK * p_cb_info)1188 tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info)
1189 {
1190     tGATT_REG    *p_reg;
1191     UINT8        i_gatt_if=0;
1192     tGATT_IF     gatt_if=0;
1193 
1194     GATT_TRACE_API ("%s", __func__);
1195     gatt_dbg_display_uuid(*p_app_uuid128);
1196 
1197     for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
1198     {
1199         if (p_reg->in_use  && !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128, LEN_UUID_128))
1200         {
1201             GATT_TRACE_ERROR("application already registered.");
1202             return 0;
1203         }
1204     }
1205 
1206     for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
1207     {
1208         if (!p_reg->in_use)
1209         {
1210             memset(p_reg, 0 , sizeof(tGATT_REG));
1211             i_gatt_if++;              /* one based number */
1212             p_reg->app_uuid128 =  *p_app_uuid128;
1213             gatt_if            =
1214             p_reg->gatt_if     = (tGATT_IF)i_gatt_if;
1215             p_reg->app_cb      = *p_cb_info;
1216             p_reg->in_use      = TRUE;
1217 
1218             GATT_TRACE_API ("%s: allocated gatt_if=%d", __func__, gatt_if);
1219             return gatt_if;
1220         }
1221     }
1222 
1223     GATT_TRACE_ERROR ("%s: can't Register GATT client, MAX client reached!", __func__);
1224     return 0;
1225 }
1226 
1227 
1228 /*******************************************************************************
1229 **
1230 ** Function         GATT_Deregister
1231 **
1232 ** Description      This function deregistered the application from GATT.
1233 **
1234 ** Parameters       gatt_if: applicaiton interface.
1235 **
1236 ** Returns          None.
1237 **
1238 *******************************************************************************/
GATT_Deregister(tGATT_IF gatt_if)1239 void GATT_Deregister (tGATT_IF gatt_if)
1240 {
1241     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
1242     tGATT_TCB       *p_tcb;
1243     tGATT_CLCB       *p_clcb;
1244     UINT8           i, ii, j;
1245     tGATT_SR_REG    *p_sreg;
1246 
1247     GATT_TRACE_API ("GATT_Deregister gatt_if=%d", gatt_if);
1248     /* Index 0 is GAP and is never deregistered */
1249     if ( (gatt_if == 0) || (p_reg == NULL) )
1250     {
1251         GATT_TRACE_ERROR ("GATT_Deregister with invalid gatt_if: %u", gatt_if);
1252         return;
1253     }
1254 
1255     /* stop all services  */
1256     /* todo an applcaiton can not be deregistered if its services is also used by other application
1257       deregisteration need to bed performed in an orderly fashion
1258       no check for now */
1259 
1260     for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++)
1261     {
1262         if (p_sreg->in_use && (p_sreg->gatt_if == gatt_if))
1263         {
1264             GATTS_StopService(p_sreg->s_hdl);
1265         }
1266     }
1267 
1268     /* free all services db buffers if owned by this application */
1269     gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128);
1270 
1271     /* When an application deregisters, check remove the link associated with the app */
1272 
1273     for (i=0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++)
1274     {
1275         if (p_tcb->in_use)
1276         {
1277             if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE)
1278             {
1279                 gatt_update_app_use_link_flag(gatt_if, p_tcb,  FALSE, TRUE);
1280             }
1281 
1282             for (j = 0, p_clcb= &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++)
1283             {
1284                 if (p_clcb->in_use &&
1285                     (p_clcb->p_reg->gatt_if == gatt_if) &&
1286                     (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx))
1287                 {
1288                     alarm_cancel(p_clcb->gatt_rsp_timer_ent);
1289                     gatt_clcb_dealloc (p_clcb);
1290                     break;
1291                 }
1292             }
1293         }
1294     }
1295 
1296     gatt_deregister_bgdev_list(gatt_if);
1297     /* update the listen mode */
1298 #if (defined(BLE_PERIPHERAL_MODE_SUPPORT) && (BLE_PERIPHERAL_MODE_SUPPORT == TRUE))
1299     GATT_Listen(gatt_if, FALSE, NULL);
1300 #endif
1301 
1302     memset (p_reg, 0, sizeof(tGATT_REG));
1303 }
1304 
1305 
1306 /*******************************************************************************
1307 **
1308 ** Function         GATT_StartIf
1309 **
1310 ** Description      This function is called after registration to start receiving
1311 **                  callbacks for registered interface.  Function may call back
1312 **                  with connection status and queued notifications
1313 **
1314 ** Parameter        gatt_if: applicaiton interface.
1315 **
1316 ** Returns          None.
1317 **
1318 *******************************************************************************/
GATT_StartIf(tGATT_IF gatt_if)1319 void GATT_StartIf (tGATT_IF gatt_if)
1320 {
1321     tGATT_REG   *p_reg;
1322     tGATT_TCB   *p_tcb;
1323     BD_ADDR     bda;
1324     UINT8       start_idx, found_idx;
1325     UINT16      conn_id;
1326     tGATT_TRANSPORT transport ;
1327 
1328     GATT_TRACE_API ("GATT_StartIf gatt_if=%d", gatt_if);
1329     if ((p_reg = gatt_get_regcb(gatt_if)) != NULL)
1330     {
1331         start_idx = 0;
1332         while (gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport))
1333         {
1334             p_tcb = gatt_find_tcb_by_addr(bda, transport);
1335             if (p_reg->app_cb.p_conn_cb && p_tcb)
1336             {
1337                 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
1338                 (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0, transport);
1339             }
1340             start_idx = ++found_idx;
1341         }
1342     }
1343 }
1344 
1345 
1346 /*******************************************************************************
1347 **
1348 ** Function         GATT_Connect
1349 **
1350 ** Description      This function initiate a connecttion to a remote device on GATT
1351 **                  channel.
1352 **
1353 ** Parameters       gatt_if: applicaiton interface
1354 **                  bd_addr: peer device address.
1355 **                  is_direct: is a direct conenection or a background auto connection
1356 **
1357 ** Returns          TRUE if connection started; FALSE if connection start failure.
1358 **
1359 *******************************************************************************/
GATT_Connect(tGATT_IF gatt_if,BD_ADDR bd_addr,BOOLEAN is_direct,tBT_TRANSPORT transport)1360 BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct, tBT_TRANSPORT transport)
1361 {
1362     tGATT_REG    *p_reg;
1363     BOOLEAN status = FALSE;
1364 
1365     GATT_TRACE_API ("GATT_Connect gatt_if=%d", gatt_if);
1366 
1367     /* Make sure app is registered */
1368     if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
1369     {
1370         GATT_TRACE_ERROR("GATT_Connect - gatt_if =%d is not registered", gatt_if);
1371         return(FALSE);
1372     }
1373 
1374     if (is_direct)
1375         status = gatt_act_connect (p_reg, bd_addr, transport);
1376     else
1377     {
1378         if (transport == BT_TRANSPORT_LE)
1379         status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr, TRUE);
1380         else
1381         {
1382             GATT_TRACE_ERROR("Unsupported transport for background connection");
1383         }
1384     }
1385 
1386     return status;
1387 
1388 }
1389 
1390 /*******************************************************************************
1391 **
1392 ** Function         GATT_CancelConnect
1393 **
1394 ** Description      This function terminate the connection initaition to a remote
1395 **                  device on GATT channel.
1396 **
1397 ** Parameters       gatt_if: client interface. If 0 used as unconditionally disconnect,
1398 **                          typically used for direct connection cancellation.
1399 **                  bd_addr: peer device address.
1400 **
1401 ** Returns          TRUE if connection started; FALSE if connection start failure.
1402 **
1403 *******************************************************************************/
GATT_CancelConnect(tGATT_IF gatt_if,BD_ADDR bd_addr,BOOLEAN is_direct)1404 BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){
1405     tGATT_REG     *p_reg;
1406     tGATT_TCB     *p_tcb;
1407     BOOLEAN       status = TRUE;
1408     tGATT_IF      temp_gatt_if;
1409     UINT8         start_idx, found_idx;
1410 
1411     GATT_TRACE_API ("GATT_CancelConnect gatt_if=%d", gatt_if);
1412 
1413     if ((gatt_if != 0) && ((p_reg = gatt_get_regcb(gatt_if)) == NULL))
1414     {
1415         GATT_TRACE_ERROR("GATT_CancelConnect - gatt_if =%d is not registered", gatt_if);
1416         return(FALSE);
1417     }
1418 
1419     if (is_direct)
1420     {
1421         if (!gatt_if)
1422         {
1423             GATT_TRACE_DEBUG("GATT_CancelConnect - unconditional");
1424             start_idx = 0;
1425             /* only LE connection can be cancelled */
1426             p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
1427             if (p_tcb && gatt_num_apps_hold_link(p_tcb))
1428             {
1429                 while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx, &temp_gatt_if))
1430                 {
1431                     status = gatt_cancel_open(temp_gatt_if, bd_addr);
1432                     start_idx = ++found_idx;
1433                 }
1434             }
1435             else
1436             {
1437                 GATT_TRACE_ERROR("GATT_CancelConnect - no app found");
1438                 status = FALSE;
1439             }
1440         }
1441         else
1442         {
1443             status = gatt_cancel_open(gatt_if, bd_addr);
1444         }
1445     }
1446     else
1447     {
1448         if (!gatt_if)
1449         {
1450             if (gatt_get_num_apps_for_bg_dev(bd_addr))
1451             {
1452                 while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if))
1453                     gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr);
1454             }
1455             else
1456             {
1457                 GATT_TRACE_ERROR("GATT_CancelConnect -no app associated with the bg device for unconditional removal");
1458                 status = FALSE;
1459             }
1460         }
1461         else
1462         {
1463             status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
1464         }
1465     }
1466 
1467     return status;
1468 }
1469 
1470 /*******************************************************************************
1471 **
1472 ** Function         GATT_Disconnect
1473 **
1474 ** Description      This function disconnect the GATT channel for this registered
1475 **                  application.
1476 **
1477 ** Parameters       conn_id: connection identifier.
1478 **
1479 ** Returns          GATT_SUCCESS if disconnected.
1480 **
1481 *******************************************************************************/
GATT_Disconnect(UINT16 conn_id)1482 tGATT_STATUS GATT_Disconnect (UINT16 conn_id)
1483 {
1484     tGATT_STATUS    ret = GATT_ILLEGAL_PARAMETER;
1485     tGATT_TCB       *p_tcb=NULL;
1486     tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
1487     UINT8          tcb_idx = GATT_GET_TCB_IDX(conn_id);
1488 
1489     GATT_TRACE_API ("GATT_Disconnect conn_id=%d ", conn_id);
1490 
1491     p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1492 
1493     if (p_tcb)
1494     {
1495         gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, TRUE);
1496         ret = GATT_SUCCESS;
1497     }
1498     return ret;
1499 }
1500 
1501 
1502 /*******************************************************************************
1503 **
1504 ** Function         GATT_GetConnectionInfor
1505 **
1506 ** Description      This function use conn_id to find its associated BD address and applciation
1507 **                  interface
1508 **
1509 ** Parameters        conn_id: connection id  (input)
1510 **                   p_gatt_if: applicaiton interface (output)
1511 **                   bd_addr: peer device address. (output)
1512 **
1513 ** Returns          TRUE the ligical link information is found for conn_id
1514 **
1515 *******************************************************************************/
GATT_GetConnectionInfor(UINT16 conn_id,tGATT_IF * p_gatt_if,BD_ADDR bd_addr,tBT_TRANSPORT * p_transport)1516 BOOLEAN GATT_GetConnectionInfor(UINT16 conn_id, tGATT_IF *p_gatt_if, BD_ADDR bd_addr,
1517                                 tBT_TRANSPORT *p_transport)
1518 {
1519 
1520     tGATT_IF        gatt_if = GATT_GET_GATT_IF(conn_id);
1521     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
1522     UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
1523     tGATT_TCB       *p_tcb= gatt_get_tcb_by_idx(tcb_idx);
1524     BOOLEAN         status=FALSE;
1525 
1526     GATT_TRACE_API ("GATT_GetConnectionInfor conn_id=%d", conn_id);
1527 
1528     if (p_tcb && p_reg )
1529     {
1530         memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN);
1531         *p_gatt_if = gatt_if;
1532         *p_transport = p_tcb->transport;
1533         status = TRUE;
1534     }
1535     return status;
1536 }
1537 
1538 
1539 /*******************************************************************************
1540 **
1541 ** Function         GATT_GetConnIdIfConnected
1542 **
1543 ** Description      This function find the conn_id if the logical link for BD address
1544 **                  and applciation interface is connected
1545 **
1546 ** Parameters        gatt_if: applicaiton interface (input)
1547 **                   bd_addr: peer device address. (input)
1548 **                   p_conn_id: connection id  (output)
1549 **                   transport: transport option
1550 **
1551 ** Returns          TRUE the logical link is connected
1552 **
1553 *******************************************************************************/
GATT_GetConnIdIfConnected(tGATT_IF gatt_if,BD_ADDR bd_addr,UINT16 * p_conn_id,tBT_TRANSPORT transport)1554 BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_conn_id,
1555                                   tBT_TRANSPORT transport)
1556 {
1557     tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
1558     tGATT_TCB       *p_tcb= gatt_find_tcb_by_addr(bd_addr, transport);
1559     BOOLEAN         status=FALSE;
1560 
1561     if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) )
1562     {
1563         *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
1564         status = TRUE;
1565     }
1566 
1567     GATT_TRACE_API ("GATT_GetConnIdIfConnected status=%d", status);
1568     return status;
1569 }
1570 
1571 
1572 /*******************************************************************************
1573 **
1574 ** Function         GATT_Listen
1575 **
1576 ** Description      This function start or stop LE advertisement and listen for
1577 **                  connection.
1578 **
1579 ** Parameters       gatt_if: applicaiton interface
1580 **                  p_bd_addr: listen for specific address connection, or NULL for
1581 **                             listen to all device connection.
1582 **                  start: start or stop listening.
1583 **
1584 ** Returns          TRUE if advertisement is started; FALSE if adv start failure.
1585 **
1586 *******************************************************************************/
GATT_Listen(tGATT_IF gatt_if,BOOLEAN start,BD_ADDR_PTR bd_addr)1587 BOOLEAN GATT_Listen (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr)
1588 {
1589     tGATT_REG    *p_reg;
1590 
1591     GATT_TRACE_API ("GATT_Listen gatt_if=%d", gatt_if);
1592 
1593     /* Make sure app is registered */
1594     if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
1595     {
1596         GATT_TRACE_ERROR("GATT_Listen - gatt_if =%d is not registered", gatt_if);
1597         return(FALSE);
1598     }
1599 
1600     if (bd_addr != NULL)
1601     {
1602         gatt_update_auto_connect_dev(gatt_if,start, bd_addr, FALSE);
1603     }
1604     else
1605     {
1606         p_reg->listening = start ? GATT_LISTEN_TO_ALL : GATT_LISTEN_TO_NONE;
1607     }
1608 
1609     return gatt_update_listen_mode();
1610 }
1611 
1612 #endif
1613 
1614