1 /******************************************************************************
2 *
3 * Copyright (C) 2008-2014 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 ATT protocol functions
22 *
23 ******************************************************************************/
24
25 #include "common/bt_target.h"
26 #include "osi/allocator.h"
27
28 #if BLE_INCLUDED == TRUE
29
30 #include "gatt_int.h"
31 #include "stack/l2c_api.h"
32
33 #define GATT_HDR_FIND_TYPE_VALUE_LEN 21
34 #define GATT_OP_CODE_SIZE 1
35 /**********************************************************************
36 ** ATT protocl message building utility *
37 ***********************************************************************/
38 /*******************************************************************************
39 **
40 ** Function attp_build_mtu_exec_cmd
41 **
42 ** Description Build a exchange MTU request
43 **
44 ** Returns None.
45 **
46 *******************************************************************************/
attp_build_mtu_cmd(UINT8 op_code,UINT16 rx_mtu)47 BT_HDR *attp_build_mtu_cmd(UINT8 op_code, UINT16 rx_mtu)
48 {
49 BT_HDR *p_buf = NULL;
50 UINT8 *p;
51
52 if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + GATT_HDR_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
53 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
54
55 UINT8_TO_STREAM (p, op_code);
56 UINT16_TO_STREAM (p, rx_mtu);
57
58 p_buf->offset = L2CAP_MIN_OFFSET;
59 p_buf->len = GATT_HDR_SIZE; /* opcode + 2 bytes mtu */
60 }
61 return p_buf;
62 }
63 /*******************************************************************************
64 **
65 ** Function attp_build_exec_write_cmd
66 **
67 ** Description Build a execute write request or response.
68 **
69 ** Returns None.
70 **
71 *******************************************************************************/
attp_build_exec_write_cmd(UINT8 op_code,UINT8 flag)72 BT_HDR *attp_build_exec_write_cmd (UINT8 op_code, UINT8 flag)
73 {
74 BT_HDR *p_buf = NULL;
75 UINT8 *p;
76
77 if ((p_buf = (BT_HDR *)osi_malloc(GATT_DATA_BUF_SIZE)) != NULL) {
78 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
79
80 p_buf->offset = L2CAP_MIN_OFFSET;
81 p_buf->len = GATT_OP_CODE_SIZE;
82
83 UINT8_TO_STREAM (p, op_code);
84
85 if (op_code == GATT_REQ_EXEC_WRITE) {
86 flag &= GATT_PREP_WRITE_EXEC;
87 UINT8_TO_STREAM (p, flag);
88 p_buf->len += 1;
89 }
90
91 }
92
93 return p_buf;
94 }
95
96 /*******************************************************************************
97 **
98 ** Function attp_build_err_cmd
99 **
100 ** Description Build a exchange MTU request
101 **
102 ** Returns None.
103 **
104 *******************************************************************************/
attp_build_err_cmd(UINT8 cmd_code,UINT16 err_handle,UINT8 reason)105 BT_HDR *attp_build_err_cmd(UINT8 cmd_code, UINT16 err_handle, UINT8 reason)
106 {
107 BT_HDR *p_buf = NULL;
108 UINT8 *p;
109
110 if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + 5)) != NULL) {
111 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
112
113 UINT8_TO_STREAM (p, GATT_RSP_ERROR);
114 UINT8_TO_STREAM (p, cmd_code);
115 UINT16_TO_STREAM(p, err_handle);
116 UINT8_TO_STREAM (p, reason);
117
118 p_buf->offset = L2CAP_MIN_OFFSET;
119 /* GATT_HDR_SIZE (1B ERR_RSP op code+ 2B handle) + 1B cmd_op_code + 1B status */
120 p_buf->len = GATT_HDR_SIZE + 1 + 1;
121 }
122 return p_buf;
123 }
124 /*******************************************************************************
125 **
126 ** Function attp_build_browse_cmd
127 **
128 ** Description Build a read information request or read by type request
129 **
130 ** Returns None.
131 **
132 *******************************************************************************/
attp_build_browse_cmd(UINT8 op_code,UINT16 s_hdl,UINT16 e_hdl,tBT_UUID uuid)133 BT_HDR *attp_build_browse_cmd(UINT8 op_code, UINT16 s_hdl, UINT16 e_hdl, tBT_UUID uuid)
134 {
135 BT_HDR *p_buf = NULL;
136 UINT8 *p;
137 /* length of ATT_READ_BY_TYPE_REQ PDU: opcode(1) + start_handle (2) + end_handle (2) + uuid (2 or 16) */
138 const UINT8 payload_size = 1 + 2 + 2 + ((uuid.len == LEN_UUID_16) ? LEN_UUID_16 : LEN_UUID_128);
139
140 if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET)) != NULL) {
141 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
142 /* Describe the built message location and size */
143 p_buf->offset = L2CAP_MIN_OFFSET;
144 p_buf->len = GATT_OP_CODE_SIZE + 4;
145
146 UINT8_TO_STREAM (p, op_code);
147 UINT16_TO_STREAM (p, s_hdl);
148 UINT16_TO_STREAM (p, e_hdl);
149 p_buf->len += gatt_build_uuid_to_stream(&p, uuid);
150 }
151
152 return p_buf;
153 }
154 /*******************************************************************************
155 **
156 ** Function attp_build_read_handles_cmd
157 **
158 ** Description Build a read by type and value request.
159 **
160 ** Returns pointer to the command buffer.
161 **
162 *******************************************************************************/
attp_build_read_by_type_value_cmd(UINT16 payload_size,tGATT_FIND_TYPE_VALUE * p_value_type)163 BT_HDR *attp_build_read_by_type_value_cmd (UINT16 payload_size, tGATT_FIND_TYPE_VALUE *p_value_type)
164 {
165 BT_HDR *p_buf = NULL;
166 UINT8 *p;
167 UINT16 len = p_value_type->value_len;
168
169 if ((p_buf = (BT_HDR *)osi_malloc((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL) {
170 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
171
172 p_buf->offset = L2CAP_MIN_OFFSET;
173 p_buf->len = 5; /* opcode + s_handle + e_handle */
174
175 UINT8_TO_STREAM (p, GATT_REQ_FIND_TYPE_VALUE);
176 UINT16_TO_STREAM (p, p_value_type->s_handle);
177 UINT16_TO_STREAM (p, p_value_type->e_handle);
178
179 p_buf->len += gatt_build_uuid_to_stream(&p, p_value_type->uuid);
180
181 if (p_value_type->value_len + p_buf->len > payload_size ) {
182 len = payload_size - p_buf->len;
183 }
184
185 memcpy (p, p_value_type->value, len);
186 p_buf->len += len;
187 }
188
189 return p_buf;
190 }
191 /*******************************************************************************
192 **
193 ** Function attp_build_read_multi_cmd
194 **
195 ** Description Build a read multiple request
196 **
197 ** Returns None.
198 **
199 *******************************************************************************/
attp_build_read_multi_cmd(UINT8 op_code,UINT16 payload_size,UINT16 num_handle,UINT16 * p_handle)200 BT_HDR *attp_build_read_multi_cmd(UINT8 op_code, UINT16 payload_size, UINT16 num_handle, UINT16 *p_handle)
201 {
202 BT_HDR *p_buf = NULL;
203 UINT8 *p, i = 0;
204
205 if ((p_buf = (BT_HDR *)osi_malloc((UINT16)(sizeof(BT_HDR) + num_handle * 2 + 1 + L2CAP_MIN_OFFSET))) != NULL) {
206 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
207
208 p_buf->offset = L2CAP_MIN_OFFSET;
209 p_buf->len = 1;
210
211 UINT8_TO_STREAM (p, op_code);
212
213 for (i = 0; i < num_handle && p_buf->len + 2 <= payload_size; i ++) {
214 UINT16_TO_STREAM (p, *(p_handle + i));
215 p_buf->len += 2;
216 }
217 }
218
219 return p_buf;
220 }
221 /*******************************************************************************
222 **
223 ** Function attp_build_handle_cmd
224 **
225 ** Description Build a read /read blob request
226 **
227 ** Returns None.
228 **
229 *******************************************************************************/
attp_build_handle_cmd(UINT8 op_code,UINT16 handle,UINT16 offset)230 BT_HDR *attp_build_handle_cmd(UINT8 op_code, UINT16 handle, UINT16 offset)
231 {
232 BT_HDR *p_buf = NULL;
233 UINT8 *p;
234
235 if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 5 + L2CAP_MIN_OFFSET)) != NULL) {
236 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
237
238 p_buf->offset = L2CAP_MIN_OFFSET;
239
240 UINT8_TO_STREAM (p, op_code);
241 p_buf->len = 1;
242
243 UINT16_TO_STREAM (p, handle);
244 p_buf->len += 2;
245
246 if (op_code == GATT_REQ_READ_BLOB) {
247 UINT16_TO_STREAM (p, offset);
248 p_buf->len += 2;
249 }
250
251 }
252
253 return p_buf;
254 }
255 /*******************************************************************************
256 **
257 ** Function attp_build_opcode_cmd
258 **
259 ** Description Build a request/response with opcode only.
260 **
261 ** Returns None.
262 **
263 *******************************************************************************/
attp_build_opcode_cmd(UINT8 op_code)264 BT_HDR *attp_build_opcode_cmd(UINT8 op_code)
265 {
266 BT_HDR *p_buf = NULL;
267 UINT8 *p;
268
269 if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 1 + L2CAP_MIN_OFFSET)) != NULL) {
270 p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
271 p_buf->offset = L2CAP_MIN_OFFSET;
272
273 UINT8_TO_STREAM (p, op_code);
274 p_buf->len = 1;
275 }
276
277 return p_buf;
278 }
279 /*******************************************************************************
280 **
281 ** Function attp_build_value_cmd
282 **
283 ** Description Build a attribute value request
284 **
285 ** Returns None.
286 **
287 *******************************************************************************/
attp_build_value_cmd(UINT16 payload_size,UINT8 op_code,UINT16 handle,UINT16 offset,UINT16 len,UINT8 * p_data)288 BT_HDR *attp_build_value_cmd (UINT16 payload_size, UINT8 op_code, UINT16 handle,
289 UINT16 offset, UINT16 len, UINT8 *p_data)
290 {
291 BT_HDR *p_buf = NULL;
292 UINT8 *p, *pp, pair_len, *p_pair_len;
293
294 if ((p_buf = (BT_HDR *)osi_malloc((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL) {
295 p = pp = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
296
297 UINT8_TO_STREAM (p, op_code);
298 p_buf->offset = L2CAP_MIN_OFFSET;
299 p_buf->len = 1;
300
301 if (op_code == GATT_RSP_READ_BY_TYPE) {
302 p_pair_len = p;
303 pair_len = len + 2;
304 UINT8_TO_STREAM (p, pair_len);
305 p_buf->len += 1;
306 }
307 if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ && op_code != GATT_HANDLE_MULTI_VALUE_NOTIF) {
308 UINT16_TO_STREAM (p, handle);
309 p_buf->len += 2;
310 }
311
312 if (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_RSP_PREPARE_WRITE ) {
313 UINT16_TO_STREAM (p, offset);
314 p_buf->len += 2;
315 }
316
317 if(payload_size < GATT_DEF_BLE_MTU_SIZE || payload_size > GATT_MAX_MTU_SIZE) {
318 GATT_TRACE_ERROR("invalid payload_size %d", payload_size);
319 osi_free(p_buf);
320 return NULL;
321 }
322
323 if (len > 0 && p_data != NULL) {
324 /* ensure data not exceed MTU size */
325 if (payload_size - p_buf->len < len) {
326 len = payload_size - p_buf->len;
327 /* update handle value pair length */
328 if (op_code == GATT_RSP_READ_BY_TYPE) {
329 *p_pair_len = (len + 2);
330 }
331
332 GATT_TRACE_WARNING("attribute value too long, to be truncated to %d", len);
333 }
334
335 ARRAY_TO_STREAM (p, p_data, len);
336 p_buf->len += len;
337 }
338 }
339 return p_buf;
340 }
341
342 /*******************************************************************************
343 **
344 ** Function attp_send_msg_to_l2cap
345 **
346 ** Description Send message to L2CAP.
347 **
348 *******************************************************************************/
attp_send_msg_to_l2cap(tGATT_TCB * p_tcb,BT_HDR * p_toL2CAP)349 tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP)
350 {
351 UINT16 l2cap_ret;
352
353
354 if (p_tcb->att_lcid == L2CAP_ATT_CID) {
355 l2cap_ret = L2CA_SendFixedChnlData (L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP);
356 } else {
357 #if (CLASSIC_BT_INCLUDED == TRUE)
358 l2cap_ret = (UINT16) L2CA_DataWrite (p_tcb->att_lcid, p_toL2CAP);
359 #else
360 l2cap_ret = L2CAP_DW_FAILED;
361 #endif ///CLASSIC_BT_INCLUDED == TRUE
362 }
363
364 if (l2cap_ret == L2CAP_DW_FAILED) {
365 GATT_TRACE_DEBUG("ATT failed to pass msg:0x%0x to L2CAP",
366 *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset));
367 return GATT_INTERNAL_ERROR;
368 } else if (l2cap_ret == L2CAP_DW_CONGESTED) {
369 GATT_TRACE_DEBUG("ATT congested, message accepted");
370 return GATT_CONGESTED;
371 }
372 return GATT_SUCCESS;
373 }
374
375 /*******************************************************************************
376 **
377 ** Function attp_build_sr_msg
378 **
379 ** Description Build ATT Server PDUs.
380 **
381 *******************************************************************************/
attp_build_sr_msg(tGATT_TCB * p_tcb,UINT8 op_code,tGATT_SR_MSG * p_msg)382 BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg)
383 {
384 BT_HDR *p_cmd = NULL;
385 UINT16 offset = 0;
386
387 switch (op_code) {
388 case GATT_RSP_READ_BLOB:
389 case GATT_RSP_PREPARE_WRITE:
390 case GATT_RSP_READ_BY_TYPE:
391 case GATT_RSP_READ:
392 case GATT_HANDLE_VALUE_NOTIF:
393 case GATT_HANDLE_VALUE_IND:
394 case GATT_HANDLE_MULTI_VALUE_NOTIF:
395 case GATT_RSP_ERROR:
396 case GATT_RSP_MTU:
397 /* Need to check the validation of parameter p_msg*/
398 if (p_msg == NULL) {
399 GATT_TRACE_ERROR("Invalid parameters in %s, op_code=0x%x, the p_msg should not be NULL.", __func__, op_code);
400 return NULL;
401 }
402 break;
403
404 default:
405 break;
406 }
407
408 switch (op_code) {
409 case GATT_RSP_READ_BLOB:
410 case GATT_RSP_PREPARE_WRITE:
411 GATT_TRACE_EVENT ("ATT_RSP_READ_BLOB/GATT_RSP_PREPARE_WRITE: len = %d offset = %d",
412 p_msg->attr_value.len, p_msg->attr_value.offset);
413 offset = p_msg->attr_value.offset;
414 /* Coverity: [FALSE-POSITIVE error] intended fall through */
415 /* Missing break statement between cases in switch statement */
416 /* fall through */
417 case GATT_RSP_READ_BY_TYPE:
418 case GATT_RSP_READ:
419 case GATT_HANDLE_VALUE_NOTIF:
420 case GATT_HANDLE_VALUE_IND:
421 case GATT_HANDLE_MULTI_VALUE_NOTIF:
422 p_cmd = attp_build_value_cmd(p_tcb->payload_size,
423 op_code,
424 p_msg->attr_value.handle,
425 offset,
426 p_msg->attr_value.len,
427 p_msg->attr_value.value);
428 break;
429
430 case GATT_RSP_WRITE:
431 p_cmd = attp_build_opcode_cmd(op_code);
432 break;
433
434 case GATT_RSP_ERROR:
435 p_cmd = attp_build_err_cmd(p_msg->error.cmd_code, p_msg->error.handle, p_msg->error.reason);
436 break;
437
438 case GATT_RSP_EXEC_WRITE:
439 p_cmd = attp_build_exec_write_cmd(op_code, 0);
440 break;
441
442 case GATT_RSP_MTU:
443 p_cmd = attp_build_mtu_cmd(op_code, p_msg->mtu);
444 break;
445
446 default:
447 GATT_TRACE_DEBUG("attp_build_sr_msg: unknown op code = %d", op_code);
448 break;
449 }
450
451 if (!p_cmd) {
452 GATT_TRACE_ERROR("No resources");
453 }
454
455 return p_cmd;
456 }
457
458 /*******************************************************************************
459 **
460 ** Function attp_send_sr_msg
461 **
462 ** Description This function sends the server response or indication message
463 ** to client.
464 **
465 ** Parameter p_tcb: pointer to the connecton control block.
466 ** p_msg: pointer to message parameters structure.
467 **
468 ** Returns GATT_SUCCESS if successfully sent; otherwise error code.
469 **
470 **
471 *******************************************************************************/
attp_send_sr_msg(tGATT_TCB * p_tcb,BT_HDR * p_msg)472 tGATT_STATUS attp_send_sr_msg (tGATT_TCB *p_tcb, BT_HDR *p_msg)
473 {
474 tGATT_STATUS cmd_sent = GATT_NO_RESOURCES;
475
476 if (p_tcb != NULL) {
477 if (p_msg != NULL) {
478 p_msg->offset = L2CAP_MIN_OFFSET;
479 cmd_sent = attp_send_msg_to_l2cap (p_tcb, p_msg);
480 }
481 }
482 return cmd_sent;
483 }
484
485 /*******************************************************************************
486 **
487 ** Function attp_cl_send_cmd
488 **
489 ** Description Send a ATT command or enqueue it.
490 **
491 ** Returns GATT_SUCCESS if command sent
492 ** GATT_CONGESTED if command sent but channel congested
493 ** GATT_CMD_STARTED if command queue up in GATT
494 ** GATT_ERROR if command sending failure
495 **
496 *******************************************************************************/
attp_cl_send_cmd(tGATT_TCB * p_tcb,UINT16 clcb_idx,UINT8 cmd_code,BT_HDR * p_cmd)497 tGATT_STATUS attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR *p_cmd)
498 {
499 tGATT_STATUS att_ret = GATT_SUCCESS;
500
501 if (p_tcb != NULL) {
502 cmd_code &= ~GATT_AUTH_SIGN_MASK;
503
504 /* no pending request or value confirmation */
505 if (p_tcb->pending_cl_req == p_tcb->next_slot_inq ||
506 cmd_code == GATT_HANDLE_VALUE_CONF) {
507 att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd);
508 if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS) {
509 /* do not enq cmd if handle value confirmation or set request */
510 if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE) {
511 gatt_start_rsp_timer (clcb_idx);
512 gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL);
513 }
514 } else {
515 att_ret = GATT_INTERNAL_ERROR;
516 }
517 } else {
518 att_ret = GATT_CMD_STARTED;
519 gatt_cmd_enq(p_tcb, clcb_idx, TRUE, cmd_code, p_cmd);
520 }
521 } else {
522 att_ret = GATT_ERROR;
523 }
524
525 return att_ret;
526 }
527 /*******************************************************************************
528 **
529 ** Function attp_send_cl_msg
530 **
531 ** Description This function sends the client request or confirmation message
532 ** to server.
533 **
534 ** Parameter p_tcb: pointer to the connection control block.
535 ** clcb_idx: clcb index
536 ** op_code: message op code.
537 ** p_msg: pointer to message parameters structure.
538 **
539 ** Returns GATT_SUCCESS if successfully sent; otherwise error code.
540 **
541 **
542 *******************************************************************************/
attp_send_cl_msg(tGATT_TCB * p_tcb,UINT16 clcb_idx,UINT8 op_code,tGATT_CL_MSG * p_msg)543 tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg)
544 {
545 tGATT_STATUS status = GATT_NO_RESOURCES;
546 BT_HDR *p_cmd = NULL;
547 UINT16 offset = 0, handle;
548
549 if (p_tcb != NULL) {
550 switch (op_code) {
551 case GATT_REQ_MTU:
552 if (p_msg->mtu <= GATT_MAX_MTU_SIZE) {
553 p_tcb->payload_size = p_msg->mtu;
554 p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
555 } else {
556 status = GATT_ILLEGAL_PARAMETER;
557 }
558 break;
559
560 case GATT_REQ_FIND_INFO:
561 case GATT_REQ_READ_BY_TYPE:
562 case GATT_REQ_READ_BY_GRP_TYPE:
563 if (GATT_HANDLE_IS_VALID (p_msg->browse.s_handle) &&
564 GATT_HANDLE_IS_VALID (p_msg->browse.e_handle) &&
565 p_msg->browse.s_handle <= p_msg->browse.e_handle) {
566 p_cmd = attp_build_browse_cmd(op_code,
567 p_msg->browse.s_handle,
568 p_msg->browse.e_handle,
569 p_msg->browse.uuid);
570 } else {
571 status = GATT_ILLEGAL_PARAMETER;
572 }
573 break;
574
575 case GATT_REQ_READ_BLOB:
576 offset = p_msg->read_blob.offset;
577 /* fall through */
578 case GATT_REQ_READ:
579 handle = (op_code == GATT_REQ_READ) ? p_msg->handle : p_msg->read_blob.handle;
580 /* handle checking */
581 if (GATT_HANDLE_IS_VALID (handle)) {
582 p_cmd = attp_build_handle_cmd(op_code, handle, offset);
583 } else {
584 status = GATT_ILLEGAL_PARAMETER;
585 }
586 break;
587
588 case GATT_HANDLE_VALUE_CONF:
589 p_cmd = attp_build_opcode_cmd(op_code);
590 break;
591
592 case GATT_REQ_PREPARE_WRITE:
593 offset = p_msg->attr_value.offset;
594 /* fall through */
595 case GATT_REQ_WRITE:
596 case GATT_CMD_WRITE:
597 case GATT_SIGN_CMD_WRITE:
598 if (GATT_HANDLE_IS_VALID (p_msg->attr_value.handle)) {
599 p_cmd = attp_build_value_cmd (p_tcb->payload_size,
600 op_code, p_msg->attr_value.handle,
601 offset,
602 p_msg->attr_value.len,
603 p_msg->attr_value.value);
604 } else {
605 status = GATT_ILLEGAL_PARAMETER;
606 }
607 break;
608
609 case GATT_REQ_EXEC_WRITE:
610 p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
611 break;
612
613 case GATT_REQ_FIND_TYPE_VALUE:
614 p_cmd = attp_build_read_by_type_value_cmd(p_tcb->payload_size, &p_msg->find_type_value);
615 break;
616
617 case GATT_REQ_READ_MULTI:
618 case GATT_REQ_READ_MULTI_VAR:
619 p_cmd = attp_build_read_multi_cmd(op_code, p_tcb->payload_size,
620 p_msg->read_multi.num_handles,
621 p_msg->read_multi.handles);
622 break;
623
624 default:
625 break;
626 }
627
628 if (p_cmd != NULL) {
629 status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd);
630 }
631
632 } else {
633 GATT_TRACE_ERROR("Peer device not connected");
634 }
635
636 return status;
637 }
638 #endif
639