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