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 *)¬if))
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