blob: b6dc9d893f1ac2fefc601405489a52056dc24cd7 [file] [log] [blame]
The Android Open Source Project5738f832012-12-12 16:00:35 -08001/******************************************************************************
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 the main GATT client functions
22 *
23 ******************************************************************************/
24
25#include "bt_target.h"
26
27#if BLE_INCLUDED == TRUE
28
29#include <string.h>
30#include "gki.h"
31#include "gatt_int.h"
32
33#define GATT_WRITE_LONG_HDR_SIZE 5 /* 1 opcode + 2 handle + 2 offset */
34#define GATT_READ_CHAR_VALUE_HDL (GATT_READ_CHAR_VALUE | 0x80)
35#define GATT_READ_INC_SRV_UUID128 (GATT_DISC_INC_SRVC | 0x90)
36
37/********************************************************************************
38** G L O B A L G A T T D A T A *
39*********************************************************************************/
40void gatt_send_prepare_write(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb);
41
42UINT8 disc_type_to_att_opcode[GATT_DISC_MAX] =
43{
44 0,
45 GATT_REQ_READ_BY_GRP_TYPE, /* GATT_DISC_SRVC_ALL = 1, */
46 GATT_REQ_FIND_TYPE_VALUE, /* GATT_DISC_SRVC_BY_UUID, */
47 GATT_REQ_READ_BY_TYPE, /* GATT_DISC_INC_SRVC, */
48 GATT_REQ_READ_BY_TYPE, /* GATT_DISC_CHAR, */
49 GATT_REQ_FIND_INFO /* GATT_DISC_CHAR_DSCPT, */
50};
51
52UINT16 disc_type_to_uuid[GATT_DISC_MAX] =
53{
54 0, /* reserved */
55 GATT_UUID_PRI_SERVICE, /* <service> DISC_SRVC_ALL */
56 GATT_UUID_PRI_SERVICE, /* <service> for DISC_SERVC_BY_UUID */
57 GATT_UUID_INCLUDE_SERVICE, /* <include_service> for DISC_INC_SRVC */
58 GATT_UUID_CHAR_DECLARE, /* <characteristic> for DISC_CHAR */
59 0 /* no type filtering for DISC_CHAR_DSCPT */
60};
61
62
63/*******************************************************************************
64**
65** Function gatt_act_discovery
66**
67** Description GATT discovery operation.
68**
69** Returns void.
70**
71*******************************************************************************/
72void gatt_act_discovery(tGATT_CLCB *p_clcb)
73{
74 UINT8 op_code = disc_type_to_att_opcode[p_clcb->op_subtype];
75 tGATT_CL_MSG cl_req;
Andre Eisenbach6975b4d2013-08-05 16:55:38 -070076 tGATT_STATUS st;
The Android Open Source Project5738f832012-12-12 16:00:35 -080077
78 if (p_clcb->s_handle <= p_clcb->e_handle && p_clcb->s_handle != 0)
79 {
80 memset(&cl_req, 0, sizeof(tGATT_CL_MSG));
81
82 cl_req.browse.s_handle = p_clcb->s_handle;
83 cl_req.browse.e_handle = p_clcb->e_handle;
84
85 if (disc_type_to_uuid[p_clcb->op_subtype] != 0)
86 {
87 cl_req.browse.uuid.len = 2;
88 cl_req.browse.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
89 }
90
91 if (p_clcb->op_subtype == GATT_DISC_SRVC_BY_UUID) /* fill in the FindByTypeValue request info*/
92 {
93 cl_req.find_type_value.uuid.len = 2;
94 cl_req.find_type_value.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
95 cl_req.find_type_value.s_handle = p_clcb->s_handle;
96 cl_req.find_type_value.e_handle = p_clcb->e_handle;
97 cl_req.find_type_value.value_len = p_clcb->uuid.len;
98 memcpy (cl_req.find_type_value.value, &p_clcb->uuid.uu, p_clcb->uuid.len);
99 }
100
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700101 st = attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, op_code, &cl_req);
102
103 if (st != GATT_SUCCESS && st != GATT_CMD_STARTED)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800104 {
105 gatt_end_operation(p_clcb, GATT_ERROR, NULL);
106 }
107 }
108 else /* end of handle range */
109 gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
110}
111
112/*******************************************************************************
113**
114** Function gatt_act_read
115**
116** Description GATT read operation.
117**
118** Returns void.
119**
120*******************************************************************************/
121void gatt_act_read (tGATT_CLCB *p_clcb, UINT16 offset)
122{
123 tGATT_TCB *p_tcb = p_clcb->p_tcb;
124 UINT8 rt = GATT_INTERNAL_ERROR;
125 tGATT_CL_MSG msg;
126 UINT8 op_code = 0;
127
128 memset (&msg, 0, sizeof(tGATT_CL_MSG));
129
130 switch (p_clcb->op_subtype)
131 {
132 case GATT_READ_CHAR_VALUE:
133 case GATT_READ_BY_TYPE:
134 op_code = GATT_REQ_READ_BY_TYPE;
135 msg.browse.s_handle = p_clcb->s_handle;
136 msg.browse.e_handle = p_clcb->e_handle;
137 if (p_clcb->op_subtype == GATT_READ_BY_TYPE)
138 memcpy(&msg.browse.uuid, &p_clcb->uuid, sizeof(tBT_UUID));
139 else
140 {
141 msg.browse.uuid.len = LEN_UUID_16;
142 msg.browse.uuid.uu.uuid16 = GATT_UUID_CHAR_DECLARE;
143 }
144 break;
145
146 case GATT_READ_CHAR_VALUE_HDL:
147 case GATT_READ_BY_HANDLE:
148 if (!p_clcb->counter)
149 {
150 op_code = GATT_REQ_READ;
151 msg.handle = p_clcb->s_handle;
152 }
153 else
154 {
155 if (!p_clcb->first_read_blob_after_read)
156 p_clcb->first_read_blob_after_read = TRUE;
157 else
158 p_clcb->first_read_blob_after_read = FALSE;
159
160 GATT_TRACE_DEBUG1("gatt_act_read first_read_blob_after_read=%d",
161 p_clcb->first_read_blob_after_read);
162 op_code = GATT_REQ_READ_BLOB;
163 msg.read_blob.offset = offset;
164 msg.read_blob.handle = p_clcb->s_handle;
165 }
166 p_clcb->op_subtype &= ~ 0x80;
167 break;
168
169 case GATT_READ_PARTIAL:
170 op_code = GATT_REQ_READ_BLOB;
171 msg.read_blob.handle = p_clcb->s_handle;
172 msg.read_blob.offset = offset;
173 break;
174
175 case GATT_READ_MULTIPLE:
176 op_code = GATT_REQ_READ_MULTI;
177 memcpy (&msg.read_multi, p_clcb->p_attr_buf, sizeof(tGATT_READ_MULTI));
178 break;
179
180 case GATT_READ_INC_SRV_UUID128:
181 op_code = GATT_REQ_READ;
182 msg.handle = p_clcb->s_handle;
183 p_clcb->op_subtype &= ~ 0x90;
184 break;
185
186 default:
187 GATT_TRACE_ERROR1("Unknown read type: %d", p_clcb->op_subtype);
188 break;
189 }
190
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700191 if (op_code != 0)
192 rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, op_code, &msg);
193
194 if ( op_code == 0 || (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800195 {
196 gatt_end_operation(p_clcb, rt, NULL);
197 }
198}
199
200/*******************************************************************************
201**
202** Function gatt_act_write
203**
204** Description GATT write operation.
205**
206** Returns void.
207**
208*******************************************************************************/
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800209void gatt_act_write (tGATT_CLCB *p_clcb, UINT8 sec_act)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800210{
211 tGATT_TCB *p_tcb = p_clcb->p_tcb;
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700212 UINT8 rt = GATT_SUCCESS, op_code = 0;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800213 tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
214
215 if (p_attr)
216 {
217 switch (p_clcb->op_subtype)
218 {
219 case GATT_WRITE_NO_RSP:
220 p_clcb->s_handle = p_attr->handle;
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800221 op_code = (sec_act == GATT_SEC_SIGN_DATA) ? GATT_SIGN_CMD_WRITE : GATT_CMD_WRITE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800222 rt = gatt_send_write_msg(p_tcb,
223 p_clcb->clcb_idx,
224 op_code,
225 p_attr->handle,
226 p_attr->len,
227 0,
228 p_attr->value);
229 break;
230
231 case GATT_WRITE:
232 if (p_attr->len <= (p_tcb->payload_size - GATT_HDR_SIZE))
233 {
234 p_clcb->s_handle = p_attr->handle;
235
236 rt = gatt_send_write_msg(p_tcb,
237 p_clcb->clcb_idx,
238 GATT_REQ_WRITE,
239 p_attr->handle,
240 p_attr->len,
241 0,
242 p_attr->value);
243 }
244 else /* prepare write for long attribute */
245 {
246 gatt_send_prepare_write(p_tcb, p_clcb);
247 }
248 break;
249
250 case GATT_WRITE_PREPARE:
251 gatt_send_prepare_write(p_tcb, p_clcb);
252 break;
253
254 default:
255 rt = GATT_INTERNAL_ERROR;
256 GATT_TRACE_ERROR1("Unknown write type: %d", p_clcb->op_subtype);
257 break;
258 }
259 }
260 else
261 rt = GATT_INTERNAL_ERROR;
262
263 if ((rt != GATT_SUCCESS && rt != GATT_CMD_STARTED)
264 || (rt != GATT_CMD_STARTED && p_clcb->op_subtype == GATT_WRITE_NO_RSP))
265 {
266 if (rt != GATT_SUCCESS)
267 {
268 GATT_TRACE_ERROR1("gatt_act_write() failed op_code=0x%x", op_code);
269 }
270 gatt_end_operation(p_clcb, rt, NULL);
271 }
272}
273/*******************************************************************************
274**
275** Function gatt_send_queue_write_cancel
276**
277** Description send queue write cancel
278**
279** Returns void.
280**
281*******************************************************************************/
282void gatt_send_queue_write_cancel (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_EXEC_FLAG flag)
283{
284 UINT8 rt ;
285
286 GATT_TRACE_DEBUG0("gatt_send_queue_write_cancel ");
287
288 rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_EXEC_WRITE, (tGATT_CL_MSG *)&flag);
289
290 if (rt != GATT_SUCCESS)
291 {
292 gatt_end_operation(p_clcb, rt, NULL);
293 }
294}
295/*******************************************************************************
296**
297** Function gatt_check_write_long_terminate
298**
299** Description To terminate write long or not.
300**
301** Returns TRUE: write long is terminated; FALSE keep sending.
302**
303*******************************************************************************/
304BOOLEAN gatt_check_write_long_terminate(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_VALUE *p_rsp_value)
305{
306 tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
307 BOOLEAN exec = FALSE;
308 tGATT_EXEC_FLAG flag = GATT_PREP_WRITE_EXEC;
309
310 GATT_TRACE_DEBUG0("gatt_check_write_long_terminate ");
311 /* check the first write response status */
312 if (p_rsp_value != NULL)
313 {
314 if (p_rsp_value->handle != p_attr->handle ||
315 p_rsp_value->len != p_clcb->counter ||
316 memcmp(p_rsp_value->value, p_attr->value + p_attr->offset, p_rsp_value->len))
317 {
318 /* data does not match */
319 p_clcb->status = GATT_ERROR;
320 flag = GATT_PREP_WRITE_CANCEL;
321 exec = TRUE;
322 }
323 else /* response checking is good */
324 {
325 p_clcb->status = GATT_SUCCESS;
326 /* update write offset and check if end of attribute value */
327 if ((p_attr->offset += p_rsp_value->len) >= p_attr->len)
328 exec = TRUE;
329 }
330 }
331 if (exec)
332 {
333 gatt_send_queue_write_cancel (p_tcb, p_clcb, flag);
334 return TRUE;
335 }
336 return FALSE;
337}
338/*******************************************************************************
339**
340** Function gatt_send_prepare_write
341**
342** Description Send prepare write.
343**
344** Returns void.
345**
346*******************************************************************************/
347void gatt_send_prepare_write(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb)
348{
349 tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
350 UINT16 to_send, offset;
351 UINT8 rt = GATT_SUCCESS;
352 UINT8 type = p_clcb->op_subtype;
353
354 GATT_TRACE_DEBUG1("gatt_send_prepare_write type=0x%x", type );
355 to_send = p_attr->len - p_attr->offset;
356
357 if (to_send > (p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE)) /* 2 = UINT16 offset bytes */
358 to_send = p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE;
359
360 p_clcb->s_handle = p_attr->handle;
361
362 offset = p_attr->offset;
363 if (type == GATT_WRITE_PREPARE)
364 {
365 offset += p_clcb->start_offset;
366 }
367
368 GATT_TRACE_DEBUG2("offset =0x%x len=%d", offset, to_send );
369
370 rt = gatt_send_write_msg(p_tcb,
371 p_clcb->clcb_idx,
372 GATT_REQ_PREPARE_WRITE,
373 p_attr->handle,
374 to_send, /* length */
375 offset, /* used as offset */
376 p_attr->value + p_attr->offset); /* data */
377
378 /* remember the write long attribute length */
379 p_clcb->counter = to_send;
380
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700381 if (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800382 {
383 gatt_end_operation(p_clcb, rt, NULL);
384 }
385}
386
The Android Open Source Project5738f832012-12-12 16:00:35 -0800387
The Android Open Source Project5738f832012-12-12 16:00:35 -0800388/*******************************************************************************
389**
390** Function gatt_process_find_type_value_rsp
391**
392** Description This function is called to handle find by type value response.
393**
394**
395** Returns void
396**
397*******************************************************************************/
398void gatt_process_find_type_value_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data)
399{
400 tGATT_DISC_RES result;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800401 UINT8 *p = p_data;
402
403 GATT_TRACE_DEBUG0("gatt_process_find_type_value_rsp ");
404 /* unexpected response */
405 if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_SRVC_BY_UUID)
406 return;
407
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800408 memset (&result, 0, sizeof(tGATT_DISC_RES));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800409 result.type.len = 2;
410 result.type.uu.uuid16 = GATT_UUID_PRI_SERVICE;
411
412 /* returns a series of handle ranges */
413 while (len >= 4)
414 {
415 STREAM_TO_UINT16 (result.handle, p);
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800416 STREAM_TO_UINT16 (result.value.group_value.e_handle, p);
417 memcpy (&result.value.group_value.service_type, &p_clcb->uuid, sizeof(tBT_UUID));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800418
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800419 len -= 4;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800420
421 if (p_clcb->p_reg->app_cb.p_disc_res_cb)
422 (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
423 }
424
425 /* last handle + 1 */
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800426 p_clcb->s_handle = (result.value.group_value.e_handle == 0) ? 0 : (result.value.group_value.e_handle + 1);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800427 /* initiate another request */
428 gatt_act_discovery(p_clcb) ;
429}
430/*******************************************************************************
431**
432** Function gatt_process_read_info_rsp
433**
434** Description This function is called to handle the read information
435** response.
436**
437**
438** Returns void
439**
440*******************************************************************************/
441void gatt_process_read_info_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
442 UINT16 len, UINT8 *p_data)
443{
444 tGATT_DISC_RES result;
445 UINT8 *p = p_data, uuid_len = 0, type;
446
447 /* unexpected response */
448 if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_CHAR_DSCPT)
449 return;
450
451 STREAM_TO_UINT8(type, p);
452 len -= 1;
453
454 if (type == GATT_INFO_TYPE_PAIR_16)
455 uuid_len = LEN_UUID_16;
456 else if (type == GATT_INFO_TYPE_PAIR_128)
457 uuid_len = LEN_UUID_128;
458
459 while (len >= uuid_len + 2)
460 {
461 STREAM_TO_UINT16 (result.handle, p);
462
463 if (uuid_len > 0)
464 {
465 if (!gatt_parse_uuid_from_cmd(&result.type, uuid_len, &p))
466 break;
467 }
468 else
469 memcpy (&result.type, &p_clcb->uuid, sizeof(tBT_UUID));
470
471 len -= (uuid_len + 2);
472
473 if (p_clcb->p_reg->app_cb.p_disc_res_cb)
474 (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
475 }
476
477 p_clcb->s_handle = (result.handle == 0) ? 0 :(result.handle + 1);
478 /* initiate another request */
479 gatt_act_discovery(p_clcb) ;
480}
481/*******************************************************************************
482**
483** Function gatt_proc_disc_error_rsp
484**
485** Description This function process the read by type response and send another
486** request if needed.
487**
488** Returns void.
489**
490*******************************************************************************/
491void gatt_proc_disc_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 opcode,
492 UINT16 handle, UINT8 reason)
493{
494 tGATT_STATUS status = (tGATT_STATUS) reason;
495
496 GATT_TRACE_DEBUG2("gatt_proc_disc_error_rsp reason: %02x cmd_code %04x", reason, opcode);
497
498 switch (opcode)
499 {
500 case GATT_REQ_READ_BY_GRP_TYPE:
501 case GATT_REQ_FIND_TYPE_VALUE:
502 case GATT_REQ_READ_BY_TYPE:
503 case GATT_REQ_FIND_INFO:
504 if (reason == GATT_NOT_FOUND)
505 {
506 status = GATT_SUCCESS;
507 GATT_TRACE_DEBUG0("Discovery completed");
508 }
509 break;
510 default:
511 GATT_TRACE_ERROR1("Incorrect discovery opcode %04x", opcode);
512 break;
513 }
514
515 gatt_end_operation(p_clcb, status, NULL);
516}
517
518/*******************************************************************************
519**
520** Function gatt_process_error_rsp
521**
522** Description This function is called to handle the error response
523**
524**
525** Returns void
526**
527*******************************************************************************/
528void gatt_process_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
529 UINT16 len, UINT8 *p_data)
530{
531 UINT8 opcode, reason, * p= p_data;
532 UINT16 handle;
533 tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
534
535 GATT_TRACE_DEBUG0("gatt_process_error_rsp ");
536 STREAM_TO_UINT8(opcode, p);
537 STREAM_TO_UINT16(handle, p);
538 STREAM_TO_UINT8(reason, p);
539
540 if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
541 {
542 gatt_proc_disc_error_rsp(p_tcb, p_clcb, opcode, handle, reason);
543 }
544 else
545 {
546 if ( (p_clcb->operation == GATTC_OPTYPE_WRITE) &&
547 (p_clcb->op_subtype == GATT_WRITE) &&
548 (opcode == GATT_REQ_PREPARE_WRITE) &&
549 (p_attr) &&
550 (handle == p_attr->handle) )
551 {
552 p_clcb->status = reason;
553 gatt_send_queue_write_cancel(p_tcb, p_clcb, GATT_PREP_WRITE_CANCEL);
554 }
555 else if ((p_clcb->operation == GATTC_OPTYPE_READ) &&
556 ((p_clcb->op_subtype == GATT_READ_CHAR_VALUE_HDL) ||
557 (p_clcb->op_subtype == GATT_READ_BY_HANDLE)) &&
558 (opcode == GATT_REQ_READ_BLOB) &&
559 p_clcb->first_read_blob_after_read &&
560 (reason == GATT_NOT_LONG))
561 {
562 gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf);
563 }
564 else
565 gatt_end_operation(p_clcb, reason, NULL);
566 }
567}
568/*******************************************************************************
569**
570** Function gatt_process_prep_write_rsp
571**
572** Description This function is called to handle the read response
573**
574**
575** Returns void
576**
577*******************************************************************************/
578void gatt_process_prep_write_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
579 UINT16 len, UINT8 *p_data)
580{
581 tGATT_VALUE value = {0};
582 UINT8 *p= p_data;
583
584 GATT_TRACE_ERROR2("value resp op_code = %s len = %d", gatt_dbg_op_name(op_code), len);
585
586 STREAM_TO_UINT16 (value.handle, p);
587 STREAM_TO_UINT16 (value.offset, p);
588
589 value.len = len - 4;
590
591 memcpy (value.value, p, value.len);
592
593 if (p_clcb->op_subtype == GATT_WRITE_PREPARE)
594 {
595 p_clcb->status = GATT_SUCCESS;
596 /* application should verify handle offset
597 and value are matched or not */
598
599 gatt_end_operation(p_clcb, p_clcb->status, &value);
600 }
601 else if (p_clcb->op_subtype == GATT_WRITE )
602 {
603 if (!gatt_check_write_long_terminate(p_tcb, p_clcb, &value))
604 gatt_send_prepare_write(p_tcb, p_clcb);
605 }
606
607}
608/*******************************************************************************
609**
610** Function gatt_process_notification
611**
612** Description This function is called to handle the handle value indication
613** or handle value notification.
614**
615**
616** Returns void
617**
618*******************************************************************************/
619void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code,
620 UINT16 len, UINT8 *p_data)
621{
622 tGATT_VALUE value = {0};
623 tGATT_REG *p_reg;
624 UINT16 conn_id;
625 tGATT_STATUS encrypt_status;
626 UINT8 *p= p_data, i,
627 event = (op_code == GATT_HANDLE_VALUE_NOTIF) ? GATTC_OPTYPE_NOTIFICATION : GATTC_OPTYPE_INDICATION;
628
629 GATT_TRACE_DEBUG0("gatt_process_notification ");
630
631 STREAM_TO_UINT16 (value.handle, p);
632 value.len = len - 2;
633 memcpy (value.value, p, value.len);
634
635 if (!GATT_HANDLE_IS_VALID(value.handle))
636 {
637 /* illegal handle, send ack now */
638 if (op_code == GATT_HANDLE_VALUE_IND)
639 attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
640 return;
641 }
642
643 if (event == GATTC_OPTYPE_INDICATION)
644 {
645 if (p_tcb->ind_count)
646 {
647 /* this is an error case that receiving an indication but we
648 still has an indication not being acked yet.
649 For now, just log the error reset the counter.
650 Later we need to disconnect the link unconditionally.
651 */
652 GATT_TRACE_ERROR1("gatt_process_notification rcv Ind. but ind_count=%d (will reset ind_count)", p_tcb->ind_count);
653 }
654 p_tcb->ind_count = 0;
655 }
656
657 /* should notify all registered client with the handle value notificaion/indication
658 Note: need to do the indication count and start timer first then do callback
659 */
660
661 for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++)
662 {
663 if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb && (event == GATTC_OPTYPE_INDICATION))
664 p_tcb->ind_count++;
665 }
666
667 if (event == GATTC_OPTYPE_INDICATION)
668 {
669 /* start a timer for app confirmation */
670 if (p_tcb->ind_count > 0)
671 gatt_start_ind_ack_timer(p_tcb);
672 else /* no app to indicate, or invalid handle */
673 attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
674 }
675
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800676 encrypt_status = gatt_get_link_encrypt_status(p_tcb);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800677 for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++)
678 {
679 if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb)
680 {
681 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800682 (*p_reg->app_cb.p_cmpl_cb) (conn_id, event, encrypt_status, (tGATT_CL_COMPLETE *)&value);
683 }
684 }
685
686}
687
688/*******************************************************************************
689**
690** Function gatt_process_read_by_type_rsp
691**
692** Description This function is called to handle the read by type response.
693** read by type can be used for discovery, or read by type or
694** read characteristic value.
695**
696** Returns void
697**
698*******************************************************************************/
699void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
700 UINT16 len, UINT8 *p_data)
701{
702 tGATT_DISC_RES result;
703 tGATT_DISC_VALUE record_value;
704 UINT8 *p = p_data, value_len, handle_len = 2;
705 UINT16 handle = 0;
706
707 /* discovery procedure and no callback function registered */
708 if (((!p_clcb->p_reg) || (!p_clcb->p_reg->app_cb.p_disc_res_cb)) && (p_clcb->operation == GATTC_OPTYPE_DISCOVERY))
709 return;
710
711 STREAM_TO_UINT8(value_len, p);
712
713 if ((value_len > (p_tcb->payload_size - 2)) || (value_len > (len-1)) )
714 {
715 /* this is an error case that server's response containing a value length which is larger than MTU-2
716 or value_len > message total length -1 */
717 GATT_TRACE_ERROR4("gatt_process_read_by_type_rsp: Discard response op_code=%d vale_len=%d > (MTU-2=%d or msg_len-1=%d)",
718 op_code, value_len, (p_tcb->payload_size - 2), (len-1));
719 gatt_end_operation(p_clcb, GATT_ERROR, NULL);
720 return;
721 }
722
723 if (op_code == GATT_RSP_READ_BY_GRP_TYPE)
724 handle_len = 4;
725
726 value_len -= handle_len; /* substract the handle pairs bytes */
727 len -= 1;
728
729 while (len >= (handle_len + value_len))
730 {
731 STREAM_TO_UINT16(handle, p);
732
733 if (!GATT_HANDLE_IS_VALID(handle))
734 {
735 gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
736 return;
737 }
738
739 memset(&result, 0, sizeof(tGATT_DISC_RES));
740 memset(&record_value, 0, sizeof(tGATT_DISC_VALUE));
741
742 result.handle = handle;
743 result.type.len = 2;
744 result.type.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
745
746 /* discover all services */
747 if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
748 p_clcb->op_subtype == GATT_DISC_SRVC_ALL &&
749 op_code == GATT_RSP_READ_BY_GRP_TYPE)
750 {
751 STREAM_TO_UINT16(handle, p);
752
753 if (!GATT_HANDLE_IS_VALID(handle))
754 {
755 gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
756 return;
757 }
758 else
759 {
760 record_value.group_value.e_handle = handle;
761 if (!gatt_parse_uuid_from_cmd(&record_value.group_value.service_type, value_len, &p))
762 {
763 GATT_TRACE_ERROR0("discover all service response parsing failure");
764 break;
765 }
766 }
767 }
768 /* discover included service */
769 else if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->op_subtype == GATT_DISC_INC_SRVC)
770 {
771 STREAM_TO_UINT16(record_value.incl_service.s_handle, p);
772 STREAM_TO_UINT16(record_value.incl_service.e_handle, p);
773
774 if (!GATT_HANDLE_IS_VALID(record_value.incl_service.s_handle) ||
775 !GATT_HANDLE_IS_VALID(record_value.incl_service.e_handle))
776 {
777 gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
778 return;
779 }
780
781 if(value_len == 6)
782 {
783 STREAM_TO_UINT16(record_value.incl_service.service_type.uu.uuid16, p);
784 record_value.incl_service.service_type.len = LEN_UUID_16;
785 }
786 else if (value_len == 4)
787 {
788 p_clcb->s_handle = record_value.incl_service.s_handle;
789 p_clcb->read_uuid128.wait_for_read_rsp = TRUE;
790 p_clcb->read_uuid128.next_disc_start_hdl = handle + 1;
791 memcpy(&p_clcb->read_uuid128.result, &result, sizeof(result));
792 memcpy(&p_clcb->read_uuid128.result.value, &record_value, sizeof (result.value));
793 p_clcb->op_subtype |= 0x90;
794 gatt_act_read(p_clcb, 0);
795 return;
796 }
797 else
798 {
799 GATT_TRACE_ERROR1("gatt_process_read_by_type_rsp INCL_SRVC failed with invalid data value_len=%d", value_len);
800 gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p);
801 return;
802 }
803 }
804 /* read by type */
805 else if (p_clcb->operation == GATTC_OPTYPE_READ && p_clcb->op_subtype == GATT_READ_BY_TYPE)
806 {
807 p_clcb->counter = len - 2;
808 p_clcb->s_handle = handle;
809 if ( p_clcb->counter == (p_clcb->p_tcb->payload_size -4))
810 {
811 p_clcb->op_subtype = GATT_READ_BY_HANDLE;
812 if (!p_clcb->p_attr_buf)
813 p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf(GATT_MAX_ATTR_LEN);
814 if (p_clcb->p_attr_buf && p_clcb->counter <= GATT_MAX_ATTR_LEN)
815 {
816 memcpy(p_clcb->p_attr_buf, p, p_clcb->counter);
817 gatt_act_read(p_clcb, p_clcb->counter);
818 }
819 else
820 gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, (void *)p);
821 }
822 else
823 {
824 gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
825 }
826 return;
827 }
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700828 else /* discover characterisitic */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800829 {
830 STREAM_TO_UINT8 (record_value.dclr_value.char_prop, p);
831 STREAM_TO_UINT16(record_value.dclr_value.val_handle, p);
832 if (!GATT_HANDLE_IS_VALID(record_value.dclr_value.val_handle))
833 {
834 gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
835 return;
836 }
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800837 if (!gatt_parse_uuid_from_cmd(&record_value.dclr_value.char_uuid, (UINT16)(value_len - 3), &p))
838 {
839 gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
840 /* invalid format, and skip the result */
841 return;
842 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800843
844 /* UUID not matching */
845 if (!gatt_uuid_compare(record_value.dclr_value.char_uuid, p_clcb->uuid))
846 {
847 len -= (value_len + 2);
848 continue; /* skip the result, and look for next one */
849 }
850 else if (p_clcb->operation == GATTC_OPTYPE_READ)
851 /* UUID match for read characteristic value */
852 {
853 /* only read the first matching UUID characteristic value, and
854 discard the rest results */
855 p_clcb->s_handle = record_value.dclr_value.val_handle;
856 p_clcb->op_subtype |= 0x80;
857 gatt_act_read(p_clcb, 0);
858 return;
859 }
860 }
861 len -= (value_len + handle_len);
862
863 /* result is (handle, 16bits UUID) pairs */
864 memcpy (&result.value, &record_value, sizeof (result.value));
865
866 /* send callback if is discover procedure */
867 if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->p_reg->app_cb.p_disc_res_cb)
868 (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
869 }
870
871 p_clcb->s_handle = (handle == 0) ? 0 : (handle + 1);
872
873 if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
874 {
875 /* initiate another request */
876 gatt_act_discovery(p_clcb) ;
877 }
878 else /* read characteristic value */
879 {
880 gatt_act_read(p_clcb, 0);
881 }
882}
883
884/*******************************************************************************
885**
886** Function gatt_process_read_rsp
887**
888** Description This function is called to handle the read BLOB response
889**
890**
891** Returns void
892**
893*******************************************************************************/
894void gatt_process_read_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
895 UINT16 len, UINT8 *p_data)
896{
897 UINT16 offset = p_clcb->counter;
898 UINT8 * p= p_data;
899
900 if (p_clcb->operation == GATTC_OPTYPE_READ)
901 {
902 if (p_clcb->op_subtype != GATT_READ_BY_HANDLE)
903 {
904 p_clcb->counter = len;
905 gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
906 }
907 else
908 {
909
910 /* allocate GKI buffer holding up long attribute value */
911 if (!p_clcb->p_attr_buf)
912 p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf(GATT_MAX_ATTR_LEN);
913
914 /* copy attrobute value into cb buffer */
915 if (p_clcb->p_attr_buf && offset < GATT_MAX_ATTR_LEN)
916 {
917 if ((len + offset) > GATT_MAX_ATTR_LEN)
918 len = GATT_MAX_ATTR_LEN - offset;
919
920 p_clcb->counter += len;
921
922 memcpy(p_clcb->p_attr_buf + offset, p, len);
923
924 /* send next request if needed */
925
926 if (len == (p_tcb->payload_size - 1) && /* full packet for read or read blob rsp */
927 len + offset < GATT_MAX_ATTR_LEN)
928 {
929 GATT_TRACE_DEBUG3("full pkt issue read blob for remianing bytes old offset=%d len=%d new offset=%d",
930 offset, len, p_clcb->counter);
931 gatt_act_read(p_clcb, p_clcb->counter);
932 }
933 else /* end of request, send callback */
934 {
935 gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf);
936 }
937 }
938 else /* exception, should not happen */
939 {
940 GATT_TRACE_ERROR2("attr offset = %d p_attr_buf = %d ", offset, p_clcb->p_attr_buf);
941 gatt_end_operation(p_clcb, GATT_NO_RESOURCES, (void *)p_clcb->p_attr_buf);
942 }
943 }
944 }
945 else
946 {
947 if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
948 p_clcb->op_subtype == GATT_DISC_INC_SRVC &&
949 p_clcb->read_uuid128.wait_for_read_rsp )
950 {
951 p_clcb->s_handle = p_clcb->read_uuid128.next_disc_start_hdl;
952 p_clcb->read_uuid128.wait_for_read_rsp = FALSE;
953 if (len == LEN_UUID_128)
954 {
955
956 memcpy(p_clcb->read_uuid128.result.value.incl_service.service_type.uu.uuid128, p, len);
957 p_clcb->read_uuid128.result.value.incl_service.service_type.len = LEN_UUID_128;
958 if ( p_clcb->p_reg->app_cb.p_disc_res_cb)
959 (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &p_clcb->read_uuid128.result);
960 gatt_act_discovery(p_clcb) ;
961 }
962 else
963 {
964 gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p);
965 }
966 }
967 }
968
969}
970
971
972/*******************************************************************************
973**
974** Function gatt_process_handle_rsp
975**
976** Description This function is called to handle the write response
977**
978**
979** Returns void
980**
981*******************************************************************************/
982void gatt_process_handle_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code, UINT16 len, UINT8 *p_data)
983{
984 UINT16 handle;
985 UINT8 * p= p_data;
986
987 STREAM_TO_UINT16(handle, p);
988 len -= 2;
989
990 if (op_code == GATT_RSP_WRITE)
991 gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
992}
993/*******************************************************************************
994**
995** Function gatt_process_mtu_rsp
996**
997** Description This function is called to process the configure MTU response.
998**
999**
1000** Returns void
1001**
1002*******************************************************************************/
1003void gatt_process_mtu_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data)
1004{
1005 UINT16 mtu;
1006
1007 STREAM_TO_UINT16(mtu, p_data);
1008
1009 if (mtu < p_tcb->payload_size && mtu >= GATT_DEF_BLE_MTU_SIZE)
1010 p_tcb->payload_size = mtu;
1011
1012 gatt_end_operation(p_clcb, p_clcb->status, NULL);
1013}
1014/*******************************************************************************
1015**
1016** Function gatt_cmd_to_rsp_code
1017**
1018** Description The function convert a ATT command op code into the corresponding
1019** response code assume no error occurs.
1020**
1021** Returns response code.
1022**
1023*******************************************************************************/
1024UINT8 gatt_cmd_to_rsp_code (UINT8 cmd_code)
1025{
1026 UINT8 rsp_code = 0;
1027
1028 if (cmd_code > 1 && cmd_code != GATT_CMD_WRITE)
1029 {
1030 rsp_code = cmd_code + 1;
1031 }
1032 return rsp_code;
1033}
1034/*******************************************************************************
1035**
1036** Function gatt_cl_send_next_cmd_inq
1037**
1038** Description Find next command in queue and sent to server
1039**
1040** Returns TRUE if command sent, otherwise FALSE.
1041**
1042*******************************************************************************/
1043BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb)
1044{
1045 tGATT_CMD_Q *p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
1046 BOOLEAN sent = FALSE;
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -08001047 UINT8 rsp_code;
1048 tGATT_CLCB *p_clcb = NULL;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001049
1050 while (!sent &&
1051 p_tcb->pending_cl_req != p_tcb->next_slot_inq &&
1052 p_cmd->to_send && p_cmd->p_cmd != NULL)
1053 {
1054 sent = attp_send_msg_to_L2CAP(p_tcb, p_cmd->p_cmd);
1055
1056 if (sent)
1057 {
1058 p_cmd->to_send = FALSE;
1059 p_cmd->p_cmd = NULL;
1060
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -08001061 /* dequeue the request if is write command or sign write */
1062 if (p_cmd->op_code != GATT_CMD_WRITE && p_cmd->op_code != GATT_SIGN_CMD_WRITE)
1063 {
1064 gatt_start_rsp_timer (p_tcb);
1065 }
1066 else
1067 {
1068 p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
1069
1070 /* if no ack needed, keep sending */
1071 sent = FALSE;
1072 p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
1073 /* send command complete callback here */
1074 gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
1075 }
The Android Open Source Project5738f832012-12-12 16:00:35 -08001076 }
1077 else
1078 {
1079 GATT_TRACE_ERROR0("gatt_cl_send_next_cmd_inq: L2CAP sent error");
1080
1081 memset(p_cmd, 0, sizeof(tGATT_CMD_Q));
1082 p_tcb->pending_cl_req ++;
1083 p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
1084 }
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -08001085
The Android Open Source Project5738f832012-12-12 16:00:35 -08001086 }
1087 return sent;
1088}
1089
1090/*******************************************************************************
1091**
1092** Function gatt_client_handle_server_rsp
1093**
1094** Description This function is called to handle the server response to
1095** client.
1096**
1097**
1098** Returns void
1099**
1100*******************************************************************************/
1101void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, UINT8 op_code,
1102 UINT16 len, UINT8 *p_data)
1103{
1104 tGATT_CLCB *p_clcb = NULL;
1105 UINT8 rsp_code;
1106
1107 if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF)
1108 {
1109 p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
1110
1111 rsp_code = gatt_cmd_to_rsp_code(rsp_code);
1112
1113 if (p_clcb == NULL || (rsp_code != op_code && op_code != GATT_RSP_ERROR))
1114 {
1115 GATT_TRACE_WARNING2 ("ATT - Ignore wrong response. Receives (%02x) \
1116 Request(%02x) Ignored", op_code, rsp_code);
1117
1118 return;
1119 }
1120 else
1121 btu_stop_timer (&p_tcb->rsp_timer_ent);
1122 }
1123 /* the size of the message may not be bigger than the local max PDU size*/
1124 /* The message has to be smaller than the agreed MTU, len does not count op_code */
1125 if (len >= p_tcb->payload_size)
1126 {
1127 GATT_TRACE_ERROR2("invalid response/indicate pkt size: %d, PDU size: %d", len + 1, p_tcb->payload_size);
1128 if (op_code != GATT_HANDLE_VALUE_NOTIF &&
1129 op_code != GATT_HANDLE_VALUE_IND)
1130 gatt_end_operation(p_clcb, GATT_ERROR, NULL);
1131 }
1132 else
1133 {
1134 switch (op_code)
1135 {
1136 case GATT_RSP_ERROR:
1137 gatt_process_error_rsp(p_tcb, p_clcb, op_code, len, p_data);
1138 break;
1139
1140 case GATT_RSP_MTU: /* 2 bytes mtu */
1141 gatt_process_mtu_rsp(p_tcb, p_clcb, len ,p_data);
1142 break;
1143
1144 case GATT_RSP_FIND_INFO:
1145 gatt_process_read_info_rsp(p_tcb, p_clcb, op_code, len, p_data);
1146 break;
1147
1148 case GATT_RSP_READ_BY_TYPE:
1149 case GATT_RSP_READ_BY_GRP_TYPE:
1150 gatt_process_read_by_type_rsp(p_tcb, p_clcb, op_code, len, p_data);
1151 break;
1152
1153 case GATT_RSP_READ:
1154 case GATT_RSP_READ_BLOB:
1155 case GATT_RSP_READ_MULTI:
1156 gatt_process_read_rsp(p_tcb, p_clcb, op_code, len, p_data);
1157 break;
1158
1159 case GATT_RSP_FIND_TYPE_VALUE: /* disc service with UUID */
1160 gatt_process_find_type_value_rsp(p_tcb, p_clcb, len, p_data);
1161 break;
1162
1163 case GATT_RSP_WRITE:
1164 gatt_process_handle_rsp(p_tcb, p_clcb, op_code, len, p_data);
1165 break;
1166
1167 case GATT_RSP_PREPARE_WRITE:
1168 gatt_process_prep_write_rsp(p_tcb, p_clcb, op_code, len, p_data);
1169 break;
1170
1171 case GATT_RSP_EXEC_WRITE:
1172 gatt_end_operation(p_clcb, p_clcb->status, NULL);
1173 break;
1174
1175 case GATT_HANDLE_VALUE_NOTIF:
1176 case GATT_HANDLE_VALUE_IND:
1177 gatt_process_notification(p_tcb, op_code, len, p_data);
1178 break;
1179
1180 default:
1181 GATT_TRACE_ERROR1("Unknown opcode = %d", op_code);
1182 break;
1183 }
1184 }
1185
1186 if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF)
1187 {
1188 gatt_cl_send_next_cmd_inq(p_tcb);
1189 }
1190
1191 return;
1192}
1193
1194#endif /* BLE_INCLUDED */