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