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 <bluetooth/log.h>
26 
27 #include "gatt_int.h"
28 #include "internal_include/bt_target.h"
29 #include "l2c_api.h"
30 #include "osi/include/allocator.h"
31 #include "stack/include/bt_hdr.h"
32 #include "stack/include/bt_types.h"
33 #include "stack/include/l2cdefs.h"
34 #include "types/bluetooth/uuid.h"
35 
36 #define GATT_HDR_FIND_TYPE_VALUE_LEN 21
37 #define GATT_OP_CODE_SIZE 1
38 #define GATT_START_END_HANDLE_SIZE 4
39 
40 using base::StringPrintf;
41 using bluetooth::Uuid;
42 using namespace bluetooth;
43 
44 /**********************************************************************
45  *   ATT protocol message building utility                              *
46  **********************************************************************/
47 /*******************************************************************************
48  *
49  * Function         attp_build_mtu_exec_cmd
50  *
51  * Description      Build a exchange MTU request
52  *
53  * Returns          None.
54  *
55  ******************************************************************************/
attp_build_mtu_cmd(uint8_t op_code,uint16_t rx_mtu)56 static BT_HDR* attp_build_mtu_cmd(uint8_t op_code, uint16_t rx_mtu) {
57   uint8_t* p;
58   BT_HDR* p_buf =
59       (BT_HDR*)osi_malloc(sizeof(BT_HDR) + GATT_HDR_SIZE + L2CAP_MIN_OFFSET);
60 
61   p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
62   UINT8_TO_STREAM(p, op_code);
63   UINT16_TO_STREAM(p, rx_mtu);
64 
65   p_buf->offset = L2CAP_MIN_OFFSET;
66   p_buf->len = GATT_HDR_SIZE; /* opcode + 2 bytes mtu */
67 
68   return p_buf;
69 }
70 /*******************************************************************************
71  *
72  * Function         attp_build_exec_write_cmd
73  *
74  * Description      Build a execute write request or response.
75  *
76  * Returns          None.
77  *
78  ******************************************************************************/
attp_build_exec_write_cmd(uint8_t op_code,uint8_t flag)79 static BT_HDR* attp_build_exec_write_cmd(uint8_t op_code, uint8_t flag) {
80   BT_HDR* p_buf = (BT_HDR*)osi_malloc(GATT_DATA_BUF_SIZE);
81   uint8_t* p;
82 
83   p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
84 
85   p_buf->offset = L2CAP_MIN_OFFSET;
86   p_buf->len = GATT_OP_CODE_SIZE;
87 
88   UINT8_TO_STREAM(p, op_code);
89 
90   if (op_code == GATT_REQ_EXEC_WRITE) {
91     flag &= GATT_PREP_WRITE_EXEC;
92     UINT8_TO_STREAM(p, flag);
93     p_buf->len += 1;
94   }
95 
96   return p_buf;
97 }
98 
99 /*******************************************************************************
100  *
101  * Function         attp_build_err_cmd
102  *
103  * Description      Build a exchange MTU request
104  *
105  * Returns          None.
106  *
107  ******************************************************************************/
attp_build_err_cmd(uint8_t cmd_code,uint16_t err_handle,uint8_t reason)108 static BT_HDR* attp_build_err_cmd(uint8_t cmd_code, uint16_t err_handle,
109                                   uint8_t reason) {
110   uint8_t* p;
111   BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + 5);
112 
113   p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
114   UINT8_TO_STREAM(p, GATT_RSP_ERROR);
115   UINT8_TO_STREAM(p, cmd_code);
116   UINT16_TO_STREAM(p, err_handle);
117   UINT8_TO_STREAM(p, reason);
118 
119   p_buf->offset = L2CAP_MIN_OFFSET;
120   /* GATT_HDR_SIZE (1B ERR_RSP op code+ 2B handle) + 1B cmd_op_code  + 1B status
121    */
122   p_buf->len = GATT_HDR_SIZE + 1 + 1;
123 
124   return p_buf;
125 }
126 /*******************************************************************************
127  *
128  * Function         attp_build_browse_cmd
129  *
130  * Description      Build a read information request or read by type request
131  *
132  * Returns          None.
133  *
134  ******************************************************************************/
attp_build_browse_cmd(uint8_t op_code,uint16_t s_hdl,uint16_t e_hdl,const bluetooth::Uuid & uuid)135 static BT_HDR* attp_build_browse_cmd(uint8_t op_code, uint16_t s_hdl,
136                                      uint16_t e_hdl,
137                                      const bluetooth::Uuid& uuid) {
138   const size_t payload_size =
139       (GATT_OP_CODE_SIZE) + (GATT_START_END_HANDLE_SIZE) + (Uuid::kNumBytes128);
140   BT_HDR* p_buf =
141       (BT_HDR*)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
142 
143   uint8_t* p = (uint8_t*)(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   return p_buf;
154 }
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_by_type_value_cmd(uint16_t payload_size,tGATT_FIND_TYPE_VALUE * p_value_type)165 static BT_HDR* attp_build_read_by_type_value_cmd(
166     uint16_t payload_size, tGATT_FIND_TYPE_VALUE* p_value_type) {
167   uint8_t* p;
168   uint16_t len = p_value_type->value_len;
169   BT_HDR* p_buf = nullptr;
170 
171   if (payload_size < 5) {
172     return nullptr;
173   }
174 
175   p_buf =
176       (BT_HDR*)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
177 
178   p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
179   p_buf->offset = L2CAP_MIN_OFFSET;
180   p_buf->len = 5; /* opcode + s_handle + e_handle */
181 
182   UINT8_TO_STREAM(p, GATT_REQ_FIND_TYPE_VALUE);
183   UINT16_TO_STREAM(p, p_value_type->s_handle);
184   UINT16_TO_STREAM(p, p_value_type->e_handle);
185 
186   p_buf->len += gatt_build_uuid_to_stream(&p, p_value_type->uuid);
187 
188   if (p_value_type->value_len + p_buf->len > payload_size)
189     len = payload_size - p_buf->len;
190 
191   memcpy(p, p_value_type->value, len);
192   p_buf->len += len;
193 
194   return p_buf;
195 }
196 
197 /*******************************************************************************
198  *
199  * Function         attp_build_read_multi_cmd
200  *
201  * Description      Build a read multiple request
202  *
203  * Returns          None.
204  *
205  ******************************************************************************/
attp_build_read_multi_cmd(uint8_t op_code,uint16_t payload_size,uint16_t num_handle,uint16_t * p_handle)206 static BT_HDR* attp_build_read_multi_cmd(uint8_t op_code, uint16_t payload_size,
207                                          uint16_t num_handle,
208                                          uint16_t* p_handle) {
209   uint8_t* p;
210   uint16_t i = 0;
211   BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + num_handle * 2 + 1 +
212                                       L2CAP_MIN_OFFSET);
213 
214   p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
215   p_buf->offset = L2CAP_MIN_OFFSET;
216   p_buf->len = 1;
217 
218   UINT8_TO_STREAM(p, op_code);
219 
220   for (i = 0; i < num_handle && p_buf->len + 2 <= payload_size; i++) {
221     UINT16_TO_STREAM(p, *(p_handle + i));
222     p_buf->len += 2;
223   }
224 
225   return p_buf;
226 }
227 /*******************************************************************************
228  *
229  * Function         attp_build_handle_cmd
230  *
231  * Description      Build a read /read blob request
232  *
233  * Returns          None.
234  *
235  ******************************************************************************/
attp_build_handle_cmd(uint8_t op_code,uint16_t handle,uint16_t offset)236 static BT_HDR* attp_build_handle_cmd(uint8_t op_code, uint16_t handle,
237                                      uint16_t offset) {
238   uint8_t* p;
239   BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + 5 + L2CAP_MIN_OFFSET);
240 
241   p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
242   p_buf->offset = L2CAP_MIN_OFFSET;
243 
244   UINT8_TO_STREAM(p, op_code);
245   p_buf->len = 1;
246 
247   UINT16_TO_STREAM(p, handle);
248   p_buf->len += 2;
249 
250   if (op_code == GATT_REQ_READ_BLOB) {
251     UINT16_TO_STREAM(p, offset);
252     p_buf->len += 2;
253   }
254 
255   return p_buf;
256 }
257 
258 /*******************************************************************************
259  *
260  * Function         attp_build_opcode_cmd
261  *
262  * Description      Build a  request/response with opcode only.
263  *
264  * Returns          None.
265  *
266  ******************************************************************************/
attp_build_opcode_cmd(uint8_t op_code)267 static BT_HDR* attp_build_opcode_cmd(uint8_t op_code) {
268   uint8_t* p;
269   BT_HDR* p_buf = (BT_HDR*)osi_malloc(sizeof(BT_HDR) + 1 + L2CAP_MIN_OFFSET);
270 
271   p = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
272   p_buf->offset = L2CAP_MIN_OFFSET;
273 
274   UINT8_TO_STREAM(p, op_code);
275   p_buf->len = 1;
276 
277   return p_buf;
278 }
279 
280 /*******************************************************************************
281  *
282  * Function         attp_build_value_cmd
283  *
284  * Description      Build a attribute value request
285  *
286  * Returns          None.
287  *
288  ******************************************************************************/
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)289 static BT_HDR* attp_build_value_cmd(uint16_t payload_size, uint8_t op_code,
290                                     uint16_t handle, uint16_t offset,
291                                     uint16_t len, uint8_t* p_data) {
292   uint8_t *p, *pp, *p_pair_len;
293   size_t pair_len;
294   size_t size_now = 1;
295 
296 #define CHECK_SIZE()                        \
297   do {                                      \
298     if (size_now > payload_size) {          \
299       log::error("payload size too small"); \
300       osi_free(p_buf);                      \
301       return nullptr;                       \
302     }                                       \
303   } while (false)
304 
305   BT_HDR* p_buf =
306       (BT_HDR*)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET);
307 
308   p = pp = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;
309 
310   CHECK_SIZE();
311   UINT8_TO_STREAM(p, op_code);
312   p_buf->offset = L2CAP_MIN_OFFSET;
313 
314   if (op_code == GATT_RSP_READ_BY_TYPE) {
315     p_pair_len = p++;
316     pair_len = len + 2;
317     size_now += 1;
318     CHECK_SIZE();
319     // this field will be backfilled in the end of this function
320   }
321 
322   if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ) {
323     size_now += 2;
324     CHECK_SIZE();
325     UINT16_TO_STREAM(p, handle);
326   }
327 
328   if (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_RSP_PREPARE_WRITE) {
329     size_now += 2;
330     CHECK_SIZE();
331     UINT16_TO_STREAM(p, offset);
332   }
333 
334   if (len > 0 && p_data != NULL) {
335     /* ensure data not exceed MTU size */
336     if (payload_size - size_now < len) {
337       len = payload_size - size_now;
338       /* update handle value pair length */
339       if (op_code == GATT_RSP_READ_BY_TYPE) {
340         pair_len = (len + 2);
341       }
342 
343       log::warn("attribute value too long, to be truncated to {}", len);
344     }
345 
346     size_now += len;
347     CHECK_SIZE();
348     ARRAY_TO_STREAM(p, p_data, len);
349   }
350 
351   // backfill pair len field
352   if (op_code == GATT_RSP_READ_BY_TYPE) {
353     if (pair_len > UINT8_MAX) {
354       log::error("pair_len greater than {}", UINT8_MAX);
355       osi_free(p_buf);
356       return nullptr;
357     }
358 
359     *p_pair_len = (uint8_t)pair_len;
360   }
361 
362 #undef CHECK_SIZE
363 
364   p_buf->len = (uint16_t)size_now;
365   return p_buf;
366 }
367 
368 /*******************************************************************************
369  *
370  * Function         attp_send_msg_to_l2cap
371  *
372  * Description      Send message to L2CAP.
373  *
374  ******************************************************************************/
attp_send_msg_to_l2cap(tGATT_TCB & tcb,uint16_t lcid,BT_HDR * p_toL2CAP)375 tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB& tcb, uint16_t lcid,
376                                     BT_HDR* p_toL2CAP) {
377   uint16_t l2cap_ret;
378 
379   if (lcid == L2CAP_ATT_CID) {
380     log::debug("Sending ATT message on att fixed channel");
381     l2cap_ret = L2CA_SendFixedChnlData(lcid, tcb.peer_bda, p_toL2CAP);
382   } else {
383     log::debug("Sending ATT message on lcid:{}", lcid);
384     l2cap_ret = (uint16_t)L2CA_DataWrite(lcid, p_toL2CAP);
385   }
386 
387   if (l2cap_ret == L2CAP_DW_FAILED) {
388     log::error("failed to write data to L2CAP");
389     return GATT_INTERNAL_ERROR;
390   } else if (l2cap_ret == L2CAP_DW_CONGESTED) {
391     log::verbose("ATT congested, message accepted");
392     return GATT_CONGESTED;
393   }
394   return GATT_SUCCESS;
395 }
396 
397 /** Build ATT Server PDUs */
attp_build_sr_msg(tGATT_TCB & tcb,uint8_t op_code,tGATT_SR_MSG * p_msg,uint16_t payload_size)398 BT_HDR* attp_build_sr_msg(tGATT_TCB& tcb, uint8_t op_code, tGATT_SR_MSG* p_msg,
399                           uint16_t payload_size) {
400   uint16_t offset = 0;
401 
402   if (payload_size == 0) {
403     log::error(
404         "Cannot send response (op: 0x{:02x}) due to payload size = 0, {}",
405         op_code, tcb.peer_bda);
406     return nullptr;
407   }
408 
409   switch (op_code) {
410     case GATT_RSP_READ_BLOB:
411     case GATT_RSP_PREPARE_WRITE:
412       log::verbose(
413           "ATT_RSP_READ_BLOB/GATT_RSP_PREPARE_WRITE: len = {} offset = {}",
414           p_msg->attr_value.len, p_msg->attr_value.offset);
415       offset = p_msg->attr_value.offset;
416       FALLTHROUGH_INTENDED; /* FALLTHROUGH */
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       return attp_build_value_cmd(
422           payload_size, op_code, p_msg->attr_value.handle, offset,
423           p_msg->attr_value.len, p_msg->attr_value.value);
424 
425     case GATT_RSP_WRITE:
426       return attp_build_opcode_cmd(op_code);
427 
428     case GATT_RSP_ERROR:
429       return attp_build_err_cmd(p_msg->error.cmd_code, p_msg->error.handle,
430                                 p_msg->error.reason);
431 
432     case GATT_RSP_EXEC_WRITE:
433       return attp_build_exec_write_cmd(op_code, 0);
434 
435     case GATT_RSP_MTU:
436       return attp_build_mtu_cmd(op_code, p_msg->mtu);
437 
438     default:
439       log::fatal("attp_build_sr_msg: unknown op code = {}", op_code);
440       return nullptr;
441   }
442 }
443 
444 /*******************************************************************************
445  *
446  * Function         attp_send_sr_msg
447  *
448  * Description      This function sends the server response or indication
449  *                  message to client.
450  *
451  * Parameter        p_tcb: pointer to the connection control block.
452  *                  p_msg: pointer to message parameters structure.
453  *
454  * Returns          GATT_SUCCESS if successfully sent; otherwise error code.
455  *
456  ******************************************************************************/
attp_send_sr_msg(tGATT_TCB & tcb,uint16_t cid,BT_HDR * p_msg)457 tGATT_STATUS attp_send_sr_msg(tGATT_TCB& tcb, uint16_t cid, BT_HDR* p_msg) {
458   if (p_msg == NULL) {
459     log::warn("Unable to send empty message");
460     return GATT_NO_RESOURCES;
461   }
462 
463   log::debug("Sending server response or indication message to client");
464   p_msg->offset = L2CAP_MIN_OFFSET;
465   return attp_send_msg_to_l2cap(tcb, cid, p_msg);
466 }
467 
468 /*******************************************************************************
469  *
470  * Function         attp_cl_send_cmd
471  *
472  * Description      Send a ATT command or enqueue it.
473  *
474  * Returns          GATT_SUCCESS if command sent
475  *                  GATT_CONGESTED if command sent but channel congested
476  *                  GATT_CMD_STARTED if command queue up in GATT
477  *                  GATT_ERROR if command sending failure
478  *
479  ******************************************************************************/
attp_cl_send_cmd(tGATT_TCB & tcb,tGATT_CLCB * p_clcb,uint8_t cmd_code,BT_HDR * p_cmd)480 static tGATT_STATUS attp_cl_send_cmd(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
481                                      uint8_t cmd_code, BT_HDR* p_cmd) {
482   cmd_code &= ~GATT_AUTH_SIGN_MASK;
483 
484   if (gatt_tcb_is_cid_busy(tcb, p_clcb->cid) &&
485       cmd_code != GATT_HANDLE_VALUE_CONF) {
486     if (gatt_cmd_enq(tcb, p_clcb, true, cmd_code, p_cmd)) {
487       log::debug("Enqueued ATT command {} conn_id=0x{:04x}, cid={}",
488                  fmt::ptr(p_clcb), p_clcb->conn_id, p_clcb->cid);
489       return GATT_CMD_STARTED;
490     }
491 
492     log::error("{}, cid 0x{:02x} already disconnected", tcb.peer_bda,
493                p_clcb->cid);
494     return GATT_INTERNAL_ERROR;
495   }
496 
497   log::debug(
498       "Sending ATT command to l2cap cid:0x{:04x} eatt_channels:{} transport:{}",
499       p_clcb->cid, tcb.eatt, bt_transport_text(tcb.transport));
500   tGATT_STATUS att_ret = attp_send_msg_to_l2cap(tcb, p_clcb->cid, p_cmd);
501   if (att_ret != GATT_CONGESTED && att_ret != GATT_SUCCESS) {
502     log::warn(
503         "Unable to send ATT command to l2cap layer {} conn_id=0x{:04x}, cid={}",
504         fmt::ptr(p_clcb), p_clcb->conn_id, p_clcb->cid);
505     return GATT_INTERNAL_ERROR;
506   }
507 
508   if (cmd_code == GATT_HANDLE_VALUE_CONF || cmd_code == GATT_CMD_WRITE) {
509     return att_ret;
510   }
511 
512   log::debug("Starting ATT response timer {} conn_id=0x{:04x}, cid={}",
513              fmt::ptr(p_clcb), p_clcb->conn_id, p_clcb->cid);
514   gatt_start_rsp_timer(p_clcb);
515   if (!gatt_cmd_enq(tcb, p_clcb, false, cmd_code, NULL)) {
516     log::error(
517         "Could not queue sent request. {}, cid 0x{:02x} already disconnected",
518         tcb.peer_bda, p_clcb->cid);
519     return GATT_INTERNAL_ERROR;
520   }
521 
522   return att_ret;
523 }
524 
525 /*******************************************************************************
526  *
527  * Function         attp_send_cl_confirmation_msg
528  *
529  * Description      This function sends the client confirmation
530  *                  message to server.
531  *
532  * Parameter        p_tcb: pointer to the connection control block.
533  *                  cid: channel id
534  *
535  * Returns          GATT_SUCCESS if successfully sent; otherwise error code.
536  *
537  *
538  ******************************************************************************/
attp_send_cl_confirmation_msg(tGATT_TCB & tcb,uint16_t cid)539 tGATT_STATUS attp_send_cl_confirmation_msg(tGATT_TCB& tcb, uint16_t cid) {
540   BT_HDR* p_cmd = NULL;
541   p_cmd = attp_build_opcode_cmd(GATT_HANDLE_VALUE_CONF);
542 
543   if (p_cmd == NULL) return GATT_NO_RESOURCES;
544 
545   /* no pending request or value confirmation */
546   tGATT_STATUS att_ret = attp_send_msg_to_l2cap(tcb, cid, p_cmd);
547   if (att_ret != GATT_CONGESTED && att_ret != GATT_SUCCESS) {
548     return GATT_INTERNAL_ERROR;
549   }
550 
551   return att_ret;
552 }
553 
554 /*******************************************************************************
555  *
556  * Function         attp_send_cl_msg
557  *
558  * Description      This function sends the client request or confirmation
559  *                  message to server.
560  *
561  * Parameter        p_tcb: pointer to the connection control block.
562  *                  p_clcb: clcb
563  *                  op_code: message op code.
564  *                  p_msg: pointer to message parameters structure.
565  *
566  * Returns          GATT_SUCCESS if successfully sent; otherwise error code.
567  *
568  *
569  ******************************************************************************/
attp_send_cl_msg(tGATT_TCB & tcb,tGATT_CLCB * p_clcb,uint8_t op_code,tGATT_CL_MSG * p_msg)570 tGATT_STATUS attp_send_cl_msg(tGATT_TCB& tcb, tGATT_CLCB* p_clcb,
571                               uint8_t op_code, tGATT_CL_MSG* p_msg) {
572   BT_HDR* p_cmd = NULL;
573   uint16_t offset = 0, handle;
574 
575   if (!p_clcb) {
576     log::error("Missing p_clcb");
577     return GATT_ILLEGAL_PARAMETER;
578   }
579 
580   uint16_t payload_size = gatt_tcb_get_payload_size(tcb, p_clcb->cid);
581   if (payload_size == 0) {
582     log::error("Cannot send request (op: 0x{:02x}) due to payload size = 0, {}",
583                op_code, tcb.peer_bda);
584     return GATT_NO_RESOURCES;
585   }
586 
587   switch (op_code) {
588     case GATT_REQ_MTU:
589       if (p_msg->mtu > GATT_MAX_MTU_SIZE) {
590         log::warn(
591             "GATT message MTU is larger than max GATT MTU size op_code:{}",
592             op_code);
593         return GATT_ILLEGAL_PARAMETER;
594       }
595       p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
596       break;
597 
598     case GATT_REQ_FIND_INFO:
599     case GATT_REQ_READ_BY_TYPE:
600     case GATT_REQ_READ_BY_GRP_TYPE:
601       if (!GATT_HANDLE_IS_VALID(p_msg->browse.s_handle) ||
602           !GATT_HANDLE_IS_VALID(p_msg->browse.e_handle) ||
603           p_msg->browse.s_handle > p_msg->browse.e_handle) {
604         log::warn("GATT message has invalid handle op_code:{}", op_code);
605         return GATT_ILLEGAL_PARAMETER;
606       }
607 
608       p_cmd = attp_build_browse_cmd(op_code, p_msg->browse.s_handle,
609                                     p_msg->browse.e_handle, p_msg->browse.uuid);
610       break;
611 
612     case GATT_REQ_READ_BLOB:
613       offset = p_msg->read_blob.offset;
614       FALLTHROUGH_INTENDED; /* FALLTHROUGH */
615     case GATT_REQ_READ:
616       handle =
617           (op_code == GATT_REQ_READ) ? p_msg->handle : p_msg->read_blob.handle;
618       /*  handle checking */
619       if (!GATT_HANDLE_IS_VALID(handle)) {
620         log::warn("GATT message has invalid handle op_code:{}", op_code);
621         return GATT_ILLEGAL_PARAMETER;
622       }
623 
624       p_cmd = attp_build_handle_cmd(op_code, handle, offset);
625       break;
626 
627     case GATT_REQ_PREPARE_WRITE:
628       offset = p_msg->attr_value.offset;
629       FALLTHROUGH_INTENDED; /* FALLTHROUGH */
630     case GATT_REQ_WRITE:
631     case GATT_CMD_WRITE:
632     case GATT_SIGN_CMD_WRITE:
633       if (!GATT_HANDLE_IS_VALID(p_msg->attr_value.handle)) {
634         log::warn("GATT message has invalid handle op_code:{}", op_code);
635         return GATT_ILLEGAL_PARAMETER;
636       }
637 
638       p_cmd = attp_build_value_cmd(
639           payload_size, op_code, p_msg->attr_value.handle, offset,
640           p_msg->attr_value.len, p_msg->attr_value.value);
641       break;
642 
643     case GATT_REQ_EXEC_WRITE:
644       p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
645       break;
646 
647     case GATT_REQ_FIND_TYPE_VALUE:
648       p_cmd = attp_build_read_by_type_value_cmd(payload_size,
649                                                 &p_msg->find_type_value);
650       break;
651 
652     case GATT_REQ_READ_MULTI:
653     case GATT_REQ_READ_MULTI_VAR:
654       p_cmd = attp_build_read_multi_cmd(op_code, payload_size,
655                                         p_msg->read_multi.num_handles,
656                                         p_msg->read_multi.handles);
657       break;
658 
659     default:
660       break;
661   }
662 
663   if (p_cmd == NULL) {
664     log::warn(
665         "Unable to build proper GATT message to send to peer device op_code:{}",
666         op_code);
667     return GATT_NO_RESOURCES;
668   }
669 
670   return attp_cl_send_cmd(tcb, p_clcb, op_code, p_cmd);
671 }
672 
673 namespace bluetooth {
674 namespace legacy {
675 namespace testing {
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)676 BT_HDR* attp_build_value_cmd(uint16_t payload_size, uint8_t op_code,
677                              uint16_t handle, uint16_t offset, uint16_t len,
678                              uint8_t* p_data) {
679   return ::attp_build_value_cmd(payload_size, op_code, handle, offset, len,
680                                 p_data);
681 }
682 }  // namespace testing
683 }  // namespace legacy
684 }  // namespace bluetooth
685