blob: 0578086bb19fc1c520c1d5b7053a7f7b52c2207e [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>
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -070030#include "bt_utils.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080031#include "gki.h"
32#include "gatt_int.h"
33
34#define GATT_WRITE_LONG_HDR_SIZE 5 /* 1 opcode + 2 handle + 2 offset */
35#define GATT_READ_CHAR_VALUE_HDL (GATT_READ_CHAR_VALUE | 0x80)
36#define GATT_READ_INC_SRV_UUID128 (GATT_DISC_INC_SRVC | 0x90)
37
Andre Eisenbachccf9c152013-10-02 15:37:21 -070038#define GATT_PREP_WRITE_RSP_MIN_LEN 4
39#define GATT_NOTIFICATION_MIN_LEN 2
40#define GATT_WRITE_RSP_MIN_LEN 2
41#define GATT_INFO_RSP_MIN_LEN 1
42#define GATT_MTU_RSP_MIN_LEN 2
43#define GATT_READ_BY_TYPE_RSP_MIN_LEN 1
44
The Android Open Source Project5738f832012-12-12 16:00:35 -080045/********************************************************************************
46** G L O B A L G A T T D A T A *
47*********************************************************************************/
48void gatt_send_prepare_write(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb);
49
50UINT8 disc_type_to_att_opcode[GATT_DISC_MAX] =
51{
52 0,
53 GATT_REQ_READ_BY_GRP_TYPE, /* GATT_DISC_SRVC_ALL = 1, */
54 GATT_REQ_FIND_TYPE_VALUE, /* GATT_DISC_SRVC_BY_UUID, */
55 GATT_REQ_READ_BY_TYPE, /* GATT_DISC_INC_SRVC, */
56 GATT_REQ_READ_BY_TYPE, /* GATT_DISC_CHAR, */
57 GATT_REQ_FIND_INFO /* GATT_DISC_CHAR_DSCPT, */
58};
59
60UINT16 disc_type_to_uuid[GATT_DISC_MAX] =
61{
62 0, /* reserved */
63 GATT_UUID_PRI_SERVICE, /* <service> DISC_SRVC_ALL */
64 GATT_UUID_PRI_SERVICE, /* <service> for DISC_SERVC_BY_UUID */
65 GATT_UUID_INCLUDE_SERVICE, /* <include_service> for DISC_INC_SRVC */
66 GATT_UUID_CHAR_DECLARE, /* <characteristic> for DISC_CHAR */
67 0 /* no type filtering for DISC_CHAR_DSCPT */
68};
69
70
71/*******************************************************************************
72**
73** Function gatt_act_discovery
74**
75** Description GATT discovery operation.
76**
77** Returns void.
78**
79*******************************************************************************/
80void gatt_act_discovery(tGATT_CLCB *p_clcb)
81{
82 UINT8 op_code = disc_type_to_att_opcode[p_clcb->op_subtype];
83 tGATT_CL_MSG cl_req;
Andre Eisenbach6975b4d2013-08-05 16:55:38 -070084 tGATT_STATUS st;
The Android Open Source Project5738f832012-12-12 16:00:35 -080085
86 if (p_clcb->s_handle <= p_clcb->e_handle && p_clcb->s_handle != 0)
87 {
88 memset(&cl_req, 0, sizeof(tGATT_CL_MSG));
89
90 cl_req.browse.s_handle = p_clcb->s_handle;
91 cl_req.browse.e_handle = p_clcb->e_handle;
92
93 if (disc_type_to_uuid[p_clcb->op_subtype] != 0)
94 {
95 cl_req.browse.uuid.len = 2;
96 cl_req.browse.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
97 }
98
99 if (p_clcb->op_subtype == GATT_DISC_SRVC_BY_UUID) /* fill in the FindByTypeValue request info*/
100 {
101 cl_req.find_type_value.uuid.len = 2;
102 cl_req.find_type_value.uuid.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
103 cl_req.find_type_value.s_handle = p_clcb->s_handle;
104 cl_req.find_type_value.e_handle = p_clcb->e_handle;
105 cl_req.find_type_value.value_len = p_clcb->uuid.len;
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700106 /* if service type is 32 bits UUID, convert it now */
107 if (p_clcb->uuid.len == LEN_UUID_32)
108 {
109 cl_req.find_type_value.value_len = LEN_UUID_128;
110 gatt_convert_uuid32_to_uuid128(cl_req.find_type_value.value, p_clcb->uuid.uu.uuid32);
111 }
112 else
The Android Open Source Project5738f832012-12-12 16:00:35 -0800113 memcpy (cl_req.find_type_value.value, &p_clcb->uuid.uu, p_clcb->uuid.len);
114 }
115
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700116 st = attp_send_cl_msg(p_clcb->p_tcb, p_clcb->clcb_idx, op_code, &cl_req);
117
118 if (st != GATT_SUCCESS && st != GATT_CMD_STARTED)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800119 {
120 gatt_end_operation(p_clcb, GATT_ERROR, NULL);
121 }
122 }
123 else /* end of handle range */
124 gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
125}
126
127/*******************************************************************************
128**
129** Function gatt_act_read
130**
131** Description GATT read operation.
132**
133** Returns void.
134**
135*******************************************************************************/
136void gatt_act_read (tGATT_CLCB *p_clcb, UINT16 offset)
137{
138 tGATT_TCB *p_tcb = p_clcb->p_tcb;
139 UINT8 rt = GATT_INTERNAL_ERROR;
140 tGATT_CL_MSG msg;
141 UINT8 op_code = 0;
142
143 memset (&msg, 0, sizeof(tGATT_CL_MSG));
144
145 switch (p_clcb->op_subtype)
146 {
147 case GATT_READ_CHAR_VALUE:
148 case GATT_READ_BY_TYPE:
149 op_code = GATT_REQ_READ_BY_TYPE;
150 msg.browse.s_handle = p_clcb->s_handle;
151 msg.browse.e_handle = p_clcb->e_handle;
152 if (p_clcb->op_subtype == GATT_READ_BY_TYPE)
153 memcpy(&msg.browse.uuid, &p_clcb->uuid, sizeof(tBT_UUID));
154 else
155 {
156 msg.browse.uuid.len = LEN_UUID_16;
157 msg.browse.uuid.uu.uuid16 = GATT_UUID_CHAR_DECLARE;
158 }
159 break;
160
161 case GATT_READ_CHAR_VALUE_HDL:
162 case GATT_READ_BY_HANDLE:
163 if (!p_clcb->counter)
164 {
165 op_code = GATT_REQ_READ;
166 msg.handle = p_clcb->s_handle;
167 }
168 else
169 {
170 if (!p_clcb->first_read_blob_after_read)
171 p_clcb->first_read_blob_after_read = TRUE;
172 else
173 p_clcb->first_read_blob_after_read = FALSE;
174
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700175 GATT_TRACE_DEBUG("gatt_act_read first_read_blob_after_read=%d",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800176 p_clcb->first_read_blob_after_read);
177 op_code = GATT_REQ_READ_BLOB;
178 msg.read_blob.offset = offset;
179 msg.read_blob.handle = p_clcb->s_handle;
180 }
181 p_clcb->op_subtype &= ~ 0x80;
182 break;
183
184 case GATT_READ_PARTIAL:
185 op_code = GATT_REQ_READ_BLOB;
186 msg.read_blob.handle = p_clcb->s_handle;
187 msg.read_blob.offset = offset;
188 break;
189
190 case GATT_READ_MULTIPLE:
191 op_code = GATT_REQ_READ_MULTI;
192 memcpy (&msg.read_multi, p_clcb->p_attr_buf, sizeof(tGATT_READ_MULTI));
193 break;
194
195 case GATT_READ_INC_SRV_UUID128:
196 op_code = GATT_REQ_READ;
197 msg.handle = p_clcb->s_handle;
198 p_clcb->op_subtype &= ~ 0x90;
199 break;
200
201 default:
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700202 GATT_TRACE_ERROR("Unknown read type: %d", p_clcb->op_subtype);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800203 break;
204 }
205
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700206 if (op_code != 0)
207 rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, op_code, &msg);
208
209 if ( op_code == 0 || (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800210 {
211 gatt_end_operation(p_clcb, rt, NULL);
212 }
213}
214
215/*******************************************************************************
216**
217** Function gatt_act_write
218**
219** Description GATT write operation.
220**
221** Returns void.
222**
223*******************************************************************************/
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800224void gatt_act_write (tGATT_CLCB *p_clcb, UINT8 sec_act)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800225{
226 tGATT_TCB *p_tcb = p_clcb->p_tcb;
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700227 UINT8 rt = GATT_SUCCESS, op_code = 0;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800228 tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
229
230 if (p_attr)
231 {
232 switch (p_clcb->op_subtype)
233 {
234 case GATT_WRITE_NO_RSP:
235 p_clcb->s_handle = p_attr->handle;
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800236 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 -0800237 rt = gatt_send_write_msg(p_tcb,
238 p_clcb->clcb_idx,
239 op_code,
240 p_attr->handle,
241 p_attr->len,
242 0,
243 p_attr->value);
244 break;
245
246 case GATT_WRITE:
247 if (p_attr->len <= (p_tcb->payload_size - GATT_HDR_SIZE))
248 {
249 p_clcb->s_handle = p_attr->handle;
250
251 rt = gatt_send_write_msg(p_tcb,
252 p_clcb->clcb_idx,
253 GATT_REQ_WRITE,
254 p_attr->handle,
255 p_attr->len,
256 0,
257 p_attr->value);
258 }
259 else /* prepare write for long attribute */
260 {
261 gatt_send_prepare_write(p_tcb, p_clcb);
262 }
263 break;
264
265 case GATT_WRITE_PREPARE:
266 gatt_send_prepare_write(p_tcb, p_clcb);
267 break;
268
269 default:
270 rt = GATT_INTERNAL_ERROR;
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700271 GATT_TRACE_ERROR("Unknown write type: %d", p_clcb->op_subtype);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800272 break;
273 }
274 }
275 else
276 rt = GATT_INTERNAL_ERROR;
277
Andre Eisenbach17b04bd2014-03-28 14:54:22 -0700278 if ((rt != GATT_SUCCESS && rt != GATT_CMD_STARTED && rt != GATT_CONGESTED)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800279 || (rt != GATT_CMD_STARTED && p_clcb->op_subtype == GATT_WRITE_NO_RSP))
280 {
281 if (rt != GATT_SUCCESS)
282 {
Andre Eisenbach5d5b0412015-01-12 13:34:01 -0800283 GATT_TRACE_ERROR("gatt_act_write() failed op_code=0x%x rt=%d", op_code, rt);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800284 }
285 gatt_end_operation(p_clcb, rt, NULL);
286 }
287}
288/*******************************************************************************
289**
290** Function gatt_send_queue_write_cancel
291**
292** Description send queue write cancel
293**
294** Returns void.
295**
296*******************************************************************************/
297void gatt_send_queue_write_cancel (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_EXEC_FLAG flag)
298{
299 UINT8 rt ;
300
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700301 GATT_TRACE_DEBUG("gatt_send_queue_write_cancel ");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800302
303 rt = attp_send_cl_msg(p_tcb, p_clcb->clcb_idx, GATT_REQ_EXEC_WRITE, (tGATT_CL_MSG *)&flag);
304
305 if (rt != GATT_SUCCESS)
306 {
307 gatt_end_operation(p_clcb, rt, NULL);
308 }
309}
310/*******************************************************************************
311**
312** Function gatt_check_write_long_terminate
313**
314** Description To terminate write long or not.
315**
316** Returns TRUE: write long is terminated; FALSE keep sending.
317**
318*******************************************************************************/
319BOOLEAN gatt_check_write_long_terminate(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, tGATT_VALUE *p_rsp_value)
320{
321 tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
322 BOOLEAN exec = FALSE;
323 tGATT_EXEC_FLAG flag = GATT_PREP_WRITE_EXEC;
324
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700325 GATT_TRACE_DEBUG("gatt_check_write_long_terminate ");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800326 /* check the first write response status */
327 if (p_rsp_value != NULL)
328 {
329 if (p_rsp_value->handle != p_attr->handle ||
330 p_rsp_value->len != p_clcb->counter ||
331 memcmp(p_rsp_value->value, p_attr->value + p_attr->offset, p_rsp_value->len))
332 {
333 /* data does not match */
334 p_clcb->status = GATT_ERROR;
335 flag = GATT_PREP_WRITE_CANCEL;
336 exec = TRUE;
337 }
338 else /* response checking is good */
339 {
340 p_clcb->status = GATT_SUCCESS;
341 /* update write offset and check if end of attribute value */
342 if ((p_attr->offset += p_rsp_value->len) >= p_attr->len)
343 exec = TRUE;
344 }
345 }
346 if (exec)
347 {
348 gatt_send_queue_write_cancel (p_tcb, p_clcb, flag);
349 return TRUE;
350 }
351 return FALSE;
352}
353/*******************************************************************************
354**
355** Function gatt_send_prepare_write
356**
357** Description Send prepare write.
358**
359** Returns void.
360**
361*******************************************************************************/
362void gatt_send_prepare_write(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb)
363{
364 tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
365 UINT16 to_send, offset;
366 UINT8 rt = GATT_SUCCESS;
367 UINT8 type = p_clcb->op_subtype;
368
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700369 GATT_TRACE_DEBUG("gatt_send_prepare_write type=0x%x", type );
The Android Open Source Project5738f832012-12-12 16:00:35 -0800370 to_send = p_attr->len - p_attr->offset;
371
372 if (to_send > (p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE)) /* 2 = UINT16 offset bytes */
373 to_send = p_tcb->payload_size - GATT_WRITE_LONG_HDR_SIZE;
374
375 p_clcb->s_handle = p_attr->handle;
376
377 offset = p_attr->offset;
378 if (type == GATT_WRITE_PREPARE)
379 {
380 offset += p_clcb->start_offset;
381 }
382
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700383 GATT_TRACE_DEBUG("offset =0x%x len=%d", offset, to_send );
The Android Open Source Project5738f832012-12-12 16:00:35 -0800384
385 rt = gatt_send_write_msg(p_tcb,
386 p_clcb->clcb_idx,
387 GATT_REQ_PREPARE_WRITE,
388 p_attr->handle,
389 to_send, /* length */
390 offset, /* used as offset */
391 p_attr->value + p_attr->offset); /* data */
392
393 /* remember the write long attribute length */
394 p_clcb->counter = to_send;
395
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700396 if (rt != GATT_SUCCESS && rt != GATT_CMD_STARTED)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800397 {
398 gatt_end_operation(p_clcb, rt, NULL);
399 }
400}
401
The Android Open Source Project5738f832012-12-12 16:00:35 -0800402
The Android Open Source Project5738f832012-12-12 16:00:35 -0800403/*******************************************************************************
404**
405** Function gatt_process_find_type_value_rsp
406**
407** Description This function is called to handle find by type value response.
408**
409**
410** Returns void
411**
412*******************************************************************************/
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700413void gatt_process_find_type_value_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800414{
415 tGATT_DISC_RES result;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800416 UINT8 *p = p_data;
417
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700418 UNUSED(p_tcb);
419
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700420 GATT_TRACE_DEBUG("gatt_process_find_type_value_rsp ");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800421 /* unexpected response */
422 if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_SRVC_BY_UUID)
423 return;
424
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800425 memset (&result, 0, sizeof(tGATT_DISC_RES));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800426 result.type.len = 2;
427 result.type.uu.uuid16 = GATT_UUID_PRI_SERVICE;
428
429 /* returns a series of handle ranges */
430 while (len >= 4)
431 {
432 STREAM_TO_UINT16 (result.handle, p);
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800433 STREAM_TO_UINT16 (result.value.group_value.e_handle, p);
434 memcpy (&result.value.group_value.service_type, &p_clcb->uuid, sizeof(tBT_UUID));
The Android Open Source Project5738f832012-12-12 16:00:35 -0800435
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800436 len -= 4;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800437
438 if (p_clcb->p_reg->app_cb.p_disc_res_cb)
439 (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
440 }
441
442 /* last handle + 1 */
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800443 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 -0800444 /* initiate another request */
445 gatt_act_discovery(p_clcb) ;
446}
447/*******************************************************************************
448**
449** Function gatt_process_read_info_rsp
450**
451** Description This function is called to handle the read information
452** response.
453**
454**
455** Returns void
456**
457*******************************************************************************/
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700458void gatt_process_read_info_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
459 UINT16 len, UINT8 *p_data)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800460{
461 tGATT_DISC_RES result;
462 UINT8 *p = p_data, uuid_len = 0, type;
463
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700464 UNUSED(p_tcb);
465 UNUSED(op_code);
466
Andre Eisenbachccf9c152013-10-02 15:37:21 -0700467 if (len < GATT_INFO_RSP_MIN_LEN)
468 {
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700469 GATT_TRACE_ERROR("invalid Info Response PDU received, discard.");
Andre Eisenbachccf9c152013-10-02 15:37:21 -0700470 gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
471 return;
472 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800473 /* unexpected response */
474 if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_CHAR_DSCPT)
475 return;
476
477 STREAM_TO_UINT8(type, p);
478 len -= 1;
479
480 if (type == GATT_INFO_TYPE_PAIR_16)
481 uuid_len = LEN_UUID_16;
482 else if (type == GATT_INFO_TYPE_PAIR_128)
483 uuid_len = LEN_UUID_128;
484
485 while (len >= uuid_len + 2)
486 {
487 STREAM_TO_UINT16 (result.handle, p);
488
489 if (uuid_len > 0)
490 {
491 if (!gatt_parse_uuid_from_cmd(&result.type, uuid_len, &p))
492 break;
493 }
494 else
495 memcpy (&result.type, &p_clcb->uuid, sizeof(tBT_UUID));
496
497 len -= (uuid_len + 2);
498
499 if (p_clcb->p_reg->app_cb.p_disc_res_cb)
500 (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
501 }
502
503 p_clcb->s_handle = (result.handle == 0) ? 0 :(result.handle + 1);
504 /* initiate another request */
505 gatt_act_discovery(p_clcb) ;
506}
507/*******************************************************************************
508**
509** Function gatt_proc_disc_error_rsp
510**
511** Description This function process the read by type response and send another
512** request if needed.
513**
514** Returns void.
515**
516*******************************************************************************/
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700517void gatt_proc_disc_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 opcode,
518 UINT16 handle, UINT8 reason)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800519{
520 tGATT_STATUS status = (tGATT_STATUS) reason;
521
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700522 UNUSED(p_tcb);
523 UNUSED(handle);
524
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700525 GATT_TRACE_DEBUG("gatt_proc_disc_error_rsp reason: %02x cmd_code %04x", reason, opcode);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800526
527 switch (opcode)
528 {
529 case GATT_REQ_READ_BY_GRP_TYPE:
530 case GATT_REQ_FIND_TYPE_VALUE:
531 case GATT_REQ_READ_BY_TYPE:
532 case GATT_REQ_FIND_INFO:
533 if (reason == GATT_NOT_FOUND)
534 {
535 status = GATT_SUCCESS;
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700536 GATT_TRACE_DEBUG("Discovery completed");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800537 }
538 break;
539 default:
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700540 GATT_TRACE_ERROR("Incorrect discovery opcode %04x", opcode);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800541 break;
542 }
543
544 gatt_end_operation(p_clcb, status, NULL);
545}
546
547/*******************************************************************************
548**
549** Function gatt_process_error_rsp
550**
551** Description This function is called to handle the error response
552**
553**
554** Returns void
555**
556*******************************************************************************/
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700557void gatt_process_error_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
558 UINT16 len, UINT8 *p_data)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800559{
560 UINT8 opcode, reason, * p= p_data;
561 UINT16 handle;
562 tGATT_VALUE *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
563
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700564 UNUSED(op_code);
565 UNUSED(len);
566
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700567 GATT_TRACE_DEBUG("gatt_process_error_rsp ");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800568 STREAM_TO_UINT8(opcode, p);
569 STREAM_TO_UINT16(handle, p);
570 STREAM_TO_UINT8(reason, p);
571
572 if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
573 {
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700574 gatt_proc_disc_error_rsp(p_tcb, p_clcb, opcode, handle, reason);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800575 }
576 else
577 {
578 if ( (p_clcb->operation == GATTC_OPTYPE_WRITE) &&
579 (p_clcb->op_subtype == GATT_WRITE) &&
580 (opcode == GATT_REQ_PREPARE_WRITE) &&
581 (p_attr) &&
582 (handle == p_attr->handle) )
583 {
584 p_clcb->status = reason;
585 gatt_send_queue_write_cancel(p_tcb, p_clcb, GATT_PREP_WRITE_CANCEL);
586 }
587 else if ((p_clcb->operation == GATTC_OPTYPE_READ) &&
588 ((p_clcb->op_subtype == GATT_READ_CHAR_VALUE_HDL) ||
589 (p_clcb->op_subtype == GATT_READ_BY_HANDLE)) &&
590 (opcode == GATT_REQ_READ_BLOB) &&
591 p_clcb->first_read_blob_after_read &&
592 (reason == GATT_NOT_LONG))
593 {
594 gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf);
595 }
596 else
597 gatt_end_operation(p_clcb, reason, NULL);
598 }
599}
600/*******************************************************************************
601**
602** Function gatt_process_prep_write_rsp
603**
604** Description This function is called to handle the read response
605**
606**
607** Returns void
608**
609*******************************************************************************/
610void gatt_process_prep_write_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
611 UINT16 len, UINT8 *p_data)
612{
613 tGATT_VALUE value = {0};
614 UINT8 *p= p_data;
615
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700616 GATT_TRACE_ERROR("value resp op_code = %s len = %d", gatt_dbg_op_name(op_code), len);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800617
Andre Eisenbachccf9c152013-10-02 15:37:21 -0700618 if (len < GATT_PREP_WRITE_RSP_MIN_LEN)
619 {
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700620 GATT_TRACE_ERROR("illegal prepare write response length, discard");
Andre Eisenbachccf9c152013-10-02 15:37:21 -0700621 gatt_end_operation(p_clcb, GATT_INVALID_PDU, &value);
622 return;
623 }
624
The Android Open Source Project5738f832012-12-12 16:00:35 -0800625 STREAM_TO_UINT16 (value.handle, p);
626 STREAM_TO_UINT16 (value.offset, p);
627
628 value.len = len - 4;
629
630 memcpy (value.value, p, value.len);
631
632 if (p_clcb->op_subtype == GATT_WRITE_PREPARE)
633 {
634 p_clcb->status = GATT_SUCCESS;
635 /* application should verify handle offset
636 and value are matched or not */
637
638 gatt_end_operation(p_clcb, p_clcb->status, &value);
639 }
640 else if (p_clcb->op_subtype == GATT_WRITE )
641 {
642 if (!gatt_check_write_long_terminate(p_tcb, p_clcb, &value))
643 gatt_send_prepare_write(p_tcb, p_clcb);
644 }
645
646}
647/*******************************************************************************
648**
649** Function gatt_process_notification
650**
651** Description This function is called to handle the handle value indication
652** or handle value notification.
653**
654**
655** Returns void
656**
657*******************************************************************************/
658void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code,
659 UINT16 len, UINT8 *p_data)
660{
661 tGATT_VALUE value = {0};
662 tGATT_REG *p_reg;
663 UINT16 conn_id;
664 tGATT_STATUS encrypt_status;
665 UINT8 *p= p_data, i,
666 event = (op_code == GATT_HANDLE_VALUE_NOTIF) ? GATTC_OPTYPE_NOTIFICATION : GATTC_OPTYPE_INDICATION;
667
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700668 GATT_TRACE_DEBUG("gatt_process_notification ");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800669
Andre Eisenbachccf9c152013-10-02 15:37:21 -0700670 if (len < GATT_NOTIFICATION_MIN_LEN)
671 {
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700672 GATT_TRACE_ERROR("illegal notification PDU length, discard");
Andre Eisenbachccf9c152013-10-02 15:37:21 -0700673 return;
674 }
675
The Android Open Source Project5738f832012-12-12 16:00:35 -0800676 STREAM_TO_UINT16 (value.handle, p);
677 value.len = len - 2;
678 memcpy (value.value, p, value.len);
679
680 if (!GATT_HANDLE_IS_VALID(value.handle))
681 {
682 /* illegal handle, send ack now */
683 if (op_code == GATT_HANDLE_VALUE_IND)
684 attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
685 return;
686 }
687
688 if (event == GATTC_OPTYPE_INDICATION)
689 {
690 if (p_tcb->ind_count)
691 {
692 /* this is an error case that receiving an indication but we
693 still has an indication not being acked yet.
694 For now, just log the error reset the counter.
695 Later we need to disconnect the link unconditionally.
696 */
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700697 GATT_TRACE_ERROR("gatt_process_notification rcv Ind. but ind_count=%d (will reset ind_count)", p_tcb->ind_count);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800698 }
699 p_tcb->ind_count = 0;
700 }
701
702 /* should notify all registered client with the handle value notificaion/indication
703 Note: need to do the indication count and start timer first then do callback
704 */
705
706 for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++)
707 {
708 if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb && (event == GATTC_OPTYPE_INDICATION))
709 p_tcb->ind_count++;
710 }
711
712 if (event == GATTC_OPTYPE_INDICATION)
713 {
714 /* start a timer for app confirmation */
715 if (p_tcb->ind_count > 0)
716 gatt_start_ind_ack_timer(p_tcb);
717 else /* no app to indicate, or invalid handle */
718 attp_send_cl_msg(p_tcb, 0, GATT_HANDLE_VALUE_CONF, NULL);
719 }
720
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800721 encrypt_status = gatt_get_link_encrypt_status(p_tcb);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800722 for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++)
723 {
724 if (p_reg->in_use && p_reg->app_cb.p_cmpl_cb)
725 {
726 conn_id = GATT_CREATE_CONN_ID(p_tcb->tcb_idx, p_reg->gatt_if);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800727 (*p_reg->app_cb.p_cmpl_cb) (conn_id, event, encrypt_status, (tGATT_CL_COMPLETE *)&value);
728 }
729 }
730
731}
732
733/*******************************************************************************
734**
735** Function gatt_process_read_by_type_rsp
736**
737** Description This function is called to handle the read by type response.
738** read by type can be used for discovery, or read by type or
739** read characteristic value.
740**
741** Returns void
742**
743*******************************************************************************/
744void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
745 UINT16 len, UINT8 *p_data)
746{
747 tGATT_DISC_RES result;
748 tGATT_DISC_VALUE record_value;
749 UINT8 *p = p_data, value_len, handle_len = 2;
750 UINT16 handle = 0;
751
752 /* discovery procedure and no callback function registered */
753 if (((!p_clcb->p_reg) || (!p_clcb->p_reg->app_cb.p_disc_res_cb)) && (p_clcb->operation == GATTC_OPTYPE_DISCOVERY))
754 return;
755
Andre Eisenbachccf9c152013-10-02 15:37:21 -0700756 if (len < GATT_READ_BY_TYPE_RSP_MIN_LEN)
757 {
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700758 GATT_TRACE_ERROR("Illegal ReadByType/ReadByGroupType Response length, discard");
Andre Eisenbachccf9c152013-10-02 15:37:21 -0700759 gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
760 return;
761 }
762
The Android Open Source Project5738f832012-12-12 16:00:35 -0800763 STREAM_TO_UINT8(value_len, p);
764
765 if ((value_len > (p_tcb->payload_size - 2)) || (value_len > (len-1)) )
766 {
767 /* this is an error case that server's response containing a value length which is larger than MTU-2
768 or value_len > message total length -1 */
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700769 GATT_TRACE_ERROR("gatt_process_read_by_type_rsp: Discard response op_code=%d vale_len=%d > (MTU-2=%d or msg_len-1=%d)",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800770 op_code, value_len, (p_tcb->payload_size - 2), (len-1));
771 gatt_end_operation(p_clcb, GATT_ERROR, NULL);
772 return;
773 }
774
775 if (op_code == GATT_RSP_READ_BY_GRP_TYPE)
776 handle_len = 4;
777
778 value_len -= handle_len; /* substract the handle pairs bytes */
779 len -= 1;
780
781 while (len >= (handle_len + value_len))
782 {
783 STREAM_TO_UINT16(handle, p);
784
785 if (!GATT_HANDLE_IS_VALID(handle))
786 {
787 gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
788 return;
789 }
790
791 memset(&result, 0, sizeof(tGATT_DISC_RES));
792 memset(&record_value, 0, sizeof(tGATT_DISC_VALUE));
793
794 result.handle = handle;
795 result.type.len = 2;
796 result.type.uu.uuid16 = disc_type_to_uuid[p_clcb->op_subtype];
797
798 /* discover all services */
799 if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
800 p_clcb->op_subtype == GATT_DISC_SRVC_ALL &&
801 op_code == GATT_RSP_READ_BY_GRP_TYPE)
802 {
803 STREAM_TO_UINT16(handle, p);
804
805 if (!GATT_HANDLE_IS_VALID(handle))
806 {
807 gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
808 return;
809 }
810 else
811 {
812 record_value.group_value.e_handle = handle;
813 if (!gatt_parse_uuid_from_cmd(&record_value.group_value.service_type, value_len, &p))
814 {
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700815 GATT_TRACE_ERROR("discover all service response parsing failure");
The Android Open Source Project5738f832012-12-12 16:00:35 -0800816 break;
817 }
818 }
819 }
820 /* discover included service */
821 else if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->op_subtype == GATT_DISC_INC_SRVC)
822 {
823 STREAM_TO_UINT16(record_value.incl_service.s_handle, p);
824 STREAM_TO_UINT16(record_value.incl_service.e_handle, p);
825
826 if (!GATT_HANDLE_IS_VALID(record_value.incl_service.s_handle) ||
827 !GATT_HANDLE_IS_VALID(record_value.incl_service.e_handle))
828 {
829 gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
830 return;
831 }
832
833 if(value_len == 6)
834 {
835 STREAM_TO_UINT16(record_value.incl_service.service_type.uu.uuid16, p);
836 record_value.incl_service.service_type.len = LEN_UUID_16;
837 }
838 else if (value_len == 4)
839 {
840 p_clcb->s_handle = record_value.incl_service.s_handle;
841 p_clcb->read_uuid128.wait_for_read_rsp = TRUE;
842 p_clcb->read_uuid128.next_disc_start_hdl = handle + 1;
843 memcpy(&p_clcb->read_uuid128.result, &result, sizeof(result));
844 memcpy(&p_clcb->read_uuid128.result.value, &record_value, sizeof (result.value));
845 p_clcb->op_subtype |= 0x90;
846 gatt_act_read(p_clcb, 0);
847 return;
848 }
849 else
850 {
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700851 GATT_TRACE_ERROR("gatt_process_read_by_type_rsp INCL_SRVC failed with invalid data value_len=%d", value_len);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800852 gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p);
853 return;
854 }
855 }
856 /* read by type */
857 else if (p_clcb->operation == GATTC_OPTYPE_READ && p_clcb->op_subtype == GATT_READ_BY_TYPE)
858 {
859 p_clcb->counter = len - 2;
860 p_clcb->s_handle = handle;
861 if ( p_clcb->counter == (p_clcb->p_tcb->payload_size -4))
862 {
863 p_clcb->op_subtype = GATT_READ_BY_HANDLE;
864 if (!p_clcb->p_attr_buf)
865 p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf(GATT_MAX_ATTR_LEN);
866 if (p_clcb->p_attr_buf && p_clcb->counter <= GATT_MAX_ATTR_LEN)
867 {
868 memcpy(p_clcb->p_attr_buf, p, p_clcb->counter);
869 gatt_act_read(p_clcb, p_clcb->counter);
870 }
871 else
872 gatt_end_operation(p_clcb, GATT_INTERNAL_ERROR, (void *)p);
873 }
874 else
875 {
876 gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
877 }
878 return;
879 }
Andre Eisenbach6975b4d2013-08-05 16:55:38 -0700880 else /* discover characterisitic */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800881 {
882 STREAM_TO_UINT8 (record_value.dclr_value.char_prop, p);
883 STREAM_TO_UINT16(record_value.dclr_value.val_handle, p);
884 if (!GATT_HANDLE_IS_VALID(record_value.dclr_value.val_handle))
885 {
886 gatt_end_operation(p_clcb, GATT_INVALID_HANDLE, NULL);
887 return;
888 }
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800889 if (!gatt_parse_uuid_from_cmd(&record_value.dclr_value.char_uuid, (UINT16)(value_len - 3), &p))
890 {
891 gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
892 /* invalid format, and skip the result */
893 return;
894 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800895
896 /* UUID not matching */
897 if (!gatt_uuid_compare(record_value.dclr_value.char_uuid, p_clcb->uuid))
898 {
899 len -= (value_len + 2);
900 continue; /* skip the result, and look for next one */
901 }
902 else if (p_clcb->operation == GATTC_OPTYPE_READ)
903 /* UUID match for read characteristic value */
904 {
905 /* only read the first matching UUID characteristic value, and
906 discard the rest results */
907 p_clcb->s_handle = record_value.dclr_value.val_handle;
908 p_clcb->op_subtype |= 0x80;
909 gatt_act_read(p_clcb, 0);
910 return;
911 }
912 }
913 len -= (value_len + handle_len);
914
915 /* result is (handle, 16bits UUID) pairs */
916 memcpy (&result.value, &record_value, sizeof (result.value));
917
918 /* send callback if is discover procedure */
919 if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY && p_clcb->p_reg->app_cb.p_disc_res_cb)
920 (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &result);
921 }
922
923 p_clcb->s_handle = (handle == 0) ? 0 : (handle + 1);
924
925 if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY)
926 {
927 /* initiate another request */
928 gatt_act_discovery(p_clcb) ;
929 }
930 else /* read characteristic value */
931 {
932 gatt_act_read(p_clcb, 0);
933 }
934}
935
936/*******************************************************************************
937**
938** Function gatt_process_read_rsp
939**
940** Description This function is called to handle the read BLOB response
941**
942**
943** Returns void
944**
945*******************************************************************************/
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700946void gatt_process_read_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
947 UINT16 len, UINT8 *p_data)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800948{
949 UINT16 offset = p_clcb->counter;
950 UINT8 * p= p_data;
951
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -0700952 UNUSED(op_code);
953
The Android Open Source Project5738f832012-12-12 16:00:35 -0800954 if (p_clcb->operation == GATTC_OPTYPE_READ)
955 {
956 if (p_clcb->op_subtype != GATT_READ_BY_HANDLE)
957 {
958 p_clcb->counter = len;
959 gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p);
960 }
961 else
962 {
963
964 /* allocate GKI buffer holding up long attribute value */
965 if (!p_clcb->p_attr_buf)
966 p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf(GATT_MAX_ATTR_LEN);
967
968 /* copy attrobute value into cb buffer */
969 if (p_clcb->p_attr_buf && offset < GATT_MAX_ATTR_LEN)
970 {
971 if ((len + offset) > GATT_MAX_ATTR_LEN)
972 len = GATT_MAX_ATTR_LEN - offset;
973
974 p_clcb->counter += len;
975
976 memcpy(p_clcb->p_attr_buf + offset, p, len);
977
978 /* send next request if needed */
979
980 if (len == (p_tcb->payload_size - 1) && /* full packet for read or read blob rsp */
981 len + offset < GATT_MAX_ATTR_LEN)
982 {
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700983 GATT_TRACE_DEBUG("full pkt issue read blob for remianing bytes old offset=%d len=%d new offset=%d",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800984 offset, len, p_clcb->counter);
985 gatt_act_read(p_clcb, p_clcb->counter);
986 }
987 else /* end of request, send callback */
988 {
989 gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p_clcb->p_attr_buf);
990 }
991 }
992 else /* exception, should not happen */
993 {
Sharvil Nanavatib44cc592014-05-04 10:03:35 -0700994 GATT_TRACE_ERROR("attr offset = %d p_attr_buf = %d ", offset, p_clcb->p_attr_buf);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800995 gatt_end_operation(p_clcb, GATT_NO_RESOURCES, (void *)p_clcb->p_attr_buf);
996 }
997 }
998 }
999 else
1000 {
1001 if (p_clcb->operation == GATTC_OPTYPE_DISCOVERY &&
1002 p_clcb->op_subtype == GATT_DISC_INC_SRVC &&
1003 p_clcb->read_uuid128.wait_for_read_rsp )
1004 {
1005 p_clcb->s_handle = p_clcb->read_uuid128.next_disc_start_hdl;
1006 p_clcb->read_uuid128.wait_for_read_rsp = FALSE;
1007 if (len == LEN_UUID_128)
1008 {
1009
1010 memcpy(p_clcb->read_uuid128.result.value.incl_service.service_type.uu.uuid128, p, len);
1011 p_clcb->read_uuid128.result.value.incl_service.service_type.len = LEN_UUID_128;
1012 if ( p_clcb->p_reg->app_cb.p_disc_res_cb)
1013 (*p_clcb->p_reg->app_cb.p_disc_res_cb)(p_clcb->conn_id, p_clcb->op_subtype, &p_clcb->read_uuid128.result);
1014 gatt_act_discovery(p_clcb) ;
1015 }
1016 else
1017 {
1018 gatt_end_operation(p_clcb, GATT_INVALID_PDU, (void *)p);
1019 }
1020 }
1021 }
1022
1023}
1024
1025
1026/*******************************************************************************
1027**
1028** Function gatt_process_handle_rsp
1029**
1030** Description This function is called to handle the write response
1031**
1032**
1033** Returns void
1034**
1035*******************************************************************************/
Andre Eisenbachccf9c152013-10-02 15:37:21 -07001036void gatt_process_handle_rsp(tGATT_CLCB *p_clcb)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001037{
Andre Eisenbachccf9c152013-10-02 15:37:21 -07001038 gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001039}
1040/*******************************************************************************
1041**
1042** Function gatt_process_mtu_rsp
1043**
1044** Description This function is called to process the configure MTU response.
1045**
1046**
1047** Returns void
1048**
1049*******************************************************************************/
1050void gatt_process_mtu_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data)
1051{
1052 UINT16 mtu;
Andre Eisenbachccf9c152013-10-02 15:37:21 -07001053 tGATT_STATUS status = GATT_SUCCESS;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001054
Andre Eisenbachccf9c152013-10-02 15:37:21 -07001055 if (len < GATT_MTU_RSP_MIN_LEN)
1056 {
Sharvil Nanavatib44cc592014-05-04 10:03:35 -07001057 GATT_TRACE_ERROR("invalid MTU response PDU received, discard.");
Andre Eisenbachccf9c152013-10-02 15:37:21 -07001058 status = GATT_INVALID_PDU;
1059 }
1060 else
1061 {
The Android Open Source Project5738f832012-12-12 16:00:35 -08001062 STREAM_TO_UINT16(mtu, p_data);
1063
1064 if (mtu < p_tcb->payload_size && mtu >= GATT_DEF_BLE_MTU_SIZE)
1065 p_tcb->payload_size = mtu;
Andre Eisenbachccf9c152013-10-02 15:37:21 -07001066 }
The Android Open Source Project5738f832012-12-12 16:00:35 -08001067
Andre Eisenbachccf9c152013-10-02 15:37:21 -07001068 gatt_end_operation(p_clcb, status, NULL);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001069}
1070/*******************************************************************************
1071**
1072** Function gatt_cmd_to_rsp_code
1073**
1074** Description The function convert a ATT command op code into the corresponding
1075** response code assume no error occurs.
1076**
1077** Returns response code.
1078**
1079*******************************************************************************/
1080UINT8 gatt_cmd_to_rsp_code (UINT8 cmd_code)
1081{
1082 UINT8 rsp_code = 0;
1083
1084 if (cmd_code > 1 && cmd_code != GATT_CMD_WRITE)
1085 {
1086 rsp_code = cmd_code + 1;
1087 }
1088 return rsp_code;
1089}
1090/*******************************************************************************
1091**
1092** Function gatt_cl_send_next_cmd_inq
1093**
1094** Description Find next command in queue and sent to server
1095**
1096** Returns TRUE if command sent, otherwise FALSE.
1097**
1098*******************************************************************************/
1099BOOLEAN gatt_cl_send_next_cmd_inq(tGATT_TCB *p_tcb)
1100{
1101 tGATT_CMD_Q *p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
1102 BOOLEAN sent = FALSE;
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -08001103 UINT8 rsp_code;
1104 tGATT_CLCB *p_clcb = NULL;
Andre Eisenbach17b04bd2014-03-28 14:54:22 -07001105 tGATT_STATUS att_ret = GATT_SUCCESS;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001106
1107 while (!sent &&
1108 p_tcb->pending_cl_req != p_tcb->next_slot_inq &&
1109 p_cmd->to_send && p_cmd->p_cmd != NULL)
1110 {
Andre Eisenbach17b04bd2014-03-28 14:54:22 -07001111 att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd->p_cmd);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001112
Andre Eisenbach17b04bd2014-03-28 14:54:22 -07001113 if (att_ret == GATT_SUCCESS || att_ret == GATT_CONGESTED)
The Android Open Source Project5738f832012-12-12 16:00:35 -08001114 {
Andre Eisenbach17b04bd2014-03-28 14:54:22 -07001115 sent = TRUE;
The Android Open Source Project5738f832012-12-12 16:00:35 -08001116 p_cmd->to_send = FALSE;
1117 p_cmd->p_cmd = NULL;
1118
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -08001119 /* dequeue the request if is write command or sign write */
1120 if (p_cmd->op_code != GATT_CMD_WRITE && p_cmd->op_code != GATT_SIGN_CMD_WRITE)
1121 {
Zhihai Xu5fba60a2014-02-05 20:04:48 -08001122 gatt_start_rsp_timer (p_cmd->clcb_idx);
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -08001123 }
1124 else
1125 {
1126 p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
1127
1128 /* if no ack needed, keep sending */
Andre Eisenbach17b04bd2014-03-28 14:54:22 -07001129 if (att_ret == GATT_SUCCESS)
1130 sent = FALSE;
1131
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -08001132 p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
1133 /* send command complete callback here */
Andre Eisenbach17b04bd2014-03-28 14:54:22 -07001134 gatt_end_operation(p_clcb, att_ret, NULL);
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -08001135 }
The Android Open Source Project5738f832012-12-12 16:00:35 -08001136 }
1137 else
1138 {
Sharvil Nanavatib44cc592014-05-04 10:03:35 -07001139 GATT_TRACE_ERROR("gatt_cl_send_next_cmd_inq: L2CAP sent error");
The Android Open Source Project5738f832012-12-12 16:00:35 -08001140
1141 memset(p_cmd, 0, sizeof(tGATT_CMD_Q));
1142 p_tcb->pending_cl_req ++;
1143 p_cmd = &p_tcb->cl_cmd_q[p_tcb->pending_cl_req];
1144 }
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -08001145
The Android Open Source Project5738f832012-12-12 16:00:35 -08001146 }
1147 return sent;
1148}
1149
1150/*******************************************************************************
1151**
1152** Function gatt_client_handle_server_rsp
1153**
1154** Description This function is called to handle the server response to
1155** client.
1156**
1157**
1158** Returns void
1159**
1160*******************************************************************************/
1161void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, UINT8 op_code,
1162 UINT16 len, UINT8 *p_data)
1163{
1164 tGATT_CLCB *p_clcb = NULL;
1165 UINT8 rsp_code;
1166
1167 if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF)
1168 {
1169 p_clcb = gatt_cmd_dequeue(p_tcb, &rsp_code);
1170
1171 rsp_code = gatt_cmd_to_rsp_code(rsp_code);
1172
1173 if (p_clcb == NULL || (rsp_code != op_code && op_code != GATT_RSP_ERROR))
1174 {
Sharvil Nanavatib44cc592014-05-04 10:03:35 -07001175 GATT_TRACE_WARNING ("ATT - Ignore wrong response. Receives (%02x) \
The Android Open Source Project5738f832012-12-12 16:00:35 -08001176 Request(%02x) Ignored", op_code, rsp_code);
1177
1178 return;
1179 }
1180 else
Zhihai Xu5fba60a2014-02-05 20:04:48 -08001181 {
1182 btu_stop_timer (&p_clcb->rsp_timer_ent);
1183 p_clcb->retry_count = 0;
1184 }
The Android Open Source Project5738f832012-12-12 16:00:35 -08001185 }
1186 /* the size of the message may not be bigger than the local max PDU size*/
1187 /* The message has to be smaller than the agreed MTU, len does not count op_code */
1188 if (len >= p_tcb->payload_size)
1189 {
Sharvil Nanavatib44cc592014-05-04 10:03:35 -07001190 GATT_TRACE_ERROR("invalid response/indicate pkt size: %d, PDU size: %d", len + 1, p_tcb->payload_size);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001191 if (op_code != GATT_HANDLE_VALUE_NOTIF &&
1192 op_code != GATT_HANDLE_VALUE_IND)
1193 gatt_end_operation(p_clcb, GATT_ERROR, NULL);
1194 }
1195 else
1196 {
1197 switch (op_code)
1198 {
1199 case GATT_RSP_ERROR:
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -07001200 gatt_process_error_rsp(p_tcb, p_clcb, op_code, len, p_data);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001201 break;
1202
1203 case GATT_RSP_MTU: /* 2 bytes mtu */
1204 gatt_process_mtu_rsp(p_tcb, p_clcb, len ,p_data);
1205 break;
1206
1207 case GATT_RSP_FIND_INFO:
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -07001208 gatt_process_read_info_rsp(p_tcb, p_clcb, op_code, len, p_data);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001209 break;
1210
1211 case GATT_RSP_READ_BY_TYPE:
1212 case GATT_RSP_READ_BY_GRP_TYPE:
1213 gatt_process_read_by_type_rsp(p_tcb, p_clcb, op_code, len, p_data);
1214 break;
1215
1216 case GATT_RSP_READ:
1217 case GATT_RSP_READ_BLOB:
1218 case GATT_RSP_READ_MULTI:
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -07001219 gatt_process_read_rsp(p_tcb, p_clcb, op_code, len, p_data);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001220 break;
1221
1222 case GATT_RSP_FIND_TYPE_VALUE: /* disc service with UUID */
Ganesh Ganapathi Batta7fa4fba2014-04-16 16:50:09 -07001223 gatt_process_find_type_value_rsp(p_tcb, p_clcb, len, p_data);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001224 break;
1225
1226 case GATT_RSP_WRITE:
Andre Eisenbachccf9c152013-10-02 15:37:21 -07001227 gatt_process_handle_rsp(p_clcb);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001228 break;
1229
1230 case GATT_RSP_PREPARE_WRITE:
1231 gatt_process_prep_write_rsp(p_tcb, p_clcb, op_code, len, p_data);
1232 break;
1233
1234 case GATT_RSP_EXEC_WRITE:
1235 gatt_end_operation(p_clcb, p_clcb->status, NULL);
1236 break;
1237
1238 case GATT_HANDLE_VALUE_NOTIF:
1239 case GATT_HANDLE_VALUE_IND:
1240 gatt_process_notification(p_tcb, op_code, len, p_data);
1241 break;
1242
1243 default:
Sharvil Nanavatib44cc592014-05-04 10:03:35 -07001244 GATT_TRACE_ERROR("Unknown opcode = %d", op_code);
The Android Open Source Project5738f832012-12-12 16:00:35 -08001245 break;
1246 }
1247 }
1248
1249 if (op_code != GATT_HANDLE_VALUE_IND && op_code != GATT_HANDLE_VALUE_NOTIF)
1250 {
1251 gatt_cl_send_next_cmd_inq(p_tcb);
1252 }
1253
1254 return;
1255}
1256
1257#endif /* BLE_INCLUDED */