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