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