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