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