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 "common/bt_target.h"
25
26
27 #if defined(BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE)
28
29 #include "osi/allocator.h"
30 #include <string.h>
31 #include "stack/gatt_api.h"
32 #include "gatt_int.h"
33 #include "stack/l2c_api.h"
34 #include "btm_int.h"
35 #include "stack/sdpdefs.h"
36 #include "stack/sdp_api.h"
37
38 /*******************************************************************************
39 **
40 ** Function GATT_SetTraceLevel
41 **
42 ** Description This function sets the trace level. If called with
43 ** a value of 0xFF, it simply returns the current trace level.
44 **
45 ** Input Parameters:
46 ** level: The level to set the GATT tracing to:
47 ** 0xff-returns the current setting.
48 ** 0-turns off tracing.
49 ** >= 1-Errors.
50 ** >= 2-Warnings.
51 ** >= 3-APIs.
52 ** >= 4-Events.
53 ** >= 5-Debug.
54 **
55 ** Returns The new or current trace level
56 **
57 *******************************************************************************/
GATT_SetTraceLevel(UINT8 new_level)58 UINT8 GATT_SetTraceLevel (UINT8 new_level)
59 {
60 if (new_level != 0xFF) {
61 gatt_cb.trace_level = new_level;
62 }
63
64 return (gatt_cb.trace_level);
65 }
66
67
68 #if (GATTS_INCLUDED == TRUE)
69 /*****************************************************************************
70 **
71 ** GATT SERVER API
72 **
73 ******************************************************************************/
74 /*******************************************************************************
75 **
76 ** Function GATTS_AddHandleRange
77 **
78 ** Description This function add the allocated handles range for the specifed
79 ** application UUID, service UUID and service instance
80 **
81 ** Parameter p_hndl_range: pointer to allocated handles information
82 **
83 ** Returns TRUE if handle range is added successfully; otherwise FALSE.
84 **
85 *******************************************************************************/
86
GATTS_AddHandleRange(tGATTS_HNDL_RANGE * p_hndl_range)87 BOOLEAN GATTS_AddHandleRange(tGATTS_HNDL_RANGE *p_hndl_range)
88 {
89 tGATT_HDL_LIST_ELEM *p_buf;
90 BOOLEAN status = FALSE;
91
92 if ((p_buf = gatt_alloc_hdl_buffer()) != NULL) {
93 p_buf->asgn_range = *p_hndl_range;
94 status = gatt_add_an_item_to_list(&gatt_cb.hdl_list_info, p_buf);
95 }
96 return status;
97 }
98
99
100 /*******************************************************************************
101 **
102 ** Function GATTS_NVRegister
103 **
104 ** Description Application manager calls this function to register for
105 ** NV save callback function. There can be one and only one
106 ** NV save callback function.
107 **
108 ** Parameter p_cb_info : callback informaiton
109 **
110 ** Returns TRUE if registered OK, else FALSE
111 **
112 *******************************************************************************/
GATTS_NVRegister(const tGATT_APPL_INFO * p_cb_info)113 BOOLEAN GATTS_NVRegister (const tGATT_APPL_INFO *p_cb_info)
114 {
115 BOOLEAN status = FALSE;
116 if (p_cb_info) {
117 gatt_cb.cb_info = *p_cb_info;
118 status = TRUE;
119 gatt_init_srv_chg();
120 }
121
122 return status;
123 }
124
125 /*******************************************************************************
126 **
127 ** Function GATTS_CreateService
128 **
129 ** Description This function is called to reserve a block of handles for a service.
130 **
131 ** *** It should be called only once per service instance ***
132 **
133 ** Parameter gatt_if : application if
134 ** p_svc_uuid : service UUID
135 ** svc_inst : instance of the service inside the application
136 ** num_handles : number of handles needed by the service.
137 ** is_pri : is a primary service or not.
138 **
139 ** Returns service handle if sucessful, otherwise 0.
140 **
141 *******************************************************************************/
GATTS_CreateService(tGATT_IF gatt_if,tBT_UUID * p_svc_uuid,UINT16 svc_inst,UINT16 num_handles,BOOLEAN is_pri)142 UINT16 GATTS_CreateService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid,
143 UINT16 svc_inst, UINT16 num_handles, BOOLEAN is_pri)
144 {
145
146 tGATT_HDL_LIST_INFO *p_list_info = &gatt_cb.hdl_list_info;
147 tGATT_HDL_LIST_ELEM *p_list = NULL;
148 UINT16 s_hdl = 0;
149 BOOLEAN save_hdl = FALSE;
150 tGATTS_PENDING_NEW_SRV_START *p_buf = NULL;
151 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
152 tBT_UUID *p_app_uuid128;
153
154
155 GATT_TRACE_API ("GATTS_CreateService\n" );
156
157 if (p_reg == NULL) {
158 GATT_TRACE_ERROR ("Inavlid gatt_if=%d\n", gatt_if);
159 return (0);
160 }
161
162 p_app_uuid128 = &p_reg->app_uuid128;
163
164 if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) != NULL) {
165 s_hdl = p_list->asgn_range.s_handle;
166 GATT_TRACE_DEBUG ("Service already been created!!\n");
167 } else {
168 if ( (p_svc_uuid->len == LEN_UUID_16) && (p_svc_uuid->uu.uuid16 == UUID_SERVCLASS_GATT_SERVER)) {
169 s_hdl = gatt_cb.hdl_cfg.gatt_start_hdl;
170 } else if ((p_svc_uuid->len == LEN_UUID_16) && (p_svc_uuid->uu.uuid16 == UUID_SERVCLASS_GAP_SERVER)) {
171 s_hdl = gatt_cb.hdl_cfg.gap_start_hdl;
172 } else {
173 p_list = p_list_info->p_first;
174
175 if (p_list) {
176 s_hdl = p_list->asgn_range.e_handle + 1;
177 }
178
179 if (s_hdl < gatt_cb.hdl_cfg.app_start_hdl) {
180
181 s_hdl = gatt_cb.hdl_cfg.app_start_hdl;
182 }
183 save_hdl = TRUE;
184 }
185
186 /* check for space */
187 if (num_handles > (0xFFFF - s_hdl + 1)) {
188 GATT_TRACE_ERROR ("GATTS_ReserveHandles: no handles, s_hdl: %u needed: %u\n", s_hdl, num_handles);
189 return (0);
190 }
191
192 if ( (p_list = gatt_alloc_hdl_buffer()) == NULL) {
193 /* No free entry */
194 GATT_TRACE_ERROR ("GATTS_ReserveHandles: no free handle blocks\n");
195 return (0);
196 }
197
198 p_list->asgn_range.app_uuid128 = *p_app_uuid128;
199 p_list->asgn_range.svc_uuid = *p_svc_uuid;
200 p_list->asgn_range.svc_inst = svc_inst;
201 p_list->asgn_range.s_handle = s_hdl;
202 p_list->asgn_range.e_handle = s_hdl + num_handles - 1;
203 p_list->asgn_range.is_primary = is_pri;
204
205 gatt_add_an_item_to_list(p_list_info, p_list);
206
207 if (save_hdl) {
208 if (gatt_cb.cb_info.p_nv_save_callback) {
209 (*gatt_cb.cb_info.p_nv_save_callback)(TRUE, &p_list->asgn_range);
210 }
211 /* add a pending new service change item to the list */
212 if ( (p_buf = gatt_add_pending_new_srv_start(&p_list->asgn_range)) == NULL) {
213 /* No free entry */
214 GATT_TRACE_ERROR ("gatt_add_pending_new_srv_start: no free blocks\n");
215
216 if (p_list) {
217 gatt_remove_an_item_from_list(p_list_info, p_list);
218 gatt_free_attr_value_buffer(p_list);
219 gatt_free_hdl_buffer(p_list);
220 }
221 return (0);
222 }
223
224 GATT_TRACE_DEBUG ("Add a new srv chg item\n");
225 }
226 }
227
228 if (!gatts_init_service_db(&p_list->svc_db, p_svc_uuid, is_pri, s_hdl , num_handles)) {
229 GATT_TRACE_ERROR ("GATTS_ReserveHandles: service DB initialization failed\n");
230 if (p_list) {
231 gatt_remove_an_item_from_list(p_list_info, p_list);
232 gatt_free_attr_value_buffer(p_list);
233 gatt_free_hdl_buffer(p_list);
234 }
235
236 if (p_buf) {
237 osi_free(fixed_queue_try_remove_from_queue(gatt_cb.pending_new_srv_start_q, p_buf));
238 }
239 return (0);
240 }
241
242 return (s_hdl);
243 }
244
245 /*******************************************************************************
246 **
247 ** Function GATTS_AddIncludeService
248 **
249 ** Description This function is called to add an included service.
250 **
251 ** Parameter service_handle : To which service this included service is added to.
252 ** include_svc_handle : included service handle.
253 **
254 ** Returns included service attribute handle. If 0, add included service
255 ** fail.
256 **
257 *******************************************************************************/
GATTS_AddIncludeService(UINT16 service_handle,UINT16 include_svc_handle)258 UINT16 GATTS_AddIncludeService (UINT16 service_handle, UINT16 include_svc_handle)
259
260 {
261 tGATT_HDL_LIST_ELEM *p_decl, *p_incl_decl;
262
263 if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) {
264 GATT_TRACE_DEBUG("Service not created");
265 return 0;
266 }
267 if ((p_incl_decl = gatt_find_hdl_buffer_by_handle(include_svc_handle)) == NULL) {
268 GATT_TRACE_DEBUG("Included Service not created");
269 return 0;
270 }
271
272 return gatts_add_included_service(&p_decl->svc_db,
273 p_incl_decl->asgn_range.s_handle,
274 p_incl_decl->asgn_range.e_handle,
275 p_incl_decl->asgn_range.svc_uuid);
276 }
277 /*******************************************************************************
278 **
279 ** Function GATTS_AddCharacteristic
280 **
281 ** Description This function is called to add a characteristic into a service.
282 ** It will add a characteristic declaration and characteristic
283 ** value declaration into the service database identified by the
284 ** service handle.
285 **
286 ** Parameter service_handle : To which service this included service is added to.
287 ** char_uuid : Characteristic UUID.
288 ** perm : Characteristic value declaration attribute permission.
289 ** property : Characteristic Properties
290 **
291 ** Returns Characteristic value declaration attribute handle. 0 if failed.
292 **
293 *******************************************************************************/
GATTS_AddCharacteristic(UINT16 service_handle,tBT_UUID * p_char_uuid,tGATT_PERM perm,tGATT_CHAR_PROP property,tGATT_ATTR_VAL * attr_val,tGATTS_ATTR_CONTROL * control)294 UINT16 GATTS_AddCharacteristic (UINT16 service_handle, tBT_UUID *p_char_uuid,
295 tGATT_PERM perm, tGATT_CHAR_PROP property,
296 tGATT_ATTR_VAL *attr_val, tGATTS_ATTR_CONTROL *control)
297 {
298 tGATT_HDL_LIST_ELEM *p_decl;
299
300 if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) {
301 GATT_TRACE_DEBUG("Service not created\n");
302 return 0;
303 }
304 /* data validity checking */
305 if ( ((property & GATT_CHAR_PROP_BIT_AUTH) && !(perm & GATT_WRITE_SIGNED_PERM)) ||
306 ((perm & GATT_WRITE_SIGNED_PERM) && !(property & GATT_CHAR_PROP_BIT_AUTH)) ) {
307 GATT_TRACE_DEBUG("Invalid configuration property=0x%x perm=0x%x\n ", property, perm);
308 return 0;
309 }
310
311 return gatts_add_characteristic(&p_decl->svc_db,
312 perm,
313 property,
314 p_char_uuid,
315 attr_val, control);
316 }
317 /*******************************************************************************
318 **
319 ** Function GATTS_AddCharDescriptor
320 **
321 ** Description This function is called to add a characteristic descriptor
322 ** into a service database. Add descriptor should follow add char
323 ** to which it belongs, and next add char should be done only
324 ** after all add descriptors for the previous char.
325 **
326 ** Parameter service_handle : To which service this characteristic descriptor
327 ** is added to.
328 ** perm : Characteristic value declaration attribute
329 ** permission.
330 ** p_descr_uuid : Characteristic descriptor UUID
331 **
332 ** Returns Characteristic descriptor attribute handle. 0 if add
333 ** characteristic descriptor failed.
334 **
335 *******************************************************************************/
GATTS_AddCharDescriptor(UINT16 service_handle,tGATT_PERM perm,tBT_UUID * p_descr_uuid,tGATT_ATTR_VAL * attr_val,tGATTS_ATTR_CONTROL * control)336 UINT16 GATTS_AddCharDescriptor (UINT16 service_handle,
337 tGATT_PERM perm,
338 tBT_UUID *p_descr_uuid, tGATT_ATTR_VAL *attr_val, tGATTS_ATTR_CONTROL *control)
339 {
340 tGATT_HDL_LIST_ELEM *p_decl;
341
342 if ((p_decl = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) {
343 GATT_TRACE_DEBUG("Service not created");
344 return 0;
345 }
346 if (p_descr_uuid == NULL ||
347 (p_descr_uuid->len != LEN_UUID_128 && p_descr_uuid->len != LEN_UUID_16
348 && p_descr_uuid->len != LEN_UUID_32)) {
349 GATT_TRACE_DEBUG("Illegal parameter");
350 return 0;
351 }
352
353 return gatts_add_char_descr(&p_decl->svc_db,
354 perm,
355 p_descr_uuid,
356 attr_val, control);
357
358 }
359 /*******************************************************************************
360 **
361 ** Function GATTS_DeleteService
362 **
363 ** Description This function is called to delete a service.
364 **
365 ** Parameter gatt_if : application interface
366 ** p_svc_uuid : service UUID
367 ** svc_inst : instance of the service inside the application
368 **
369 ** Returns TRUE if operation succeed, FALSE if handle block was not found.
370 **
371 *******************************************************************************/
GATTS_DeleteService(tGATT_IF gatt_if,tBT_UUID * p_svc_uuid,UINT16 svc_inst)372 BOOLEAN GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, UINT16 svc_inst)
373 {
374
375 tGATT_HDL_LIST_INFO *p_list_info = &gatt_cb.hdl_list_info;
376 tGATT_HDL_LIST_ELEM *p_list = NULL;
377 UINT8 i_sreg;
378 tGATTS_PENDING_NEW_SRV_START *p_buf;
379 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
380 tBT_UUID *p_app_uuid128;
381
382 GATT_TRACE_DEBUG ("GATTS_DeleteService");
383
384 if (p_reg == NULL) {
385 GATT_TRACE_ERROR ("Application not foud");
386 return (FALSE);
387 }
388 p_app_uuid128 = &p_reg->app_uuid128;
389
390 if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) == NULL) {
391 GATT_TRACE_ERROR ("No Service found");
392 return (FALSE);
393 }
394
395 if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128,
396 &p_list->asgn_range.svc_uuid,
397 p_list->asgn_range.svc_inst)) != NULL) {
398 GATT_TRACE_DEBUG ("Delete a new service changed item - the service has not yet started");
399 osi_free(fixed_queue_try_remove_from_queue(gatt_cb.pending_new_srv_start_q, p_buf));
400 } else {
401 if (GATTS_SEND_SERVICE_CHANGE_MODE == GATTS_SEND_SERVICE_CHANGE_AUTO) {
402 gatt_proc_srv_chg();
403 }
404 }
405
406 if ((i_sreg = gatt_sr_find_i_rcb_by_app_id (p_app_uuid128,
407 p_svc_uuid,
408 svc_inst)) != GATT_MAX_SR_PROFILES) {
409 GATTS_StopService(gatt_cb.sr_reg[i_sreg].s_hdl);
410 }
411
412 GATT_TRACE_DEBUG ("released handles s_hdl=%u e_hdl=%u",
413 p_list->asgn_range.s_handle , p_list->asgn_range.e_handle );
414
415 if ( (p_list->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl)
416 && gatt_cb.cb_info.p_nv_save_callback) {
417 (*gatt_cb.cb_info.p_nv_save_callback)(FALSE, &p_list->asgn_range);
418 }
419
420 gatt_remove_an_item_from_list(p_list_info, p_list);
421 gatt_free_attr_value_buffer(p_list);
422 gatt_free_hdl_buffer(p_list);
423
424 return (TRUE);
425 }
426
427 /*******************************************************************************
428 **
429 ** Function GATTS_StartService
430 **
431 ** Description This function is called to start a service with GATT
432 **
433 ** Parameter gatt_if : service handle.
434 ** p_cback : application service callback functions.
435 ** sup_transport : supported transport(s) for this primary service
436 **
437 ** return GATT_SUCCESS if successfully started; otherwise error code.
438 **
439 *******************************************************************************/
GATTS_StartService(tGATT_IF gatt_if,UINT16 service_handle,tGATT_TRANSPORT sup_transport)440 tGATT_STATUS GATTS_StartService (tGATT_IF gatt_if, UINT16 service_handle,
441 tGATT_TRANSPORT sup_transport)
442 {
443 tGATT_SR_REG *p_sreg;
444 tGATT_HDL_LIST_ELEM *p_list = NULL;
445 UINT8 i_sreg;
446 #if (SDP_INCLUDED == TRUE && CLASSIC_BT_GATT_INCLUDED == TRUE)
447 tBT_UUID *p_uuid;
448 #endif ///SDP_INCLUDED == TRUE && CLASSIC_BT_GATT_INCLUDED == TRUE
449 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
450
451 tGATTS_PENDING_NEW_SRV_START *p_buf;
452
453 GATT_TRACE_API ("GATTS_StartService");
454
455 if (p_reg == NULL) {
456 /* Not found */
457 GATT_TRACE_ERROR ("Application not found ");
458 return GATT_NOT_FOUND;
459 }
460
461 if ((p_list = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL) {
462 /* Not found */
463 GATT_TRACE_ERROR ("no service found");
464 return GATT_NOT_FOUND;
465 }
466
467 if (gatt_sr_find_i_rcb_by_app_id (&p_list->asgn_range.app_uuid128,
468 &p_list->asgn_range.svc_uuid,
469 p_list->asgn_range.svc_inst) != GATT_MAX_SR_PROFILES) {
470 GATT_TRACE_ERROR ("Duplicate Service start - Service already started");
471 return GATT_SERVICE_STARTED;
472 }
473
474 /*this is a new application servoce start */
475 if ((i_sreg = gatt_sr_alloc_rcb(p_list)) == GATT_MAX_SR_PROFILES) {
476 GATT_TRACE_ERROR ("GATTS_StartService: no free server registration block");
477 return GATT_NO_RESOURCES;
478 }
479
480 p_sreg = &gatt_cb.sr_reg[i_sreg];
481 p_sreg->gatt_if = gatt_if;
482
483 switch (sup_transport) {
484 case GATT_TRANSPORT_BR_EDR:
485 case GATT_TRANSPORT_LE_BR_EDR:
486 if (p_sreg->type == GATT_UUID_PRI_SERVICE) {
487 #if (SDP_INCLUDED == TRUE && CLASSIC_BT_GATT_INCLUDED == TRUE)
488 p_uuid = gatts_get_service_uuid (p_sreg->p_db);
489 p_sreg->sdp_handle = gatt_add_sdp_record(p_uuid, p_sreg->s_hdl, p_sreg->e_hdl);
490 #endif ///SDP_INCLUDED == TRUE && CLASSIC_BT_GATT_INCLUDED == TRUE
491 }
492 break;
493 default:
494 break;
495 }
496
497 gatts_update_srv_list_elem(i_sreg, p_sreg->s_hdl,
498 p_list->asgn_range.is_primary);
499
500 gatt_add_a_srv_to_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[i_sreg]);
501
502 GATT_TRACE_DEBUG ("allocated i_sreg=%d\n", i_sreg);
503
504 GATT_TRACE_DEBUG ("s_hdl=%d e_hdl=%d type=0x%x svc_inst=%d sdp_hdl=0x%x\n",
505 p_sreg->s_hdl, p_sreg->e_hdl,
506 p_sreg->type, p_sreg->service_instance,
507 p_sreg->sdp_handle);
508
509
510 if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128,
511 &p_list->asgn_range.svc_uuid,
512 p_list->asgn_range.svc_inst)) != NULL) {
513 if (GATTS_SEND_SERVICE_CHANGE_MODE == GATTS_SEND_SERVICE_CHANGE_AUTO) {
514 gatt_proc_srv_chg();
515 }
516 /* remove the new service element after the srv changed processing is completed*/
517
518 osi_free(fixed_queue_try_remove_from_queue(gatt_cb.pending_new_srv_start_q, p_buf));
519 }
520 return GATT_SUCCESS;
521 }
522
523 /*******************************************************************************
524 **
525 ** Function GATTS_StopService
526 **
527 ** Description This function is called to stop a service
528 **
529 ** Parameter service_handle : this is the start handle of a service
530 **
531 ** Returns None.
532 **
533 *******************************************************************************/
GATTS_StopService(UINT16 service_handle)534 void GATTS_StopService (UINT16 service_handle)
535 {
536 UINT8 ii = gatt_sr_find_i_rcb_by_handle(service_handle);
537
538 GATT_TRACE_API("GATTS_StopService %u", service_handle);
539
540 /* Index 0 is reserved for GATT, and is never stopped */
541 if ( (ii > 0) && (ii < GATT_MAX_SR_PROFILES) && (gatt_cb.sr_reg[ii].in_use) ) {
542 #if(SDP_INCLUDED == TRUE && CLASSIC_BT_GATT_INCLUDED == TRUE)
543 if (gatt_cb.sr_reg[ii].sdp_handle) {
544 SDP_DeleteRecord(gatt_cb.sr_reg[ii].sdp_handle);
545 }
546 #endif ///SDP_INCLUDED == TRUE && CLASSIC_BT_GATT_INCLUDED == TRUE
547 gatt_remove_a_srv_from_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[ii]);
548 gatt_cb.srv_list[ii].in_use = FALSE;
549 memset (&gatt_cb.sr_reg[ii], 0, sizeof(tGATT_SR_REG));
550 } else {
551 GATT_TRACE_ERROR("GATTS_StopService service_handle: %u is not in use", service_handle);
552 }
553 }
554 /*******************************************************************************
555 **
556 ** Function GATTs_HandleValueIndication
557 **
558 ** Description This function sends a handle value indication to a client.
559 **
560 ** Parameter conn_id: connection identifier.
561 ** attr_handle: Attribute handle of this handle value indication.
562 ** val_len: Length of the indicated attribute value.
563 ** p_val: Pointer to the indicated attribute value data.
564 **
565 ** Returns GATT_SUCCESS if successfully sent or queued; otherwise error code.
566 **
567 *******************************************************************************/
GATTS_HandleValueIndication(UINT16 conn_id,UINT16 attr_handle,UINT16 val_len,UINT8 * p_val)568 tGATT_STATUS GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_handle, UINT16 val_len, UINT8 *p_val)
569 {
570 tGATT_STATUS cmd_status = GATT_NO_RESOURCES;
571
572 tGATT_VALUE indication;
573 BT_HDR *p_msg;
574 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
575 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
576 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
577 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
578
579
580 GATT_TRACE_API ("GATTS_HandleValueIndication");
581 if ( (p_reg == NULL) || (p_tcb == NULL)) {
582 GATT_TRACE_ERROR ("GATTS_HandleValueIndication Unknown conn_id: %u ", conn_id);
583 return (tGATT_STATUS) GATT_INVALID_CONN_ID;
584 }
585
586 if (! GATT_HANDLE_IS_VALID (attr_handle)) {
587 return GATT_ILLEGAL_PARAMETER;
588 }
589
590 indication.conn_id = conn_id;
591 indication.handle = attr_handle;
592 indication.len = val_len;
593 memcpy (indication.value, p_val, val_len);
594 indication.auth_req = GATT_AUTH_REQ_NONE;
595
596 if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle)) {
597 /* TODO: need to further check whether deleting pending queue here cause reducing transport performance */
598 /*
599 GATT_TRACE_DEBUG ("Add a pending indication");
600 if ((p_buf = gatt_add_pending_ind(p_tcb, &indication)) != NULL) {
601 cmd_status = GATT_SUCCESS;
602 } else {
603 cmd_status = GATT_NO_RESOURCES;
604 }
605 */
606 return GATT_BUSY;
607 } else {
608
609 if ( (p_msg = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_IND, (tGATT_SR_MSG *)&indication)) != NULL) {
610 cmd_status = attp_send_sr_msg (p_tcb, p_msg);
611
612 if (cmd_status == GATT_SUCCESS || cmd_status == GATT_CONGESTED) {
613 p_tcb->indicate_handle = indication.handle;
614 gatt_start_conf_timer(p_tcb);
615 }
616 }
617 }
618 return cmd_status;
619 }
620
621 /*******************************************************************************
622 **
623 ** Function GATTS_HandleValueNotification
624 **
625 ** Description This function sends a handle value notification to a client.
626 **
627 ** Parameter conn_id: connection identifier.
628 ** attr_handle: Attribute handle of this handle value indication.
629 ** val_len: Length of the indicated attribute value.
630 ** p_val: Pointer to the indicated attribute value data.
631 **
632 ** Returns GATT_SUCCESS if successfully sent; otherwise error code.
633 **
634 *******************************************************************************/
GATTS_HandleValueNotification(UINT16 conn_id,UINT16 attr_handle,UINT16 val_len,UINT8 * p_val)635 tGATT_STATUS GATTS_HandleValueNotification (UINT16 conn_id, UINT16 attr_handle,
636 UINT16 val_len, UINT8 *p_val)
637 {
638 tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
639 BT_HDR *p_buf;
640 tGATT_VALUE notif;
641 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
642 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
643 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
644 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
645
646 GATT_TRACE_API ("GATTS_HandleValueNotification");
647
648 if ( (p_reg == NULL) || (p_tcb == NULL)) {
649 GATT_TRACE_ERROR ("GATTS_HandleValueNotification Unknown conn_id: %u \n", conn_id);
650 return (tGATT_STATUS) GATT_INVALID_CONN_ID;
651 }
652
653 if (GATT_HANDLE_IS_VALID (attr_handle)) {
654 notif.handle = attr_handle;
655 notif.len = val_len;
656 memcpy (notif.value, p_val, val_len);
657 notif.auth_req = GATT_AUTH_REQ_NONE;
658
659 if ((p_buf = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_NOTIF, (tGATT_SR_MSG *)¬if))
660 != NULL) {
661 cmd_sent = attp_send_sr_msg (p_tcb, p_buf);
662 } else {
663 cmd_sent = GATT_NO_RESOURCES;
664 }
665 }
666 return cmd_sent;
667 }
668
669 /*******************************************************************************
670 **
671 ** Function GATTS_SendRsp
672 **
673 ** Description This function sends the server response to client.
674 **
675 ** Parameter conn_id: connection identifier.
676 ** trans_id: transaction id
677 ** status: response status
678 ** p_msg: pointer to message parameters structure.
679 **
680 ** Returns GATT_SUCCESS if successfully sent; otherwise error code.
681 **
682 *******************************************************************************/
GATTS_SendRsp(UINT16 conn_id,UINT32 trans_id,tGATT_STATUS status,tGATTS_RSP * p_msg)683 tGATT_STATUS GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id,
684 tGATT_STATUS status, tGATTS_RSP *p_msg)
685 {
686 tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
687 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
688 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
689 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
690 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
691
692 GATT_TRACE_API ("GATTS_SendRsp: conn_id: %u trans_id: %u Status: 0x%04x\n",
693 conn_id, trans_id, status);
694
695 if ( (p_reg == NULL) || (p_tcb == NULL)) {
696 GATT_TRACE_ERROR ("GATTS_SendRsp Unknown conn_id: %u\n", conn_id);
697 return (tGATT_STATUS) GATT_INVALID_CONN_ID;
698 }
699
700 if (p_tcb->sr_cmd.trans_id != trans_id) {
701 GATT_TRACE_ERROR ("GATTS_SendRsp conn_id: %u waiting for op_code = %02x\n",
702 conn_id, p_tcb->sr_cmd.op_code);
703
704 return (GATT_WRONG_STATE);
705 }
706 /* Process App response */
707 cmd_sent = gatt_sr_process_app_rsp (p_tcb, gatt_if, trans_id, p_tcb->sr_cmd.op_code, status, p_msg);
708
709 return cmd_sent;
710 }
711
712
713 /*******************************************************************************
714 **
715 ** Function GATTS_SetAttributeValue
716 **
717 ** Description This function sends to set the attribute value .
718 **
719 ** Parameter attr_handle:the attribute handle
720 ** length: the attribute length
721 ** value: the value to be set to the attribute in the database
722 **
723 ** Returns GATT_SUCCESS if successfully sent; otherwise error code.
724 **
725 *******************************************************************************/
GATTS_SetAttributeValue(UINT16 attr_handle,UINT16 length,UINT8 * value)726 tGATT_STATUS GATTS_SetAttributeValue(UINT16 attr_handle, UINT16 length, UINT8 *value)
727 {
728 tGATT_STATUS status;
729 tGATT_HDL_LIST_ELEM *p_decl = NULL;
730
731 GATT_TRACE_DEBUG("GATTS_SetAttributeValue: attr_handle: %u length: %u \n",
732 attr_handle, length);
733 if (length <= 0){
734 return GATT_INVALID_ATTR_LEN;
735 }
736 if ((p_decl = gatt_find_hdl_buffer_by_attr_handle(attr_handle)) == NULL) {
737 GATT_TRACE_DEBUG("Service not created\n");
738 return GATT_INVALID_HANDLE;
739 }
740
741 status = gatts_set_attribute_value(&p_decl->svc_db, attr_handle, length, value);
742 return status;
743
744 }
745
746
747 /*******************************************************************************
748 **
749 ** Function GATTS_GetAttributeValue
750 **
751 ** Description This function sends to set the attribute value .
752 **
753 ** Parameter attr_handle: the attribute handle
754 ** length:the attribute value length in the database
755 ** value: the attribute value out put
756 **
757 ** Returns GATT_SUCCESS if successfully sent; otherwise error code.
758 **
759 *******************************************************************************/
GATTS_GetAttributeValue(UINT16 attr_handle,UINT16 * length,UINT8 ** value)760 tGATT_STATUS GATTS_GetAttributeValue(UINT16 attr_handle, UINT16 *length, UINT8 **value)
761 {
762 tGATT_STATUS status;
763 tGATT_HDL_LIST_ELEM *p_decl;
764
765 GATT_TRACE_DEBUG("GATTS_GetAttributeValue: attr_handle: %u\n",
766 attr_handle);
767
768 if ((p_decl = gatt_find_hdl_buffer_by_attr_handle(attr_handle)) == NULL) {
769 GATT_TRACE_ERROR("Service not created\n");
770 *length = 0;
771 return GATT_INVALID_HANDLE;
772 }
773
774 status = gatts_get_attribute_value(&p_decl->svc_db, attr_handle, length, value);
775 return status;
776 }
777 #endif ///GATTS_INCLUDED == TRUE
778
779
780 #if (GATTC_INCLUDED == TRUE)
781 /*******************************************************************************/
782 /* GATT Profile Srvr Functions */
783 /*******************************************************************************/
784
785 /*******************************************************************************/
786 /* */
787 /* GATT CLIENT APIs */
788 /* */
789 /*******************************************************************************/
790
791
792 /*******************************************************************************
793 **
794 ** Function GATTC_ConfigureMTU
795 **
796 ** Description This function is called to configure the ATT MTU size.
797 **
798 ** Parameters conn_id: connection identifier.
799 ** mtu - attribute MTU size..
800 **
801 ** Returns GATT_SUCCESS if command started successfully.
802 **
803 *******************************************************************************/
GATTC_ConfigureMTU(UINT16 conn_id)804 tGATT_STATUS GATTC_ConfigureMTU (UINT16 conn_id)
805 {
806 UINT8 ret = GATT_NO_RESOURCES;
807 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
808 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
809 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
810 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
811
812 tGATT_CLCB *p_clcb;
813 uint16_t mtu = gatt_get_local_mtu();
814
815 GATT_TRACE_API ("GATTC_ConfigureMTU conn_id=%d mtu=%d", conn_id, mtu );
816
817 if ( (p_tcb == NULL) || (p_reg == NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) || (mtu > GATT_MAX_MTU_SIZE)) {
818 return GATT_ILLEGAL_PARAMETER;
819 }
820
821 /* Validate that the link is BLE, not BR/EDR */
822 if (p_tcb->transport != BT_TRANSPORT_LE) {
823 return GATT_ERROR;
824 }
825
826 if (gatt_is_clcb_allocated(conn_id)) {
827 GATT_TRACE_ERROR("GATTC_ConfigureMTU GATT_BUSY conn_id = %d", conn_id);
828 return GATT_BUSY;
829 }
830
831 if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL) {
832 p_clcb->p_tcb->payload_size = mtu;
833 p_clcb->operation = GATTC_OPTYPE_CONFIG;
834
835 ret = attp_send_cl_msg (p_clcb->p_tcb, p_clcb->clcb_idx, GATT_REQ_MTU, (tGATT_CL_MSG *)&mtu);
836 }
837
838 return ret;
839 }
840
841 /*******************************************************************************
842 **
843 ** Function GATTC_Discover
844 **
845 ** Description This function is called to do a discovery procedure on ATT server.
846 **
847 ** Parameters conn_id: connection identifier.
848 ** disc_type:discovery type.
849 ** p_param: parameters of discovery requirement.
850 **
851 ** Returns GATT_SUCCESS if command received/sent successfully.
852 **
853 *******************************************************************************/
GATTC_Discover(UINT16 conn_id,tGATT_DISC_TYPE disc_type,tGATT_DISC_PARAM * p_param)854 tGATT_STATUS GATTC_Discover (UINT16 conn_id, tGATT_DISC_TYPE disc_type,
855 tGATT_DISC_PARAM *p_param)
856 {
857 tGATT_STATUS status = GATT_SUCCESS;
858 tGATT_CLCB *p_clcb;
859 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
860 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
861 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
862 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
863
864
865 GATT_TRACE_API ("GATTC_Discover conn_id=%d disc_type=%d", conn_id, disc_type);
866
867 if ( (p_tcb == NULL) || (p_reg == NULL) || (p_param == NULL) ||
868 (disc_type >= GATT_DISC_MAX)) {
869 GATT_TRACE_ERROR("GATTC_Discover Illegal param: disc_type %d conn_id = %d", disc_type, conn_id);
870 return GATT_ILLEGAL_PARAMETER;
871 }
872
873
874 if (gatt_is_clcb_allocated(conn_id)) {
875 GATT_TRACE_ERROR("GATTC_Discover GATT_BUSY conn_id = %d", conn_id);
876 return GATT_BUSY;
877 }
878
879
880 if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL ) {
881 if (!GATT_HANDLE_IS_VALID(p_param->s_handle) ||
882 !GATT_HANDLE_IS_VALID(p_param->e_handle) ||
883 /* search by type does not have a valid UUID param */
884 (disc_type == GATT_DISC_SRVC_BY_UUID &&
885 p_param->service.len == 0)) {
886 gatt_clcb_dealloc(p_clcb);
887 return GATT_ILLEGAL_PARAMETER;
888 }
889
890 p_clcb->operation = GATTC_OPTYPE_DISCOVERY;
891 p_clcb->op_subtype = disc_type;
892 p_clcb->s_handle = p_param->s_handle;
893 p_clcb->e_handle = p_param->e_handle;
894 p_clcb->uuid = p_param->service;
895
896 gatt_act_discovery(p_clcb);
897 } else {
898 status = GATT_NO_RESOURCES;
899 }
900 return status;
901 }
902
903 /*******************************************************************************
904 **
905 ** Function GATTC_Read
906 **
907 ** Description This function is called to read the value of an attribute from
908 ** the server.
909 **
910 ** Parameters conn_id: connection identifier.
911 ** type - attribute read type.
912 ** p_read - read operation parameters.
913 **
914 ** Returns GATT_SUCCESS if command started successfully.
915 **
916 *******************************************************************************/
GATTC_Read(UINT16 conn_id,tGATT_READ_TYPE type,tGATT_READ_PARAM * p_read)917 tGATT_STATUS GATTC_Read (UINT16 conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read)
918 {
919 tGATT_STATUS status = GATT_SUCCESS;
920 tGATT_CLCB *p_clcb;
921 tGATT_READ_MULTI *p_read_multi;
922 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
923 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
924 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
925 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
926
927
928 GATT_TRACE_API ("GATTC_Read conn_id=%d type=%d", conn_id, type);
929
930 if ( (p_tcb == NULL) || (p_reg == NULL) || (p_read == NULL) || ((type >= GATT_READ_MAX) || (type == 0))) {
931 GATT_TRACE_ERROR("GATT_Read Illegal param: conn_id %d, type 0%d,", conn_id, type);
932 return GATT_ILLEGAL_PARAMETER;
933 }
934
935 if (gatt_is_clcb_allocated(conn_id)) {
936 GATT_TRACE_ERROR("GATTC_Read GATT_BUSY conn_id = %d", conn_id);
937 return GATT_BUSY;
938 }
939
940 if ( (p_clcb = gatt_clcb_alloc(conn_id)) != NULL ) {
941 p_clcb->operation = GATTC_OPTYPE_READ;
942 p_clcb->op_subtype = type;
943 p_clcb->auth_req = p_read->by_handle.auth_req;
944 p_clcb->counter = 0;
945
946 switch (type) {
947 case GATT_READ_BY_TYPE:
948 case GATT_READ_CHAR_VALUE:
949 p_clcb->s_handle = p_read->service.s_handle;
950 p_clcb->e_handle = p_read->service.e_handle;
951 memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID));
952 break;
953 case GATT_READ_MULTIPLE:
954 p_clcb->s_handle = 0;
955 /* copy multiple handles in CB */
956 p_read_multi = (tGATT_READ_MULTI *)osi_malloc(sizeof(tGATT_READ_MULTI));
957 p_clcb->p_attr_buf = (UINT8 *)p_read_multi;
958 memcpy (p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI));
959 case GATT_READ_BY_HANDLE:
960 case GATT_READ_PARTIAL:
961 memset(&p_clcb->uuid, 0, sizeof(tBT_UUID));
962 p_clcb->s_handle = p_read->by_handle.handle;
963
964 if (type == GATT_READ_PARTIAL) {
965 p_clcb->counter = p_read->partial.offset;
966 }
967
968 break;
969 default:
970 break;
971 }
972 /* start security check */
973 if (gatt_security_check_start(p_clcb) == FALSE) {
974 status = GATT_NO_RESOURCES;
975 gatt_clcb_dealloc(p_clcb);
976 }
977 } else {
978 status = GATT_NO_RESOURCES;
979 }
980 return status;
981 }
982
983 /*******************************************************************************
984 **
985 ** Function GATTC_Write
986 **
987 ** Description This function is called to write the value of an attribute to
988 ** the server.
989 **
990 ** Parameters conn_id: connection identifier.
991 ** type - attribute write type.
992 ** p_write - write operation parameters.
993 **
994 ** Returns GATT_SUCCESS if command started successfully.
995 **
996 *******************************************************************************/
GATTC_Write(UINT16 conn_id,tGATT_WRITE_TYPE type,tGATT_VALUE * p_write)997 tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
998 {
999 tGATT_STATUS status = GATT_SUCCESS;
1000 tGATT_CLCB *p_clcb;
1001 tGATT_VALUE *p;
1002 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
1003 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
1004 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1005 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
1006
1007 if ( (p_tcb == NULL) || (p_reg == NULL) || (p_write == NULL) ||
1008 ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) ) {
1009 GATT_TRACE_ERROR("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type);
1010 return GATT_ILLEGAL_PARAMETER;
1011 }
1012
1013 if (gatt_is_clcb_allocated(conn_id)) {
1014 GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
1015 return GATT_BUSY;
1016 }
1017
1018 if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL ) {
1019 p_clcb->operation = GATTC_OPTYPE_WRITE;
1020 p_clcb->op_subtype = type;
1021 p_clcb->auth_req = p_write->auth_req;
1022
1023 if (( p_clcb->p_attr_buf = (UINT8 *)osi_malloc((UINT16)sizeof(tGATT_VALUE))) != NULL) {
1024 memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));
1025
1026 p = (tGATT_VALUE *)p_clcb->p_attr_buf;
1027 if (type == GATT_WRITE_PREPARE) {
1028 p_clcb->start_offset = p_write->offset;
1029 p->offset = 0;
1030 }
1031
1032 if (gatt_security_check_start(p_clcb) == FALSE) {
1033 status = GATT_NO_RESOURCES;
1034 }
1035 } else {
1036 status = GATT_NO_RESOURCES;
1037 }
1038
1039 if (status == GATT_NO_RESOURCES) {
1040 gatt_clcb_dealloc(p_clcb);
1041 }
1042 } else {
1043 status = GATT_NO_RESOURCES;
1044 }
1045 return status;
1046 }
1047
1048
1049 /*******************************************************************************
1050 **
1051 ** Function GATTC_ExecuteWrite
1052 **
1053 ** Description This function is called to send an Execute write request to
1054 ** the server.
1055 **
1056 ** Parameters conn_id: connection identifier.
1057 ** is_execute - to execute or cancel the prepare write request(s)
1058 **
1059 ** Returns GATT_SUCCESS if command started successfully.
1060 **
1061 *******************************************************************************/
GATTC_ExecuteWrite(UINT16 conn_id,BOOLEAN is_execute)1062 tGATT_STATUS GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute)
1063 {
1064 tGATT_STATUS status = GATT_SUCCESS;
1065 tGATT_CLCB *p_clcb;
1066 tGATT_EXEC_FLAG flag;
1067 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
1068 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
1069 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1070 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
1071
1072 GATT_TRACE_API ("GATTC_ExecuteWrite conn_id=%d is_execute=%d", conn_id, is_execute);
1073
1074 if ( (p_tcb == NULL) || (p_reg == NULL) ) {
1075 GATT_TRACE_ERROR("GATTC_ExecuteWrite Illegal param: conn_id %d", conn_id);
1076 return GATT_ILLEGAL_PARAMETER;
1077 }
1078
1079 if (gatt_is_clcb_allocated(conn_id)) {
1080 GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
1081 return GATT_BUSY;
1082 }
1083
1084 if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL) {
1085 p_clcb->operation = GATTC_OPTYPE_EXE_WRITE;
1086 flag = is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL;
1087 gatt_send_queue_write_cancel (p_clcb->p_tcb, p_clcb, flag);
1088 } else {
1089 GATT_TRACE_ERROR("Unable to allocate client CB for conn_id %d ", conn_id);
1090 status = GATT_NO_RESOURCES;
1091 }
1092 return status;
1093 }
1094
1095 /*******************************************************************************
1096 **
1097 ** Function GATTC_SendHandleValueConfirm
1098 **
1099 ** Description This function is called to send a handle value confirmation
1100 ** as response to a handle value notification from server.
1101 **
1102 ** Parameters conn_id: connection identifier.
1103 ** handle: the handle of the attribute confirmation.
1104 **
1105 ** Returns GATT_SUCCESS if command started successfully.
1106 **
1107 *******************************************************************************/
GATTC_SendHandleValueConfirm(UINT16 conn_id,UINT16 handle)1108 tGATT_STATUS GATTC_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle)
1109 {
1110 tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER;
1111 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id));
1112
1113 GATT_TRACE_API ("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id, handle);
1114
1115 if (p_tcb) {
1116 if (p_tcb->ind_count > 0 ) {
1117 btu_stop_timer (&p_tcb->ind_ack_timer_ent);
1118
1119 GATT_TRACE_DEBUG ("notif_count=%d ", p_tcb->ind_count);
1120 /* send confirmation now */
1121 ret = attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, (tGATT_CL_MSG *)&handle);
1122
1123 p_tcb->ind_count = 0;
1124
1125 } else {
1126 GATT_TRACE_DEBUG ("GATTC_SendHandleValueConfirm - conn_id: %u - ignored not waiting for indicaiton ack", conn_id);
1127 ret = GATT_SUCCESS;
1128 }
1129 } else {
1130 GATT_TRACE_ERROR ("GATTC_SendHandleValueConfirm - Unknown conn_id: %u", conn_id);
1131 }
1132 return ret;
1133 }
1134
1135 #endif ///GATTC_INCLUDED == TRUE
1136
1137 /*******************************************************************************/
1138 /* */
1139 /* GATT APIs */
1140 /* */
1141 /*******************************************************************************/
1142 /*******************************************************************************
1143 **
1144 ** Function GATT_SetIdleTimeout
1145 **
1146 ** Description This function (common to both client and server) sets the idle
1147 ** timeout for a tansport connection
1148 **
1149 ** Parameter bd_addr: target device bd address.
1150 ** idle_tout: timeout value in seconds.
1151 **
1152 ** Returns void
1153 **
1154 *******************************************************************************/
GATT_SetIdleTimeout(BD_ADDR bd_addr,UINT16 idle_tout,tBT_TRANSPORT transport)1155 void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout, tBT_TRANSPORT transport)
1156 {
1157 tGATT_TCB *p_tcb;
1158 BOOLEAN status = FALSE;
1159
1160 if ((p_tcb = gatt_find_tcb_by_addr (bd_addr, transport)) != NULL) {
1161 if (p_tcb->att_lcid == L2CAP_ATT_CID) {
1162 status = L2CA_SetFixedChannelTout (bd_addr, L2CAP_ATT_CID, idle_tout);
1163
1164 if (idle_tout == GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP) {
1165 L2CA_SetIdleTimeoutByBdAddr(p_tcb->peer_bda,
1166 GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP, BT_TRANSPORT_LE);
1167 }
1168 } else {
1169 status = L2CA_SetIdleTimeout (p_tcb->att_lcid, idle_tout, FALSE);
1170 }
1171 }
1172
1173 #if (CONFIG_BT_STACK_NO_LOG)
1174 (void) status;
1175 #endif
1176
1177 GATT_TRACE_API ("GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)",
1178 idle_tout, status);
1179 }
1180
1181
1182 /*******************************************************************************
1183 **
1184 ** Function GATT_Register
1185 **
1186 ** Description This function is called to register an application
1187 ** with GATT
1188 **
1189 ** Parameter p_app_uuid128: Application UUID
1190 ** p_cb_info: callback functions.
1191 **
1192 ** Returns 0 for error, otherwise the index of the client registered with GATT
1193 **
1194 *******************************************************************************/
GATT_Register(tBT_UUID * p_app_uuid128,const tGATT_CBACK * p_cb_info)1195 tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, const tGATT_CBACK *p_cb_info)
1196 {
1197 tGATT_REG *p_reg;
1198 UINT8 i_gatt_if = 0;
1199 tGATT_IF gatt_if = 0;
1200
1201 GATT_TRACE_API ("GATT_Register");
1202 gatt_dbg_display_uuid(*p_app_uuid128);
1203
1204 for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++) {
1205 if (p_reg->in_use && !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128, LEN_UUID_128)) {
1206 GATT_TRACE_ERROR("application already registered.");
1207 return 0;
1208 }
1209 }
1210
1211 for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++) {
1212 if (!p_reg->in_use) {
1213 memset(p_reg, 0 , sizeof(tGATT_REG));
1214 i_gatt_if++; /* one based number */
1215 p_reg->app_uuid128 = *p_app_uuid128;
1216 gatt_if =
1217 p_reg->gatt_if = (tGATT_IF)i_gatt_if;
1218 p_reg->app_cb = *p_cb_info;
1219 p_reg->in_use = TRUE;
1220
1221 break;
1222 }
1223 }
1224 GATT_TRACE_API ("allocated gatt_if=%d\n", gatt_if);
1225 return gatt_if;
1226 }
1227
1228
1229 /*******************************************************************************
1230 **
1231 ** Function GATT_Deregister
1232 **
1233 ** Description This function deregistered the application from GATT.
1234 **
1235 ** Parameters gatt_if: application interface.
1236 **
1237 ** Returns None.
1238 **
1239 *******************************************************************************/
GATT_Deregister(tGATT_IF gatt_if)1240 void GATT_Deregister (tGATT_IF gatt_if)
1241 {
1242 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
1243 tGATT_TCB *p_tcb;
1244 tGATT_CLCB *p_clcb;
1245 list_node_t *p_node = NULL;
1246 list_node_t *p_next = NULL;
1247 #if (GATTS_INCLUDED == TRUE)
1248 UINT8 ii;
1249 tGATT_SR_REG *p_sreg;
1250 #endif ///GATTS_INCLUDED == TRUE
1251 GATT_TRACE_API ("GATT_Deregister gatt_if=%d", gatt_if);
1252 /* Index 0 is GAP and is never deregistered */
1253 if ( (gatt_if == 0) || (p_reg == NULL) ) {
1254 GATT_TRACE_ERROR ("GATT_Deregister with invalid gatt_if: %u", gatt_if);
1255 return;
1256 }
1257
1258 /* stop all services */
1259 /* todo an applcaiton can not be deregistered if its services is also used by other application
1260 deregisteration need to bed performed in an orderly fashion
1261 no check for now */
1262 #if (GATTS_INCLUDED == TRUE)
1263 for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++) {
1264 if (p_sreg->in_use && (p_sreg->gatt_if == gatt_if)) {
1265 GATTS_StopService(p_sreg->s_hdl);
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 #endif ///GATTS_INCLUDED == TRUE
1271 /* When an application deregisters, check remove the link associated with the app */
1272
1273 for(p_node = list_begin(gatt_cb.p_tcb_list); p_node; p_node = p_next) {
1274 p_tcb = list_node(p_node);
1275 p_next = list_next(p_node);
1276 if (p_tcb->in_use) {
1277 if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE) {
1278 gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE);
1279 if (!gatt_num_apps_hold_link(p_tcb)) {
1280 /* this will disconnect the link or cancel the pending connect request at lower layer*/
1281 gatt_disconnect(p_tcb);
1282 }
1283 }
1284
1285 list_node_t *p_node_clcb = NULL;
1286 list_node_t *p_node_next = NULL;
1287 for(p_node_clcb = list_begin(gatt_cb.p_clcb_list); p_node_clcb; p_node_clcb = p_node_next) {
1288 p_clcb = list_node(p_node_clcb);
1289 p_node_next = list_next(p_node_clcb);
1290 if (p_clcb->in_use &&
1291 (p_clcb->p_reg->gatt_if == gatt_if) &&
1292 (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx)) {
1293 btu_stop_timer(&p_clcb->rsp_timer_ent);
1294 gatt_clcb_dealloc (p_clcb);
1295 break;
1296 }
1297 }
1298 }
1299 }
1300
1301 gatt_deregister_bgdev_list(gatt_if);
1302 /* update the listen mode */
1303 #if (defined(BLE_PERIPHERAL_MODE_SUPPORT) && (BLE_PERIPHERAL_MODE_SUPPORT == TRUE))
1304 GATT_Listen(gatt_if, FALSE, NULL);
1305 #endif
1306
1307 memset (p_reg, 0, sizeof(tGATT_REG));
1308 }
1309
1310
1311 /*******************************************************************************
1312 **
1313 ** Function GATT_StartIf
1314 **
1315 ** Description This function is called after registration to start receiving
1316 ** callbacks for registered interface. Function may call back
1317 ** with connection status and queued notifications
1318 **
1319 ** Parameter gatt_if: application interface.
1320 **
1321 ** Returns None.
1322 **
1323 *******************************************************************************/
GATT_StartIf(tGATT_IF gatt_if)1324 void GATT_StartIf (tGATT_IF gatt_if)
1325 {
1326 tGATT_REG *p_reg;
1327 tGATT_TCB *p_tcb;
1328 BD_ADDR bda;
1329 UINT8 start_idx, found_idx;
1330 UINT16 conn_id;
1331 tGATT_TRANSPORT transport ;
1332
1333 GATT_TRACE_API ("GATT_StartIf gatt_if=%d", gatt_if);
1334 if ((p_reg = gatt_get_regcb(gatt_if)) != NULL) {
1335 start_idx = 0;
1336 while (gatt_find_the_connected_bda(start_idx, bda, &found_idx, &transport)) {
1337 p_tcb = gatt_find_tcb_by_addr(bda, transport);
1338 if (p_reg->app_cb.p_conn_cb && p_tcb) {
1339 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
1340 (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0, transport);
1341 }
1342 start_idx = ++found_idx;
1343 }
1344 }
1345 }
1346
1347
1348 /*******************************************************************************
1349 **
1350 ** Function GATT_Connect
1351 **
1352 ** Description This function initiate a connection to a remote device on GATT
1353 ** channel.
1354 **
1355 ** Parameters gatt_if: application interface
1356 ** bd_addr: peer device address.
1357 ** bd_addr_type: peer device address type.
1358 ** is_direct: is a direct connection or a background auto connection
1359 **
1360 ** Returns TRUE if connection started; FALSE if connection start failure.
1361 **
1362 *******************************************************************************/
GATT_Connect(tGATT_IF gatt_if,BD_ADDR bd_addr,tBLE_ADDR_TYPE bd_addr_type,BOOLEAN is_direct,tBT_TRANSPORT transport,BOOLEAN is_aux)1363 BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, tBLE_ADDR_TYPE bd_addr_type,
1364 BOOLEAN is_direct, tBT_TRANSPORT transport, BOOLEAN is_aux)
1365 {
1366 tGATT_REG *p_reg;
1367 BOOLEAN status = FALSE;
1368
1369 GATT_TRACE_API ("GATT_Connect gatt_if=%d", gatt_if);
1370
1371 /* Make sure app is registered */
1372 if ((p_reg = gatt_get_regcb(gatt_if)) == NULL) {
1373 GATT_TRACE_ERROR("GATT_Connect - gatt_if =%d is not registered", gatt_if);
1374 return (FALSE);
1375 }
1376
1377 if (is_direct) {
1378 status = gatt_act_connect (p_reg, bd_addr, bd_addr_type, transport, is_aux);
1379 } else {
1380 if (transport == BT_TRANSPORT_LE) {
1381 status = gatt_update_auto_connect_dev(gatt_if, TRUE, bd_addr, TRUE);
1382 } else {
1383 GATT_TRACE_ERROR("Unsupported transport for background connection");
1384 }
1385 }
1386
1387 return status;
1388
1389 }
1390
1391 /*******************************************************************************
1392 **
1393 ** Function GATT_CancelConnect
1394 **
1395 ** Description This function terminate the connection initaition to a remote
1396 ** device on GATT channel.
1397 **
1398 ** Parameters gatt_if: client interface. If 0 used as unconditionally disconnect,
1399 ** typically used for direct connection cancellation.
1400 ** bd_addr: peer device address.
1401 **
1402 ** Returns TRUE if connection started; FALSE if connection start failure.
1403 **
1404 *******************************************************************************/
GATT_CancelConnect(tGATT_IF gatt_if,BD_ADDR bd_addr,BOOLEAN is_direct)1405 BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct)
1406 {
1407 tGATT_REG *p_reg;
1408 tGATT_TCB *p_tcb;
1409 BOOLEAN status = TRUE;
1410 tGATT_IF temp_gatt_if;
1411 UINT8 start_idx, found_idx;
1412
1413 GATT_TRACE_API ("GATT_CancelConnect gatt_if=%d", gatt_if);
1414
1415 if ((gatt_if != 0) && ((p_reg = gatt_get_regcb(gatt_if)) == NULL)) {
1416 GATT_TRACE_ERROR("GATT_CancelConnect - gatt_if =%d is not registered", gatt_if);
1417 return (FALSE);
1418 }
1419
1420 if (is_direct) {
1421 if (!gatt_if) {
1422 GATT_TRACE_DEBUG("GATT_CancelConnect - unconditional");
1423 start_idx = 0;
1424 /* only LE connection can be cancelled */
1425 p_tcb = gatt_find_tcb_by_addr(bd_addr, BT_TRANSPORT_LE);
1426 if (p_tcb && gatt_num_apps_hold_link(p_tcb)) {
1427 while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx, &temp_gatt_if)) {
1428 status = gatt_cancel_open(temp_gatt_if, bd_addr);
1429 start_idx = ++found_idx;
1430 }
1431 } else {
1432 GATT_TRACE_ERROR("GATT_CancelConnect - no app found");
1433 status = FALSE;
1434 }
1435 } else {
1436 status = gatt_cancel_open(gatt_if, bd_addr);
1437 }
1438 } else {
1439 if (!gatt_if) {
1440 if (gatt_get_num_apps_for_bg_dev(bd_addr)) {
1441 while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if)) {
1442 gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr);
1443 }
1444 } else {
1445 GATT_TRACE_ERROR("GATT_CancelConnect -no app associated with the bg device for unconditional removal");
1446 status = FALSE;
1447 }
1448 } else {
1449 status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
1450 }
1451 }
1452
1453 return status;
1454 }
1455
1456 /*******************************************************************************
1457 **
1458 ** Function GATT_Disconnect
1459 **
1460 ** Description This function disconnect the GATT channel for this registered
1461 ** application.
1462 **
1463 ** Parameters conn_id: connection identifier.
1464 **
1465 ** Returns GATT_SUCCESS if disconnected.
1466 **
1467 *******************************************************************************/
GATT_Disconnect(UINT16 conn_id)1468 tGATT_STATUS GATT_Disconnect (UINT16 conn_id)
1469 {
1470 tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER;
1471 tGATT_TCB *p_tcb = NULL;
1472 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
1473 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
1474
1475 GATT_TRACE_API ("GATT_Disconnect conn_id=%d ", conn_id);
1476
1477 p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1478
1479 if (p_tcb) {
1480 gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE);
1481 if (!gatt_num_apps_hold_link(p_tcb)) {
1482 gatt_disconnect(p_tcb);
1483 }
1484 ret = GATT_SUCCESS;
1485 }
1486 return ret;
1487 }
1488
1489 /*******************************************************************************
1490 **
1491 ** Function GATT_SendServiceChangeIndication
1492 **
1493 ** Description This function is to send a service change indication
1494 **
1495 ** Parameters bd_addr: peer device address.
1496 **
1497 ** Returns None.
1498 **
1499 *******************************************************************************/
GATT_SendServiceChangeIndication(BD_ADDR bd_addr)1500 tGATT_STATUS GATT_SendServiceChangeIndication (BD_ADDR bd_addr)
1501 {
1502 UINT8 start_idx, found_idx;
1503 BOOLEAN srv_chg_ind_pending = FALSE;
1504 tGATT_TCB *p_tcb;
1505 tBT_TRANSPORT transport;
1506 tGATT_STATUS status = GATT_NOT_FOUND;
1507 if (GATTS_SEND_SERVICE_CHANGE_MODE == GATTS_SEND_SERVICE_CHANGE_AUTO) {
1508 status = GATT_WRONG_STATE;
1509 GATT_TRACE_ERROR ("%s can't send service change indication manually, please configure the option through menuconfig", __func__);
1510 return status;
1511 }
1512
1513 if(bd_addr) {
1514 status = gatt_send_srv_chg_ind(bd_addr);
1515 } else {
1516 start_idx = 0;
1517 BD_ADDR addr;
1518 while (gatt_find_the_connected_bda(start_idx, addr, &found_idx, &transport)) {
1519 p_tcb = gatt_get_tcb_by_idx(found_idx);
1520 srv_chg_ind_pending = gatt_is_srv_chg_ind_pending(p_tcb);
1521
1522 if (!srv_chg_ind_pending) {
1523 status = gatt_send_srv_chg_ind(addr);
1524 } else {
1525 status = GATT_BUSY;
1526 GATT_TRACE_DEBUG("discard srv chg - already has one in the queue");
1527 }
1528 start_idx = ++found_idx;
1529 }
1530 }
1531
1532 return status;
1533 }
1534
1535 /*******************************************************************************
1536 **
1537 ** Function GATT_GetConnectionInfor
1538 **
1539 ** Description This function use conn_id to find its associated BD address and applciation
1540 ** interface
1541 **
1542 ** Parameters conn_id: connection id (input)
1543 ** p_gatt_if: application interface (output)
1544 ** bd_addr: peer device address. (output)
1545 **
1546 ** Returns TRUE the logical link information is found for conn_id
1547 **
1548 *******************************************************************************/
GATT_GetConnectionInfor(UINT16 conn_id,tGATT_IF * p_gatt_if,BD_ADDR bd_addr,tBT_TRANSPORT * p_transport)1549 BOOLEAN GATT_GetConnectionInfor(UINT16 conn_id, tGATT_IF *p_gatt_if, BD_ADDR bd_addr,
1550 tBT_TRANSPORT *p_transport)
1551 {
1552
1553 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
1554 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
1555 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
1556 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1557 BOOLEAN status = FALSE;
1558
1559 GATT_TRACE_API ("GATT_GetConnectionInfor conn_id=%d", conn_id);
1560
1561 if (p_tcb && p_reg ) {
1562 memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN);
1563 *p_gatt_if = gatt_if;
1564 *p_transport = p_tcb->transport;
1565 status = TRUE;
1566 }
1567 return status;
1568 }
1569
1570
1571 /*******************************************************************************
1572 **
1573 ** Function GATT_GetConnIdIfConnected
1574 **
1575 ** Description This function find the conn_id if the logical link for BD address
1576 ** and applciation interface is connected
1577 **
1578 ** Parameters gatt_if: application interface (input)
1579 ** bd_addr: peer device address. (input)
1580 ** p_conn_id: connection id (output)
1581 ** transport: transport option
1582 **
1583 ** Returns TRUE the logical link is connected
1584 **
1585 *******************************************************************************/
GATT_GetConnIdIfConnected(tGATT_IF gatt_if,BD_ADDR bd_addr,UINT16 * p_conn_id,tBT_TRANSPORT transport)1586 BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_conn_id,
1587 tBT_TRANSPORT transport)
1588 {
1589 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
1590 tGATT_TCB *p_tcb = gatt_find_tcb_by_addr(bd_addr, transport);
1591 BOOLEAN status = FALSE;
1592
1593 if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) ) {
1594 *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
1595 status = TRUE;
1596 }
1597
1598 GATT_TRACE_API ("GATT_GetConnIdIfConnected status=%d\n", status);
1599 return status;
1600 }
1601
1602
1603 /*******************************************************************************
1604 **
1605 ** Function GATT_Listen
1606 **
1607 ** Description This function start or stop LE advertisement and listen for
1608 ** connection.
1609 **
1610 ** Parameters gatt_if: application interface
1611 ** p_bd_addr: listen for specific address connection, or NULL for
1612 ** listen to all device connection.
1613 ** start: start or stop listening.
1614 **
1615 ** Returns TRUE if advertisement is started; FALSE if adv start failure.
1616 **
1617 *******************************************************************************/
GATT_Listen(tGATT_IF gatt_if,BOOLEAN start,BD_ADDR_PTR bd_addr)1618 BOOLEAN GATT_Listen (tGATT_IF gatt_if, BOOLEAN start, BD_ADDR_PTR bd_addr)
1619 {
1620 tGATT_REG *p_reg;
1621
1622 GATT_TRACE_API ("GATT_Listen gatt_if=%d", gatt_if);
1623
1624 /* Make sure app is registered */
1625 if ((p_reg = gatt_get_regcb(gatt_if)) == NULL) {
1626 GATT_TRACE_ERROR("GATT_Listen - gatt_if =%d is not registered", gatt_if);
1627 return (FALSE);
1628 }
1629
1630 if (bd_addr != NULL) {
1631 gatt_update_auto_connect_dev(gatt_if, start, bd_addr, FALSE);
1632 } else {
1633 p_reg->listening = start ? GATT_LISTEN_TO_ALL : GATT_LISTEN_TO_NONE;
1634 }
1635
1636 return gatt_update_listen_mode();
1637 }
1638
1639 #endif
1640