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