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