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_API0 ("GATTS_CreateService" );
155
156 if (p_reg == NULL)
157 {
158 GATT_TRACE_ERROR1 ("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_DEBUG0 ("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_ERROR2 ("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_ERROR0 ("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_ERROR0 ("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_DEBUG0 ("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_ERROR0 ("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_DEBUG6 ("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_DEBUG0("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_DEBUG0("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_DEBUG0("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_DEBUG2("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_DEBUG0("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 {
371 GATT_TRACE_DEBUG0("Illegal parameter");
372 return 0;
373 }
374
375 return gatts_add_char_descr(&p_decl->svc_db,
376 perm,
377 p_descr_uuid);
378
379 }
380 /*******************************************************************************
381 **
382 ** Function GATTS_DeleteService
383 **
384 ** Description This function is called to delete a service.
385 **
386 ** Parameter gatt_if : application interface
387 ** p_svc_uuid : service UUID
388 ** svc_inst : instance of the service inside the application
389 **
390 ** Returns TRUE if operation succeed, FALSE if handle block was not found.
391 **
392 *******************************************************************************/
GATTS_DeleteService(tGATT_IF gatt_if,tBT_UUID * p_svc_uuid,UINT16 svc_inst)393 BOOLEAN GATTS_DeleteService (tGATT_IF gatt_if, tBT_UUID *p_svc_uuid, UINT16 svc_inst)
394 {
395
396 tGATT_HDL_LIST_INFO *p_list_info= &gatt_cb.hdl_list_info;
397 tGATT_HDL_LIST_ELEM *p_list=NULL;
398 UINT8 i_sreg;
399 tGATTS_PENDING_NEW_SRV_START *p_buf;
400 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
401 tBT_UUID *p_app_uuid128;
402
403 GATT_TRACE_DEBUG0 ("GATTS_DeleteService");
404
405 if (p_reg == NULL)
406 {
407 GATT_TRACE_ERROR0 ("Applicaiton not foud");
408 return(FALSE);
409 }
410 p_app_uuid128 = &p_reg->app_uuid128;
411
412 if ((p_list = gatt_find_hdl_buffer_by_app_id(p_app_uuid128, p_svc_uuid, svc_inst)) == NULL)
413 {
414 GATT_TRACE_ERROR0 ("No Service found");
415 return(FALSE);
416 }
417
418 if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128,
419 &p_list->asgn_range.svc_uuid,
420 p_list->asgn_range.svc_inst)) != NULL)
421 {
422 GATT_TRACE_DEBUG0 ("Delete a new service changed item - the service has not yet started");
423 GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf));
424 }
425 else
426 {
427 gatt_proc_srv_chg();
428 }
429
430 if ((i_sreg = gatt_sr_find_i_rcb_by_app_id (p_app_uuid128,
431 p_svc_uuid,
432 svc_inst)) != GATT_MAX_SR_PROFILES)
433 {
434 GATTS_StopService(gatt_cb.sr_reg[i_sreg].s_hdl);
435 }
436
437 GATT_TRACE_DEBUG2 ("released handles s_hdl=%u e_hdl=%u",
438 p_list->asgn_range.s_handle , p_list->asgn_range.e_handle );
439
440 if ( (p_list->asgn_range.s_handle >= gatt_cb.hdl_cfg.app_start_hdl)
441 && gatt_cb.cb_info.p_nv_save_callback)
442 (*gatt_cb.cb_info.p_nv_save_callback)(FALSE, &p_list->asgn_range);
443
444 gatt_remove_an_item_from_list(p_list_info, p_list);
445 gatt_free_hdl_buffer(p_list);
446
447 return(TRUE);
448 }
449
450 /*******************************************************************************
451 **
452 ** Function GATTS_StartService
453 **
454 ** Description This function is called to start a service with GATT
455 **
456 ** Parameter gatt_if : service handle.
457 ** p_cback : application service callback functions.
458 ** sup_transport : supported transport(s) for this primary service
459 **
460 ** return GATT_SUCCESS if sucessfully started; otherwise error code.
461 **
462 *******************************************************************************/
GATTS_StartService(tGATT_IF gatt_if,UINT16 service_handle,tGATT_TRANSPORT sup_transport)463 tGATT_STATUS GATTS_StartService (tGATT_IF gatt_if, UINT16 service_handle,
464 tGATT_TRANSPORT sup_transport)
465 {
466 tGATT_SR_REG *p_sreg;
467 tGATT_HDL_LIST_ELEM *p_list=NULL;
468 UINT8 i_sreg;
469 tBT_UUID *p_uuid;
470 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
471
472 tGATTS_PENDING_NEW_SRV_START *p_buf;
473
474 GATT_TRACE_API0 ("GATTS_StartService");
475
476 if (p_reg == NULL)
477 {
478 /* Not found */
479 GATT_TRACE_ERROR0 ("Applicaiton not found ");
480 return GATT_NOT_FOUND;
481 }
482
483 if ((p_list = gatt_find_hdl_buffer_by_handle(service_handle)) == NULL)
484 {
485 /* Not found */
486 GATT_TRACE_ERROR0 ("no service found");
487 return GATT_NOT_FOUND;
488 }
489
490 if (gatt_sr_find_i_rcb_by_app_id (&p_list->asgn_range.app_uuid128,
491 &p_list->asgn_range.svc_uuid,
492 p_list->asgn_range.svc_inst) != GATT_MAX_SR_PROFILES)
493 {
494 GATT_TRACE_ERROR0 ("Duplicate Service start - Service already started");
495 return GATT_SERVICE_STARTED;
496 }
497
498 /*this is a new application servoce start */
499 if ((i_sreg = gatt_sr_alloc_rcb(p_list)) == GATT_MAX_SR_PROFILES)
500 {
501 GATT_TRACE_ERROR0 ("GATTS_StartService: no free server registration block");
502 return GATT_NO_RESOURCES;
503 }
504
505 p_sreg = &gatt_cb.sr_reg[i_sreg];
506 p_sreg->gatt_if = gatt_if;
507
508 switch (sup_transport)
509 {
510 case GATT_TRANSPORT_BR_EDR:
511 case GATT_TRANSPORT_LE_BR_EDR:
512 if (p_sreg->type == GATT_UUID_PRI_SERVICE)
513 {
514 p_uuid = gatts_get_service_uuid (p_sreg->p_db);
515
516 p_sreg->sdp_handle = gatt_add_sdp_record(p_uuid, p_sreg->s_hdl, p_sreg->e_hdl);
517 }
518 break;
519 default:
520 break;
521 }
522
523 gatts_update_srv_list_elem(i_sreg, p_sreg->s_hdl,
524 p_list->asgn_range.is_primary);
525
526 gatt_add_a_srv_to_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[i_sreg]);
527
528 GATT_TRACE_DEBUG1 ("allocated i_sreg=%d ",i_sreg);
529
530 GATT_TRACE_DEBUG5 ("s_hdl=%d e_hdl=%d type=0x%x svc_inst=%d sdp_hdl=0x%x",
531 p_sreg->s_hdl,p_sreg->e_hdl,
532 p_sreg->type, p_sreg->service_instance,
533 p_sreg->sdp_handle);
534
535
536 if ( (p_buf = gatt_sr_is_new_srv_chg(&p_list->asgn_range.app_uuid128,
537 &p_list->asgn_range.svc_uuid,
538 p_list->asgn_range.svc_inst)) != NULL)
539 {
540 gatt_proc_srv_chg();
541 /* remove the new service element after the srv changed processing is completed*/
542
543 GKI_freebuf (GKI_remove_from_queue (&gatt_cb.pending_new_srv_start_q, p_buf));
544 }
545 return GATT_SUCCESS;
546 }
547
548 /*******************************************************************************
549 **
550 ** Function GATTS_StopService
551 **
552 ** Description This function is called to stop a service
553 **
554 ** Parameter service_handle : this is the start handle of a service
555 **
556 ** Returns None.
557 **
558 *******************************************************************************/
GATTS_StopService(UINT16 service_handle)559 void GATTS_StopService (UINT16 service_handle)
560 {
561 UINT8 ii = gatt_sr_find_i_rcb_by_handle(service_handle);
562
563 GATT_TRACE_API1("GATTS_StopService %u", service_handle);
564
565 /* Index 0 is reserved for GATT, and is never stopped */
566 if ( (ii > 0) && (ii < GATT_MAX_SR_PROFILES) && (gatt_cb.sr_reg[ii].in_use) )
567 {
568 if (gatt_cb.sr_reg[ii].sdp_handle)
569 {
570 SDP_DeleteRecord(gatt_cb.sr_reg[ii].sdp_handle);
571 }
572 gatt_remove_a_srv_from_list(&gatt_cb.srv_list_info, &gatt_cb.srv_list[ii]);
573 gatt_cb.srv_list[ii].in_use = FALSE;
574 memset (&gatt_cb.sr_reg[ii], 0, sizeof(tGATT_SR_REG));
575 }
576 else
577 {
578 GATT_TRACE_ERROR1("GATTS_StopService service_handle: %u is not in use", service_handle);
579 }
580 }
581 /*******************************************************************************
582 **
583 ** Function GATTs_HandleValueIndication
584 **
585 ** Description This function sends a handle value indication to a client.
586 **
587 ** Parameter conn_id: connection identifier.
588 ** attr_handle: Attribute handle of this handle value indication.
589 ** val_len: Length of the indicated attribute value.
590 ** p_val: Pointer to the indicated attribute value data.
591 **
592 ** Returns GATT_SUCCESS if sucessfully sent or queued; otherwise error code.
593 **
594 *******************************************************************************/
GATTS_HandleValueIndication(UINT16 conn_id,UINT16 attr_handle,UINT16 val_len,UINT8 * p_val)595 tGATT_STATUS GATTS_HandleValueIndication (UINT16 conn_id, UINT16 attr_handle, UINT16 val_len, UINT8 *p_val)
596 {
597 tGATT_STATUS cmd_status = GATT_ILLEGAL_PARAMETER;
598
599 tGATT_VALUE indication;
600 BT_HDR *p_msg;
601 tGATT_VALUE *p_buf;
602 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
603 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
604 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
605 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
606
607
608 GATT_TRACE_API0 ("GATTS_HandleValueIndication");
609 if ( (p_reg == NULL) || (p_tcb == NULL))
610 {
611 GATT_TRACE_ERROR1 ("GATTS_HandleValueIndication Unknown conn_id: %u ", conn_id);
612 return(tGATT_STATUS) GATT_INVALID_CONN_ID;
613 }
614 indication.conn_id = conn_id;
615 indication.handle = attr_handle;
616 indication.len = val_len;
617 memcpy (indication.value, p_val, val_len);
618 indication.auth_req = GATT_AUTH_REQ_NONE;
619
620 if (GATT_HANDLE_IS_VALID (attr_handle) )
621 {
622 if (GATT_HANDLE_IS_VALID(p_tcb->indicate_handle))
623 {
624 GATT_TRACE_DEBUG0 ("Add a pending indication");
625 if ((p_buf = gatt_add_pending_ind(p_tcb, &indication)) !=NULL)
626 {
627 cmd_status = GATT_SUCCESS;
628 }
629 else
630 {
631 cmd_status = GATT_NO_RESOURCES;
632 }
633 }
634 else
635 {
636
637 if ( (p_msg = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_IND, (tGATT_SR_MSG *)&indication)) != NULL)
638 {
639 cmd_status = attp_send_sr_msg (p_tcb, p_msg);
640
641 if (cmd_status == GATT_SUCCESS)
642 {
643 p_tcb->indicate_handle = indication.handle;
644 gatt_start_conf_timer(p_tcb);
645 }
646 }
647 }
648 }
649 return cmd_status;
650 }
651
652 /*******************************************************************************
653 **
654 ** Function GATTS_HandleValueNotification
655 **
656 ** Description This function sends a handle value notification to a client.
657 **
658 ** Parameter conn_id: connection identifier.
659 ** attr_handle: Attribute handle of this handle value indication.
660 ** val_len: Length of the indicated attribute value.
661 ** p_val: Pointer to the indicated attribute value data.
662 **
663 ** Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
664 **
665 *******************************************************************************/
GATTS_HandleValueNotification(UINT16 conn_id,UINT16 attr_handle,UINT16 val_len,UINT8 * p_val)666 tGATT_STATUS GATTS_HandleValueNotification (UINT16 conn_id, UINT16 attr_handle,
667 UINT16 val_len, UINT8 *p_val)
668 {
669 tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
670 BT_HDR *p_buf;
671 tGATT_VALUE notif;
672 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
673 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
674 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
675 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
676
677 GATT_TRACE_API0 ("GATTS_HandleValueNotification");
678
679 if ( (p_reg == NULL) || (p_tcb == NULL))
680 {
681 GATT_TRACE_ERROR1 ("GATTS_HandleValueNotification Unknown conn_id: %u ", conn_id);
682 return(tGATT_STATUS) GATT_INVALID_CONN_ID;
683 }
684
685 if (GATT_HANDLE_IS_VALID (attr_handle))
686 {
687 notif.handle = attr_handle;
688 notif.len = val_len;
689 memcpy (notif.value, p_val, val_len);
690 notif.auth_req = GATT_AUTH_REQ_NONE;;
691
692 p_buf = attp_build_sr_msg (p_tcb, GATT_HANDLE_VALUE_NOTIF, (tGATT_SR_MSG *)¬if);
693 cmd_sent = attp_send_sr_msg (p_tcb, p_buf);
694 }
695 return cmd_sent;
696 }
697
698 /*******************************************************************************
699 **
700 ** Function GATTS_SendRsp
701 **
702 ** Description This function sends the server response to client.
703 **
704 ** Parameter conn_id: connection identifier.
705 ** trans_id: transaction id
706 ** status: response status
707 ** p_msg: pointer to message parameters structure.
708 **
709 ** Returns GATT_SUCCESS if sucessfully sent; otherwise error code.
710 **
711 *******************************************************************************/
GATTS_SendRsp(UINT16 conn_id,UINT32 trans_id,tGATT_STATUS status,tGATTS_RSP * p_msg)712 tGATT_STATUS GATTS_SendRsp (UINT16 conn_id, UINT32 trans_id,
713 tGATT_STATUS status, tGATTS_RSP *p_msg)
714 {
715 tGATT_STATUS cmd_sent = GATT_ILLEGAL_PARAMETER;
716 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
717 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
718 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
719 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
720
721 GATT_TRACE_API3 ("GATTS_SendRsp: conn_id: %u trans_id: %u Status: 0x%04x",
722 conn_id, trans_id, status);
723
724 if ( (p_reg == NULL) || (p_tcb == NULL))
725 {
726 GATT_TRACE_ERROR1 ("GATTS_SendRsp Unknown conn_id: %u ", conn_id);
727 return(tGATT_STATUS) GATT_INVALID_CONN_ID;
728 }
729
730 if (p_tcb->sr_cmd.trans_id != trans_id)
731 {
732 GATT_TRACE_ERROR2 ("GATTS_SendRsp conn_id: %u waiting for op_code = %02x",
733 conn_id, p_tcb->sr_cmd.op_code);
734
735 return(GATT_WRONG_STATE);
736 }
737 /* Process App response */
738 cmd_sent = gatt_sr_process_app_rsp (p_tcb, gatt_if, trans_id, p_tcb->sr_cmd.op_code, status, p_msg);
739
740 return cmd_sent;
741 }
742
743 /*******************************************************************************/
744 /* GATT Profile Srvr Functions */
745 /*******************************************************************************/
746
747 /*******************************************************************************/
748 /* */
749 /* GATT CLIENT APIs */
750 /* */
751 /*******************************************************************************/
752
753
754 /*******************************************************************************
755 **
756 ** Function GATTC_ConfigureMTU
757 **
758 ** Description This function is called to configure the ATT MTU size.
759 **
760 ** Parameters conn_id: connection identifier.
761 ** mtu - attribute MTU size..
762 **
763 ** Returns GATT_SUCCESS if command started successfully.
764 **
765 *******************************************************************************/
GATTC_ConfigureMTU(UINT16 conn_id,UINT16 mtu)766 tGATT_STATUS GATTC_ConfigureMTU (UINT16 conn_id, UINT16 mtu)
767 {
768 UINT8 ret = GATT_NO_RESOURCES;
769 tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
770 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
771 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
772 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
773
774 tGATT_CLCB *p_clcb;
775
776 GATT_TRACE_API2 ("GATTC_ConfigureMTU conn_id=%d mtu=%d", conn_id, mtu );
777
778 // Validate that the link is BLE, not BR/EDR
779 // ????
780
781 if ( (p_tcb == NULL) || (p_reg==NULL) || (mtu < GATT_DEF_BLE_MTU_SIZE) || (mtu > GATT_MAX_MTU_SIZE))
782 {
783 return GATT_ILLEGAL_PARAMETER;
784 }
785
786 if (gatt_is_clcb_allocated(conn_id))
787 {
788 GATT_TRACE_ERROR1("GATTC_ConfigureMTU GATT_BUSY conn_id = %d", conn_id);
789 return GATT_BUSY;
790 }
791
792 if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL)
793 {
794 p_clcb->p_tcb->payload_size = mtu;
795 p_clcb->operation = GATTC_OPTYPE_CONFIG;
796
797 ret = attp_send_cl_msg (p_clcb->p_tcb, p_clcb->clcb_idx, GATT_REQ_MTU, (tGATT_CL_MSG *)&mtu);
798 }
799
800 return ret;
801 }
802
803 /*******************************************************************************
804 **
805 ** Function GATTC_Discover
806 **
807 ** Description This function is called to do a discovery procedure on ATT server.
808 **
809 ** Parameters conn_id: connection identifier.
810 ** disc_type:discovery type.
811 ** p_param: parameters of discovery requirement.
812 **
813 ** Returns GATT_SUCCESS if command received/sent successfully.
814 **
815 *******************************************************************************/
GATTC_Discover(UINT16 conn_id,tGATT_DISC_TYPE disc_type,tGATT_DISC_PARAM * p_param)816 tGATT_STATUS GATTC_Discover (UINT16 conn_id, tGATT_DISC_TYPE disc_type,
817 tGATT_DISC_PARAM *p_param)
818 {
819 tGATT_STATUS status = GATT_SUCCESS;
820 tGATT_CLCB *p_clcb;
821 tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
822 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
823 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
824 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
825
826
827 GATT_TRACE_API2 ("GATTC_Discover conn_id=%d disc_type=%d",conn_id, disc_type);
828
829 if ( (p_tcb == NULL) || (p_reg==NULL) ||(p_param == NULL) ||
830 (disc_type >= GATT_DISC_MAX))
831 {
832 GATT_TRACE_ERROR2("GATTC_Discover Illegal param: disc_type %d conn_id = %d", disc_type, conn_id);
833 return GATT_ILLEGAL_PARAMETER;
834 }
835
836
837 if (gatt_is_clcb_allocated(conn_id))
838 {
839 GATT_TRACE_ERROR1("GATTC_Discover GATT_BUSY conn_id = %d", conn_id);
840 return GATT_BUSY;
841 }
842
843
844 if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
845 {
846 if (!GATT_HANDLE_IS_VALID(p_param->s_handle) ||
847 !GATT_HANDLE_IS_VALID(p_param->e_handle) ||
848 /* search by type does not have a valid UUID param */
849 (disc_type == GATT_DISC_SRVC_BY_UUID &&
850 p_param->service.len == 0))
851 {
852 return GATT_ILLEGAL_PARAMETER;
853 }
854
855 p_clcb->operation = GATTC_OPTYPE_DISCOVERY;
856 p_clcb->op_subtype = disc_type;
857 p_clcb->s_handle = p_param->s_handle;
858 p_clcb->e_handle = p_param->e_handle;
859 p_clcb->uuid = p_param->service;
860
861 gatt_act_discovery(p_clcb);
862 }
863 else
864 {
865 status = GATT_NO_RESOURCES;
866 }
867 return status;
868 }
869
870 /*******************************************************************************
871 **
872 ** Function GATTC_Read
873 **
874 ** Description This function is called to read the value of an attribute from
875 ** the server.
876 **
877 ** Parameters conn_id: connection identifier.
878 ** type - attribute read type.
879 ** p_read - read operation parameters.
880 **
881 ** Returns GATT_SUCCESS if command started successfully.
882 **
883 *******************************************************************************/
GATTC_Read(UINT16 conn_id,tGATT_READ_TYPE type,tGATT_READ_PARAM * p_read)884 tGATT_STATUS GATTC_Read (UINT16 conn_id, tGATT_READ_TYPE type, tGATT_READ_PARAM *p_read)
885 {
886 tGATT_STATUS status = GATT_SUCCESS;
887 tGATT_CLCB *p_clcb;
888 tGATT_READ_MULTI *p_read_multi;
889 tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
890 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
891 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
892 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
893
894
895 GATT_TRACE_API2 ("GATTC_Read conn_id=%d type=%d", conn_id, type);
896
897 if ( (p_tcb == NULL) || (p_reg==NULL) || (p_read == NULL) || ((type >= GATT_READ_MAX) || (type == 0)))
898 {
899 GATT_TRACE_ERROR2("GATT_Read Illegal param: conn_id %d, type 0%d,", conn_id, type);
900 return GATT_ILLEGAL_PARAMETER;
901 }
902
903 if (gatt_is_clcb_allocated(conn_id))
904 {
905 GATT_TRACE_ERROR1("GATTC_Read GATT_BUSY conn_id = %d", conn_id);
906 return GATT_BUSY;
907 }
908
909 if ( (p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
910 {
911 p_clcb->operation = GATTC_OPTYPE_READ;
912 p_clcb->op_subtype = type;
913 p_clcb->auth_req = p_read->by_handle.auth_req;
914 p_clcb->counter = 0;
915
916 switch (type)
917 {
918 case GATT_READ_BY_TYPE:
919 case GATT_READ_CHAR_VALUE:
920 p_clcb->s_handle = p_read->service.s_handle;
921 p_clcb->e_handle = p_read->service.e_handle;
922 memcpy(&p_clcb->uuid, &p_read->service.uuid, sizeof(tBT_UUID));
923 break;
924 case GATT_READ_MULTIPLE:
925 p_clcb->s_handle = 0;
926 /* copy multiple handles in CB */
927 p_read_multi = (tGATT_READ_MULTI *)GKI_getbuf(sizeof(tGATT_READ_MULTI));
928 p_clcb->p_attr_buf = (UINT8*)p_read_multi;
929 memcpy (p_read_multi, &p_read->read_multiple, sizeof(tGATT_READ_MULTI));
930 case GATT_READ_BY_HANDLE:
931 case GATT_READ_PARTIAL:
932 memset(&p_clcb->uuid, 0, sizeof(tBT_UUID));
933 p_clcb->s_handle = p_read->by_handle.handle;
934
935 if (type == GATT_READ_PARTIAL)
936 {
937 p_clcb->counter = p_read->partial.offset;
938 }
939
940 break;
941 default:
942 break;
943 }
944 /* start security check */
945 if (gatt_security_check_start(p_clcb) == FALSE)
946 {
947 status = GATT_NO_RESOURCES;
948 gatt_clcb_dealloc(p_clcb);
949 }
950 }
951 else
952 {
953 status = GATT_NO_RESOURCES;
954 }
955 return status;
956 }
957
958 /*******************************************************************************
959 **
960 ** Function GATTC_Write
961 **
962 ** Description This function is called to write the value of an attribute to
963 ** the server.
964 **
965 ** Parameters conn_id: connection identifier.
966 ** type - attribute write type.
967 ** p_write - write operation parameters.
968 **
969 ** Returns GATT_SUCCESS if command started successfully.
970 **
971 *******************************************************************************/
GATTC_Write(UINT16 conn_id,tGATT_WRITE_TYPE type,tGATT_VALUE * p_write)972 tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
973 {
974 tGATT_STATUS status = GATT_SUCCESS;
975 tGATT_CLCB *p_clcb;
976 tGATT_VALUE *p;
977 tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
978 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
979 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
980 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
981
982 if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) ||
983 ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) )
984 {
985 GATT_TRACE_ERROR2("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type);
986 return GATT_ILLEGAL_PARAMETER;
987 }
988
989 if (gatt_is_clcb_allocated(conn_id))
990 {
991 GATT_TRACE_ERROR1("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
992 return GATT_BUSY;
993 }
994
995 if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
996 {
997 p_clcb->operation = GATTC_OPTYPE_WRITE;
998 p_clcb->op_subtype = type;
999 p_clcb->auth_req = p_write->auth_req;
1000
1001 if (( p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL)
1002 {
1003 memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));
1004
1005 p = (tGATT_VALUE *)p_clcb->p_attr_buf;
1006 if (type == GATT_WRITE_PREPARE)
1007 {
1008 p_clcb->start_offset = p_write->offset;
1009 p->offset = 0;
1010 }
1011
1012 if (gatt_security_check_start(p_clcb) == FALSE)
1013 {
1014 status = GATT_NO_RESOURCES;
1015 }
1016 }
1017 else
1018 {
1019 status = GATT_NO_RESOURCES;
1020 }
1021
1022 if (status == GATT_NO_RESOURCES)
1023 gatt_clcb_dealloc(p_clcb);
1024 }
1025 else
1026 {
1027 status = GATT_NO_RESOURCES;
1028 }
1029 return status;
1030 }
1031
1032
1033 /*******************************************************************************
1034 **
1035 ** Function GATTC_ExecuteWrite
1036 **
1037 ** Description This function is called to send an Execute write request to
1038 ** the server.
1039 **
1040 ** Parameters conn_id: connection identifier.
1041 ** is_execute - to execute or cancel the prepare write requet(s)
1042 **
1043 ** Returns GATT_SUCCESS if command started successfully.
1044 **
1045 *******************************************************************************/
GATTC_ExecuteWrite(UINT16 conn_id,BOOLEAN is_execute)1046 tGATT_STATUS GATTC_ExecuteWrite (UINT16 conn_id, BOOLEAN is_execute)
1047 {
1048 tGATT_STATUS status = GATT_SUCCESS;
1049 tGATT_CLCB *p_clcb;
1050 tGATT_EXEC_FLAG flag;
1051 tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
1052 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
1053 tGATT_TCB *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1054 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
1055
1056 GATT_TRACE_API2 ("GATTC_ExecuteWrite conn_id=%d is_execute=%d", conn_id, is_execute);
1057
1058 if ( (p_tcb == NULL) || (p_reg==NULL) )
1059 {
1060 GATT_TRACE_ERROR1("GATTC_ExecuteWrite Illegal param: conn_id %d", conn_id);
1061 return GATT_ILLEGAL_PARAMETER;
1062 }
1063
1064 if (gatt_is_clcb_allocated(conn_id))
1065 {
1066 GATT_TRACE_ERROR1("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
1067 return GATT_BUSY;
1068 }
1069
1070 if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL)
1071 {
1072 p_clcb->operation = GATTC_OPTYPE_EXE_WRITE;
1073 flag = is_execute ? GATT_PREP_WRITE_EXEC : GATT_PREP_WRITE_CANCEL;
1074 gatt_send_queue_write_cancel (p_clcb->p_tcb, p_clcb, flag);
1075 }
1076 else
1077 {
1078 GATT_TRACE_ERROR1("Unable to allocate client CB for conn_id %d ", conn_id);
1079 status = GATT_NO_RESOURCES;
1080 }
1081 return status;
1082 }
1083
1084 /*******************************************************************************
1085 **
1086 ** Function GATTC_SendHandleValueConfirm
1087 **
1088 ** Description This function is called to send a handle value confirmation
1089 ** as response to a handle value notification from server.
1090 **
1091 ** Parameters conn_id: connection identifier.
1092 ** handle: the handle of the attribute confirmation.
1093 **
1094 ** Returns GATT_SUCCESS if command started successfully.
1095 **
1096 *******************************************************************************/
GATTC_SendHandleValueConfirm(UINT16 conn_id,UINT16 handle)1097 tGATT_STATUS GATTC_SendHandleValueConfirm (UINT16 conn_id, UINT16 handle)
1098 {
1099 tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER;
1100 tGATT_TCB *p_tcb=gatt_get_tcb_by_idx(GATT_GET_TCB_IDX(conn_id));
1101
1102 GATT_TRACE_API2 ("GATTC_SendHandleValueConfirm conn_id=%d handle=0x%x", conn_id, handle);
1103
1104 if (p_tcb)
1105 {
1106 if (p_tcb->ind_count > 0 )
1107 {
1108 btu_stop_timer (&p_tcb->ind_ack_timer_ent);
1109
1110 GATT_TRACE_DEBUG1 ("notif_count=%d ", p_tcb->ind_count);
1111 /* send confirmation now */
1112 ret = attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, (tGATT_CL_MSG *)&handle);
1113
1114 p_tcb->ind_count = 0;
1115
1116 }
1117 else
1118 {
1119 GATT_TRACE_DEBUG1 ("GATTC_SendHandleValueConfirm - conn_id: %u - ignored not waiting for indicaiton ack", conn_id);
1120 ret = GATT_SUCCESS;
1121 }
1122 }
1123 else
1124 {
1125 GATT_TRACE_ERROR1 ("GATTC_SendHandleValueConfirm - Unknown conn_id: %u", conn_id);
1126 }
1127 return ret;
1128 }
1129
1130
1131 /*******************************************************************************/
1132 /* */
1133 /* GATT APIs */
1134 /* */
1135 /*******************************************************************************/
1136 /*******************************************************************************
1137 **
1138 ** Function GATT_SetIdleTimeout
1139 **
1140 ** Description This function (common to both client and server) sets the idle
1141 ** timeout for a tansport connection
1142 **
1143 ** Parameter bd_addr: target device bd address.
1144 ** idle_tout: timeout value in seconds.
1145 **
1146 ** Returns void
1147 **
1148 *******************************************************************************/
GATT_SetIdleTimeout(BD_ADDR bd_addr,UINT16 idle_tout)1149 void GATT_SetIdleTimeout (BD_ADDR bd_addr, UINT16 idle_tout)
1150 {
1151 tGATT_TCB *p_tcb;
1152 BOOLEAN status = FALSE;
1153
1154 if ((p_tcb = gatt_find_tcb_by_addr (bd_addr)) != NULL)
1155 {
1156 if (p_tcb->att_lcid == L2CAP_ATT_CID)
1157 {
1158 status = L2CA_SetFixedChannelTout (bd_addr, L2CAP_ATT_CID, idle_tout);
1159 }
1160 else
1161 {
1162 status = L2CA_SetIdleTimeout (p_tcb->att_lcid, idle_tout, FALSE);
1163 }
1164 }
1165
1166 GATT_TRACE_API2 ("GATT_SetIdleTimeout idle_tout=%d status=%d(1-OK 0-not performed)",
1167 idle_tout, status);
1168 }
1169
1170
1171 /*******************************************************************************
1172 **
1173 ** Function GATT_Register
1174 **
1175 ** Description This function is called to register an application
1176 ** with GATT
1177 **
1178 ** Parameter p_app_uuid128: Application UUID
1179 ** p_cb_info: callback functions.
1180 **
1181 ** Returns 0 for error, otherwise the index of the client registered with GATT
1182 **
1183 *******************************************************************************/
GATT_Register(tBT_UUID * p_app_uuid128,tGATT_CBACK * p_cb_info)1184 tGATT_IF GATT_Register (tBT_UUID *p_app_uuid128, tGATT_CBACK *p_cb_info)
1185 {
1186 tGATT_REG *p_reg;
1187 UINT8 i_gatt_if=0;
1188 tGATT_IF gatt_if=0;
1189
1190 GATT_TRACE_API0 ("GATT_Register");
1191 gatt_dbg_display_uuid(*p_app_uuid128);
1192
1193 for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
1194 {
1195 if (p_reg->in_use && !memcmp(p_app_uuid128->uu.uuid128, p_reg->app_uuid128.uu.uuid128, LEN_UUID_128))
1196 {
1197 GATT_TRACE_ERROR0("application already registered.");
1198 return 0;
1199 }
1200 }
1201
1202 for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS; i_gatt_if++, p_reg++)
1203 {
1204 if (!p_reg->in_use)
1205 {
1206 memset(p_reg, 0 , sizeof(tGATT_REG));
1207 i_gatt_if++; /* one based number */
1208 p_reg->app_uuid128 = *p_app_uuid128;
1209 gatt_if =
1210 p_reg->gatt_if = (tGATT_IF)i_gatt_if;
1211 p_reg->app_cb = *p_cb_info;
1212 p_reg->in_use = TRUE;
1213
1214 break;
1215 }
1216 }
1217 GATT_TRACE_API1 ("allocated gatt_if=%d", gatt_if);
1218 return gatt_if;
1219 }
1220
1221
1222 /*******************************************************************************
1223 **
1224 ** Function GATT_Deregister
1225 **
1226 ** Description This function deregistered the application from GATT.
1227 **
1228 ** Parameters gatt_if: applicaiton interface.
1229 **
1230 ** Returns None.
1231 **
1232 *******************************************************************************/
GATT_Deregister(tGATT_IF gatt_if)1233 void GATT_Deregister (tGATT_IF gatt_if)
1234 {
1235 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
1236 tGATT_TCB *p_tcb;
1237 tGATT_CLCB *p_clcb;
1238 UINT8 i, ii, j;
1239 tGATT_SR_REG *p_sreg;
1240
1241 GATT_TRACE_API1 ("GATT_Deregister gatt_if=%d", gatt_if);
1242 /* Index 0 is GAP and is never deregistered */
1243 if ( (gatt_if == 0) || (p_reg == NULL) )
1244 {
1245 GATT_TRACE_ERROR1 ("GATT_Deregister with invalid gatt_if: %u", gatt_if);
1246 return;
1247 }
1248
1249 /* stop all services */
1250 /* todo an applcaiton can not be deregistered if its services is also used by other application
1251 deregisteration need to bed performed in an orderly fashion
1252 no check for now */
1253
1254 for (ii = 0, p_sreg = gatt_cb.sr_reg; ii < GATT_MAX_SR_PROFILES; ii++, p_sreg++)
1255 {
1256 if (p_sreg->in_use && (p_sreg->gatt_if == gatt_if))
1257 {
1258 GATTS_StopService(p_sreg->s_hdl);
1259 }
1260 }
1261
1262 /* free all services db buffers if owned by this application */
1263 gatt_free_srvc_db_buffer_app_id(&p_reg->app_uuid128);
1264
1265 /* When an application deregisters, check remove the link associated with the app */
1266
1267 for (i=0, p_tcb = gatt_cb.tcb; i < GATT_MAX_PHY_CHANNEL; i++, p_tcb++)
1268 {
1269 if (p_tcb->in_use)
1270 {
1271 if (gatt_get_ch_state(p_tcb) != GATT_CH_CLOSE)
1272 {
1273 gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE);
1274 if (!gatt_num_apps_hold_link(p_tcb))
1275 {
1276 /* this will disconnect the link or cancel the pending connect request at lower layer*/
1277 gatt_disconnect(p_tcb->peer_bda);
1278 }
1279 }
1280
1281 for (j = 0, p_clcb= &gatt_cb.clcb[j]; j < GATT_CL_MAX_LCB; j++, p_clcb++)
1282 {
1283 if (p_clcb->in_use &&
1284 (p_clcb->p_reg->gatt_if == gatt_if) &&
1285 (p_clcb->p_tcb->tcb_idx == p_tcb->tcb_idx))
1286 {
1287 gatt_clcb_dealloc (p_clcb);
1288 break;
1289 }
1290 }
1291 }
1292 }
1293
1294 gatt_deregister_bgdev_list(gatt_if);
1295 memset (p_reg, 0, sizeof(tGATT_REG));
1296 }
1297
1298
1299 /*******************************************************************************
1300 **
1301 ** Function GATT_StartIf
1302 **
1303 ** Description This function is called after registration to start receiving
1304 ** callbacks for registered interface. Function may call back
1305 ** with connection status and queued notifications
1306 **
1307 ** Parameter gatt_if: applicaiton interface.
1308 **
1309 ** Returns 0 for error, otherwise the index of the client registered with GATT
1310 **
1311 *******************************************************************************/
GATT_StartIf(tGATT_IF gatt_if)1312 void GATT_StartIf (tGATT_IF gatt_if)
1313 {
1314 tGATT_REG *p_reg;
1315 tGATT_TCB *p_tcb;
1316 //tGATT_CLCB *p_clcb;
1317 BD_ADDR bda;
1318 UINT8 start_idx, found_idx;
1319 UINT16 conn_id;
1320
1321 GATT_TRACE_API1 ("GATT_StartIf gatt_if=%d", gatt_if);
1322 if ((p_reg = gatt_get_regcb(gatt_if)) != NULL)
1323 {
1324 p_reg = &gatt_cb.cl_rcb[gatt_if - 1];
1325 start_idx = 0;
1326 while (gatt_find_the_connected_bda(start_idx, bda, &found_idx))
1327 {
1328 p_tcb = gatt_find_tcb_by_addr(bda);
1329 if (p_reg->app_cb.p_conn_cb)
1330 {
1331 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
1332 (*p_reg->app_cb.p_conn_cb)(gatt_if, bda, conn_id, TRUE, 0);
1333 }
1334 start_idx = ++found_idx;
1335 }
1336 }
1337 }
1338
1339
1340 /*******************************************************************************
1341 **
1342 ** Function GATT_Connect
1343 **
1344 ** Description This function initiate a connecttion to a ATT server.
1345 **
1346 ** Parameters gatt_if: applicaiton interface
1347 ** bd_addr: peer device address.
1348 ** is_direct: is a direct conenection or a background auto connection
1349 **
1350 ** Returns TRUE if connection started; FALSE if connection start failure.
1351 **
1352 *******************************************************************************/
GATT_Connect(tGATT_IF gatt_if,BD_ADDR bd_addr,BOOLEAN is_direct)1353 BOOLEAN GATT_Connect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){
1354 tGATT_REG *p_reg;
1355 BOOLEAN status;
1356
1357 GATT_TRACE_API1 ("GATT_Connect gatt_if=%d", gatt_if);
1358
1359 /* Make sure app is registered */
1360 if ((p_reg = gatt_get_regcb(gatt_if)) == NULL)
1361 {
1362 GATT_TRACE_ERROR1("GATT_Connect - gatt_if =%d is not registered", gatt_if);
1363 return(FALSE);
1364 }
1365
1366 if (is_direct)
1367 status = gatt_act_connect (p_reg, bd_addr);
1368 else
1369 status = gatt_update_auto_connect_dev(gatt_if,TRUE, bd_addr);
1370
1371 return status;
1372
1373 }
1374
1375 /*******************************************************************************
1376 **
1377 ** Function GATT_CancelConnect
1378 **
1379 ** Description This function initiate a connecttion to a ATT server.
1380 **
1381 ** Parameters gatt_if: client interface. If 0 used as unconditionally disconnect,
1382 ** typically used for direct connection cancellation.
1383 ** bd_addr: peer device address.
1384 **
1385 ** Returns TRUE if connection started; FALSE if connection start failure.
1386 **
1387 *******************************************************************************/
GATT_CancelConnect(tGATT_IF gatt_if,BD_ADDR bd_addr,BOOLEAN is_direct)1388 BOOLEAN GATT_CancelConnect (tGATT_IF gatt_if, BD_ADDR bd_addr, BOOLEAN is_direct){
1389 tGATT_REG *p_reg;
1390 tGATT_TCB *p_tcb;
1391 BOOLEAN status = TRUE;
1392 tGATT_IF temp_gatt_if;
1393 UINT8 start_idx, found_idx;
1394
1395 GATT_TRACE_API1 ("GATT_CancelConnect gatt_if=%d", gatt_if);
1396
1397 if ((gatt_if != 0) && ((p_reg = gatt_get_regcb(gatt_if)) == NULL))
1398 {
1399 GATT_TRACE_ERROR1("GATT_CancelConnect - gatt_if =%d is not registered", gatt_if);
1400 return(FALSE);
1401 }
1402
1403 if (is_direct)
1404 {
1405 if (!gatt_if)
1406 {
1407 GATT_TRACE_DEBUG0("GATT_CancelConnect - unconditional");
1408 start_idx = 0;
1409 p_tcb = gatt_find_tcb_by_addr(bd_addr);
1410 if (p_tcb && gatt_num_apps_hold_link(p_tcb))
1411 {
1412 while (status && gatt_find_app_hold_link(p_tcb, start_idx, &found_idx, &temp_gatt_if))
1413 {
1414 status = gatt_cancel_open(temp_gatt_if, bd_addr);
1415 start_idx = ++found_idx;
1416 }
1417 }
1418 else
1419 {
1420 GATT_TRACE_ERROR0("GATT_CancelConnect - no app found");
1421 status = FALSE;
1422 }
1423 }
1424 else
1425 {
1426 status = gatt_cancel_open(gatt_if, bd_addr);
1427 }
1428 }
1429 else
1430 {
1431 if (!gatt_if)
1432 {
1433 if (gatt_get_num_apps_for_bg_dev(bd_addr))
1434 {
1435 while (gatt_find_app_for_bg_dev(bd_addr, &temp_gatt_if))
1436 gatt_remove_bg_dev_for_app(temp_gatt_if, bd_addr);
1437 }
1438 else
1439 {
1440 GATT_TRACE_ERROR0("GATT_CancelConnect -no app associated with the bg device for unconditional removal");
1441 status = FALSE;
1442 }
1443 }
1444 else
1445 {
1446 status = gatt_remove_bg_dev_for_app(gatt_if, bd_addr);
1447 }
1448 }
1449
1450 return status;
1451 }
1452
1453 /*******************************************************************************
1454 **
1455 ** Function GATT_Disconnect
1456 **
1457 ** Description This function disconnect a logic channel.
1458 **
1459 ** Parameters conn_id: connection identifier.
1460 **
1461 ** Returns GATT_SUCCESS if disconnected.
1462 **
1463 *******************************************************************************/
GATT_Disconnect(UINT16 conn_id)1464 tGATT_STATUS GATT_Disconnect (UINT16 conn_id)
1465 {
1466 tGATT_STATUS ret = GATT_ILLEGAL_PARAMETER;
1467 tGATT_TCB *p_tcb=NULL;
1468 tGATT_IF gatt_if=GATT_GET_GATT_IF(conn_id);
1469 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
1470
1471 GATT_TRACE_API1 ("GATT_Disconnect conn_id=%d ", conn_id);
1472
1473 p_tcb = gatt_get_tcb_by_idx(tcb_idx);
1474
1475 if (p_tcb)
1476 {
1477 gatt_update_app_use_link_flag(gatt_if, p_tcb, FALSE, FALSE);
1478 if (!gatt_num_apps_hold_link(p_tcb))
1479 {
1480 gatt_disconnect(p_tcb->peer_bda);
1481 }
1482 ret = GATT_SUCCESS;
1483 }
1484 return ret;
1485 }
1486
1487
1488 /*******************************************************************************
1489 **
1490 ** Function GATT_GetConnectionInfor
1491 **
1492 ** Description This function use conn_id to find its associated BD address and applciation
1493 ** interface
1494 **
1495 ** Parameters conn_id: connection id (input)
1496 ** p_gatt_if: applicaiton interface (output)
1497 ** bd_addr: peer device address. (output)
1498 **
1499 ** Returns TRUE the ligical link information is found for conn_id
1500 **
1501 *******************************************************************************/
GATT_GetConnectionInfor(UINT16 conn_id,tGATT_IF * p_gatt_if,BD_ADDR bd_addr)1502 BOOLEAN GATT_GetConnectionInfor(UINT16 conn_id, tGATT_IF *p_gatt_if, BD_ADDR bd_addr)
1503 {
1504
1505 tGATT_IF gatt_if = GATT_GET_GATT_IF(conn_id);
1506 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
1507 UINT8 tcb_idx = GATT_GET_TCB_IDX(conn_id);
1508 tGATT_TCB *p_tcb= gatt_get_tcb_by_idx(tcb_idx);
1509 BOOLEAN status=FALSE;
1510
1511 GATT_TRACE_API1 ("GATT_GetConnectionInfor conn_id=%d", conn_id);
1512
1513 if (p_tcb && p_reg )
1514 {
1515 memcpy(bd_addr, p_tcb->peer_bda, BD_ADDR_LEN);
1516 *p_gatt_if = gatt_if;
1517 status = TRUE;
1518 }
1519 return status;
1520 }
1521
1522
1523 /*******************************************************************************
1524 **
1525 ** Function GATT_GetConnIdIfConnected
1526 **
1527 ** Description This function find the conn_id if the logical link for BD address
1528 ** and applciation interface is connected
1529 **
1530 ** Parameters gatt_if: applicaiton interface (input)
1531 ** bd_addr: peer device address. (input)
1532 ** p_conn_id: connection id (output)
1533 **
1534 ** Returns TRUE the ligical link is connected
1535 **
1536 *******************************************************************************/
GATT_GetConnIdIfConnected(tGATT_IF gatt_if,BD_ADDR bd_addr,UINT16 * p_conn_id)1537 BOOLEAN GATT_GetConnIdIfConnected(tGATT_IF gatt_if, BD_ADDR bd_addr, UINT16 *p_conn_id)
1538 {
1539 tGATT_REG *p_reg = gatt_get_regcb(gatt_if);
1540 tGATT_TCB *p_tcb= gatt_find_tcb_by_addr(bd_addr);
1541 BOOLEAN status=FALSE;
1542
1543 if (p_reg && p_tcb && (gatt_get_ch_state(p_tcb) == GATT_CH_OPEN) )
1544 {
1545 *p_conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, gatt_if);
1546 status = TRUE;
1547 }
1548
1549 GATT_TRACE_API1 ("GATT_GetConnIdIfConnected status=%d", status);
1550 return status;
1551 }
1552
1553 #endif
1554
1555
1556