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