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