att_protocol.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. /******************************************************************************
  2. *
  3. * Copyright (C) 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. * this file contains ATT protocol functions
  21. *
  22. ******************************************************************************/
  23. #include "common/bt_target.h"
  24. #include "osi/allocator.h"
  25. #if BLE_INCLUDED == TRUE
  26. #include "gatt_int.h"
  27. #include "stack/l2c_api.h"
  28. #define GATT_HDR_FIND_TYPE_VALUE_LEN 21
  29. #define GATT_OP_CODE_SIZE 1
  30. /**********************************************************************
  31. ** ATT protocl message building utility *
  32. ***********************************************************************/
  33. /*******************************************************************************
  34. **
  35. ** Function attp_build_mtu_exec_cmd
  36. **
  37. ** Description Build a exchange MTU request
  38. **
  39. ** Returns None.
  40. **
  41. *******************************************************************************/
  42. BT_HDR *attp_build_mtu_cmd(UINT8 op_code, UINT16 rx_mtu)
  43. {
  44. BT_HDR *p_buf = NULL;
  45. UINT8 *p;
  46. if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + GATT_HDR_SIZE + L2CAP_MIN_OFFSET)) != NULL) {
  47. p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
  48. UINT8_TO_STREAM (p, op_code);
  49. UINT16_TO_STREAM (p, rx_mtu);
  50. p_buf->offset = L2CAP_MIN_OFFSET;
  51. p_buf->len = GATT_HDR_SIZE; /* opcode + 2 bytes mtu */
  52. }
  53. return p_buf;
  54. }
  55. /*******************************************************************************
  56. **
  57. ** Function attp_build_exec_write_cmd
  58. **
  59. ** Description Build a execute write request or response.
  60. **
  61. ** Returns None.
  62. **
  63. *******************************************************************************/
  64. BT_HDR *attp_build_exec_write_cmd (UINT8 op_code, UINT8 flag)
  65. {
  66. BT_HDR *p_buf = NULL;
  67. UINT8 *p;
  68. if ((p_buf = (BT_HDR *)osi_malloc(GATT_DATA_BUF_SIZE)) != NULL) {
  69. p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
  70. p_buf->offset = L2CAP_MIN_OFFSET;
  71. p_buf->len = GATT_OP_CODE_SIZE;
  72. UINT8_TO_STREAM (p, op_code);
  73. if (op_code == GATT_REQ_EXEC_WRITE) {
  74. flag &= GATT_PREP_WRITE_EXEC;
  75. UINT8_TO_STREAM (p, flag);
  76. p_buf->len += 1;
  77. }
  78. }
  79. return p_buf;
  80. }
  81. /*******************************************************************************
  82. **
  83. ** Function attp_build_err_cmd
  84. **
  85. ** Description Build a exchange MTU request
  86. **
  87. ** Returns None.
  88. **
  89. *******************************************************************************/
  90. BT_HDR *attp_build_err_cmd(UINT8 cmd_code, UINT16 err_handle, UINT8 reason)
  91. {
  92. BT_HDR *p_buf = NULL;
  93. UINT8 *p;
  94. if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + 5)) != NULL) {
  95. p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
  96. UINT8_TO_STREAM (p, GATT_RSP_ERROR);
  97. UINT8_TO_STREAM (p, cmd_code);
  98. UINT16_TO_STREAM(p, err_handle);
  99. UINT8_TO_STREAM (p, reason);
  100. p_buf->offset = L2CAP_MIN_OFFSET;
  101. /* GATT_HDR_SIZE (1B ERR_RSP op code+ 2B handle) + 1B cmd_op_code + 1B status */
  102. p_buf->len = GATT_HDR_SIZE + 1 + 1;
  103. }
  104. return p_buf;
  105. }
  106. /*******************************************************************************
  107. **
  108. ** Function attp_build_browse_cmd
  109. **
  110. ** Description Build a read information request or read by type request
  111. **
  112. ** Returns None.
  113. **
  114. *******************************************************************************/
  115. BT_HDR *attp_build_browse_cmd(UINT8 op_code, UINT16 s_hdl, UINT16 e_hdl, tBT_UUID uuid)
  116. {
  117. BT_HDR *p_buf = NULL;
  118. UINT8 *p;
  119. /* length of ATT_READ_BY_TYPE_REQ PDU: opcode(1) + start_handle (2) + end_handle (2) + uuid (2 or 16) */
  120. const UINT8 payload_size = 1 + 2 + 2 + ((uuid.len == LEN_UUID_16) ? LEN_UUID_16 : LEN_UUID_128);
  121. if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET)) != NULL) {
  122. p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
  123. /* Describe the built message location and size */
  124. p_buf->offset = L2CAP_MIN_OFFSET;
  125. p_buf->len = GATT_OP_CODE_SIZE + 4;
  126. UINT8_TO_STREAM (p, op_code);
  127. UINT16_TO_STREAM (p, s_hdl);
  128. UINT16_TO_STREAM (p, e_hdl);
  129. p_buf->len += gatt_build_uuid_to_stream(&p, uuid);
  130. }
  131. return p_buf;
  132. }
  133. /*******************************************************************************
  134. **
  135. ** Function attp_build_read_handles_cmd
  136. **
  137. ** Description Build a read by type and value request.
  138. **
  139. ** Returns pointer to the command buffer.
  140. **
  141. *******************************************************************************/
  142. BT_HDR *attp_build_read_by_type_value_cmd (UINT16 payload_size, tGATT_FIND_TYPE_VALUE *p_value_type)
  143. {
  144. BT_HDR *p_buf = NULL;
  145. UINT8 *p;
  146. UINT16 len = p_value_type->value_len;
  147. if ((p_buf = (BT_HDR *)osi_malloc((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL) {
  148. p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
  149. p_buf->offset = L2CAP_MIN_OFFSET;
  150. p_buf->len = 5; /* opcode + s_handle + e_handle */
  151. UINT8_TO_STREAM (p, GATT_REQ_FIND_TYPE_VALUE);
  152. UINT16_TO_STREAM (p, p_value_type->s_handle);
  153. UINT16_TO_STREAM (p, p_value_type->e_handle);
  154. p_buf->len += gatt_build_uuid_to_stream(&p, p_value_type->uuid);
  155. if (p_value_type->value_len + p_buf->len > payload_size ) {
  156. len = payload_size - p_buf->len;
  157. }
  158. memcpy (p, p_value_type->value, len);
  159. p_buf->len += len;
  160. }
  161. return p_buf;
  162. }
  163. /*******************************************************************************
  164. **
  165. ** Function attp_build_read_multi_cmd
  166. **
  167. ** Description Build a read multiple request
  168. **
  169. ** Returns None.
  170. **
  171. *******************************************************************************/
  172. BT_HDR *attp_build_read_multi_cmd(UINT8 op_code, UINT16 payload_size, UINT16 num_handle, UINT16 *p_handle)
  173. {
  174. BT_HDR *p_buf = NULL;
  175. UINT8 *p, i = 0;
  176. if ((p_buf = (BT_HDR *)osi_malloc((UINT16)(sizeof(BT_HDR) + num_handle * 2 + 1 + L2CAP_MIN_OFFSET))) != NULL) {
  177. p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
  178. p_buf->offset = L2CAP_MIN_OFFSET;
  179. p_buf->len = 1;
  180. UINT8_TO_STREAM (p, op_code);
  181. for (i = 0; i < num_handle && p_buf->len + 2 <= payload_size; i ++) {
  182. UINT16_TO_STREAM (p, *(p_handle + i));
  183. p_buf->len += 2;
  184. }
  185. }
  186. return p_buf;
  187. }
  188. /*******************************************************************************
  189. **
  190. ** Function attp_build_handle_cmd
  191. **
  192. ** Description Build a read /read blob request
  193. **
  194. ** Returns None.
  195. **
  196. *******************************************************************************/
  197. BT_HDR *attp_build_handle_cmd(UINT8 op_code, UINT16 handle, UINT16 offset)
  198. {
  199. BT_HDR *p_buf = NULL;
  200. UINT8 *p;
  201. if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 5 + L2CAP_MIN_OFFSET)) != NULL) {
  202. p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
  203. p_buf->offset = L2CAP_MIN_OFFSET;
  204. UINT8_TO_STREAM (p, op_code);
  205. p_buf->len = 1;
  206. UINT16_TO_STREAM (p, handle);
  207. p_buf->len += 2;
  208. if (op_code == GATT_REQ_READ_BLOB) {
  209. UINT16_TO_STREAM (p, offset);
  210. p_buf->len += 2;
  211. }
  212. }
  213. return p_buf;
  214. }
  215. /*******************************************************************************
  216. **
  217. ** Function attp_build_opcode_cmd
  218. **
  219. ** Description Build a request/response with opcode only.
  220. **
  221. ** Returns None.
  222. **
  223. *******************************************************************************/
  224. BT_HDR *attp_build_opcode_cmd(UINT8 op_code)
  225. {
  226. BT_HDR *p_buf = NULL;
  227. UINT8 *p;
  228. if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + 1 + L2CAP_MIN_OFFSET)) != NULL) {
  229. p = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
  230. p_buf->offset = L2CAP_MIN_OFFSET;
  231. UINT8_TO_STREAM (p, op_code);
  232. p_buf->len = 1;
  233. }
  234. return p_buf;
  235. }
  236. /*******************************************************************************
  237. **
  238. ** Function attp_build_value_cmd
  239. **
  240. ** Description Build a attribute value request
  241. **
  242. ** Returns None.
  243. **
  244. *******************************************************************************/
  245. BT_HDR *attp_build_value_cmd (UINT16 payload_size, UINT8 op_code, UINT16 handle,
  246. UINT16 offset, UINT16 len, UINT8 *p_data)
  247. {
  248. BT_HDR *p_buf = NULL;
  249. UINT8 *p, *pp, pair_len, *p_pair_len;
  250. if ((p_buf = (BT_HDR *)osi_malloc((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL) {
  251. p = pp = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
  252. UINT8_TO_STREAM (p, op_code);
  253. p_buf->offset = L2CAP_MIN_OFFSET;
  254. p_buf->len = 1;
  255. if (op_code == GATT_RSP_READ_BY_TYPE) {
  256. p_pair_len = p;
  257. pair_len = len + 2;
  258. UINT8_TO_STREAM (p, pair_len);
  259. p_buf->len += 1;
  260. }
  261. if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ && op_code != GATT_HANDLE_MULTI_VALUE_NOTIF) {
  262. UINT16_TO_STREAM (p, handle);
  263. p_buf->len += 2;
  264. }
  265. if (op_code == GATT_REQ_PREPARE_WRITE || op_code == GATT_RSP_PREPARE_WRITE ) {
  266. UINT16_TO_STREAM (p, offset);
  267. p_buf->len += 2;
  268. }
  269. if(payload_size < GATT_DEF_BLE_MTU_SIZE || payload_size > GATT_MAX_MTU_SIZE) {
  270. GATT_TRACE_ERROR("invalid payload_size %d", payload_size);
  271. osi_free(p_buf);
  272. return NULL;
  273. }
  274. if (len > 0 && p_data != NULL) {
  275. /* ensure data not exceed MTU size */
  276. if (payload_size - p_buf->len < len) {
  277. len = payload_size - p_buf->len;
  278. /* update handle value pair length */
  279. if (op_code == GATT_RSP_READ_BY_TYPE) {
  280. *p_pair_len = (len + 2);
  281. }
  282. GATT_TRACE_WARNING("attribute value too long, to be truncated to %d", len);
  283. }
  284. ARRAY_TO_STREAM (p, p_data, len);
  285. p_buf->len += len;
  286. }
  287. }
  288. return p_buf;
  289. }
  290. /*******************************************************************************
  291. **
  292. ** Function attp_send_msg_to_l2cap
  293. **
  294. ** Description Send message to L2CAP.
  295. **
  296. *******************************************************************************/
  297. tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP)
  298. {
  299. UINT16 l2cap_ret;
  300. if (p_tcb->att_lcid == L2CAP_ATT_CID) {
  301. l2cap_ret = L2CA_SendFixedChnlData (L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP);
  302. } else {
  303. #if (CLASSIC_BT_INCLUDED == TRUE)
  304. l2cap_ret = (UINT16) L2CA_DataWrite (p_tcb->att_lcid, p_toL2CAP);
  305. #else
  306. l2cap_ret = L2CAP_DW_FAILED;
  307. #endif ///CLASSIC_BT_INCLUDED == TRUE
  308. }
  309. if (l2cap_ret == L2CAP_DW_FAILED) {
  310. GATT_TRACE_DEBUG("ATT failed to pass msg:0x%0x to L2CAP",
  311. *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset));
  312. return GATT_INTERNAL_ERROR;
  313. } else if (l2cap_ret == L2CAP_DW_CONGESTED) {
  314. GATT_TRACE_DEBUG("ATT congested, message accepted");
  315. return GATT_CONGESTED;
  316. }
  317. return GATT_SUCCESS;
  318. }
  319. /*******************************************************************************
  320. **
  321. ** Function attp_build_sr_msg
  322. **
  323. ** Description Build ATT Server PDUs.
  324. **
  325. *******************************************************************************/
  326. BT_HDR *attp_build_sr_msg(tGATT_TCB *p_tcb, UINT8 op_code, tGATT_SR_MSG *p_msg)
  327. {
  328. BT_HDR *p_cmd = NULL;
  329. UINT16 offset = 0;
  330. switch (op_code) {
  331. case GATT_RSP_READ_BLOB:
  332. case GATT_RSP_PREPARE_WRITE:
  333. case GATT_RSP_READ_BY_TYPE:
  334. case GATT_RSP_READ:
  335. case GATT_HANDLE_VALUE_NOTIF:
  336. case GATT_HANDLE_VALUE_IND:
  337. case GATT_HANDLE_MULTI_VALUE_NOTIF:
  338. case GATT_RSP_ERROR:
  339. case GATT_RSP_MTU:
  340. /* Need to check the validation of parameter p_msg*/
  341. if (p_msg == NULL) {
  342. GATT_TRACE_ERROR("Invalid parameters in %s, op_code=0x%x, the p_msg should not be NULL.", __func__, op_code);
  343. return NULL;
  344. }
  345. break;
  346. default:
  347. break;
  348. }
  349. switch (op_code) {
  350. case GATT_RSP_READ_BLOB:
  351. case GATT_RSP_PREPARE_WRITE:
  352. GATT_TRACE_EVENT ("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. /* Coverity: [FALSE-POSITIVE error] intended fall through */
  356. /* Missing break statement between cases in switch statement */
  357. /* fall through */
  358. case GATT_RSP_READ_BY_TYPE:
  359. case GATT_RSP_READ:
  360. case GATT_HANDLE_VALUE_NOTIF:
  361. case GATT_HANDLE_VALUE_IND:
  362. case GATT_HANDLE_MULTI_VALUE_NOTIF:
  363. p_cmd = attp_build_value_cmd(p_tcb->payload_size,
  364. op_code,
  365. p_msg->attr_value.handle,
  366. offset,
  367. p_msg->attr_value.len,
  368. p_msg->attr_value.value);
  369. break;
  370. case GATT_RSP_WRITE:
  371. p_cmd = attp_build_opcode_cmd(op_code);
  372. break;
  373. case GATT_RSP_ERROR:
  374. p_cmd = attp_build_err_cmd(p_msg->error.cmd_code, p_msg->error.handle, p_msg->error.reason);
  375. break;
  376. case GATT_RSP_EXEC_WRITE:
  377. p_cmd = attp_build_exec_write_cmd(op_code, 0);
  378. break;
  379. case GATT_RSP_MTU:
  380. p_cmd = attp_build_mtu_cmd(op_code, p_msg->mtu);
  381. break;
  382. default:
  383. GATT_TRACE_DEBUG("attp_build_sr_msg: unknown op code = %d", op_code);
  384. break;
  385. }
  386. if (!p_cmd) {
  387. GATT_TRACE_ERROR("No resources");
  388. }
  389. return p_cmd;
  390. }
  391. /*******************************************************************************
  392. **
  393. ** Function attp_send_sr_msg
  394. **
  395. ** Description This function sends the server response or indication message
  396. ** to client.
  397. **
  398. ** Parameter p_tcb: pointer to the connecton control block.
  399. ** p_msg: pointer to message parameters structure.
  400. **
  401. ** Returns GATT_SUCCESS if successfully sent; otherwise error code.
  402. **
  403. **
  404. *******************************************************************************/
  405. tGATT_STATUS attp_send_sr_msg (tGATT_TCB *p_tcb, BT_HDR *p_msg)
  406. {
  407. tGATT_STATUS cmd_sent = GATT_NO_RESOURCES;
  408. if (p_tcb != NULL) {
  409. if (p_msg != NULL) {
  410. p_msg->offset = L2CAP_MIN_OFFSET;
  411. cmd_sent = attp_send_msg_to_l2cap (p_tcb, p_msg);
  412. }
  413. }
  414. return cmd_sent;
  415. }
  416. /*******************************************************************************
  417. **
  418. ** Function attp_cl_send_cmd
  419. **
  420. ** Description Send a ATT command or enqueue it.
  421. **
  422. ** Returns GATT_SUCCESS if command sent
  423. ** GATT_CONGESTED if command sent but channel congested
  424. ** GATT_CMD_STARTED if command queue up in GATT
  425. ** GATT_ERROR if command sending failure
  426. **
  427. *******************************************************************************/
  428. tGATT_STATUS attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR *p_cmd)
  429. {
  430. tGATT_STATUS att_ret = GATT_SUCCESS;
  431. if (p_tcb != NULL) {
  432. cmd_code &= ~GATT_AUTH_SIGN_MASK;
  433. /* no pending request or value confirmation */
  434. if (p_tcb->pending_cl_req == p_tcb->next_slot_inq ||
  435. cmd_code == GATT_HANDLE_VALUE_CONF) {
  436. att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd);
  437. if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS) {
  438. /* do not enq cmd if handle value confirmation or set request */
  439. if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE) {
  440. gatt_start_rsp_timer (clcb_idx);
  441. gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL);
  442. }
  443. } else {
  444. att_ret = GATT_INTERNAL_ERROR;
  445. }
  446. } else {
  447. att_ret = GATT_CMD_STARTED;
  448. gatt_cmd_enq(p_tcb, clcb_idx, TRUE, cmd_code, p_cmd);
  449. }
  450. } else {
  451. att_ret = GATT_ERROR;
  452. }
  453. return att_ret;
  454. }
  455. /*******************************************************************************
  456. **
  457. ** Function attp_send_cl_msg
  458. **
  459. ** Description This function sends the client request or confirmation message
  460. ** to server.
  461. **
  462. ** Parameter p_tcb: pointer to the connection control block.
  463. ** clcb_idx: clcb index
  464. ** op_code: message op code.
  465. ** p_msg: pointer to message parameters structure.
  466. **
  467. ** Returns GATT_SUCCESS if successfully sent; otherwise error code.
  468. **
  469. **
  470. *******************************************************************************/
  471. tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg)
  472. {
  473. tGATT_STATUS status = GATT_NO_RESOURCES;
  474. BT_HDR *p_cmd = NULL;
  475. UINT16 offset = 0, handle;
  476. if (p_tcb != NULL) {
  477. switch (op_code) {
  478. case GATT_REQ_MTU:
  479. if (p_msg->mtu <= GATT_MAX_MTU_SIZE) {
  480. p_tcb->payload_size = p_msg->mtu;
  481. p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
  482. } else {
  483. status = GATT_ILLEGAL_PARAMETER;
  484. }
  485. break;
  486. case GATT_REQ_FIND_INFO:
  487. case GATT_REQ_READ_BY_TYPE:
  488. case GATT_REQ_READ_BY_GRP_TYPE:
  489. if (GATT_HANDLE_IS_VALID (p_msg->browse.s_handle) &&
  490. GATT_HANDLE_IS_VALID (p_msg->browse.e_handle) &&
  491. p_msg->browse.s_handle <= p_msg->browse.e_handle) {
  492. p_cmd = attp_build_browse_cmd(op_code,
  493. p_msg->browse.s_handle,
  494. p_msg->browse.e_handle,
  495. p_msg->browse.uuid);
  496. } else {
  497. status = GATT_ILLEGAL_PARAMETER;
  498. }
  499. break;
  500. case GATT_REQ_READ_BLOB:
  501. offset = p_msg->read_blob.offset;
  502. /* fall through */
  503. case GATT_REQ_READ:
  504. handle = (op_code == GATT_REQ_READ) ? p_msg->handle : p_msg->read_blob.handle;
  505. /* handle checking */
  506. if (GATT_HANDLE_IS_VALID (handle)) {
  507. p_cmd = attp_build_handle_cmd(op_code, handle, offset);
  508. } else {
  509. status = GATT_ILLEGAL_PARAMETER;
  510. }
  511. break;
  512. case GATT_HANDLE_VALUE_CONF:
  513. p_cmd = attp_build_opcode_cmd(op_code);
  514. break;
  515. case GATT_REQ_PREPARE_WRITE:
  516. offset = p_msg->attr_value.offset;
  517. /* fall through */
  518. case GATT_REQ_WRITE:
  519. case GATT_CMD_WRITE:
  520. case GATT_SIGN_CMD_WRITE:
  521. if (GATT_HANDLE_IS_VALID (p_msg->attr_value.handle)) {
  522. p_cmd = attp_build_value_cmd (p_tcb->payload_size,
  523. op_code, p_msg->attr_value.handle,
  524. offset,
  525. p_msg->attr_value.len,
  526. p_msg->attr_value.value);
  527. } else {
  528. status = GATT_ILLEGAL_PARAMETER;
  529. }
  530. break;
  531. case GATT_REQ_EXEC_WRITE:
  532. p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write);
  533. break;
  534. case GATT_REQ_FIND_TYPE_VALUE:
  535. p_cmd = attp_build_read_by_type_value_cmd(p_tcb->payload_size, &p_msg->find_type_value);
  536. break;
  537. case GATT_REQ_READ_MULTI:
  538. case GATT_REQ_READ_MULTI_VAR:
  539. p_cmd = attp_build_read_multi_cmd(op_code, p_tcb->payload_size,
  540. p_msg->read_multi.num_handles,
  541. p_msg->read_multi.handles);
  542. break;
  543. default:
  544. break;
  545. }
  546. if (p_cmd != NULL) {
  547. status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd);
  548. }
  549. } else {
  550. GATT_TRACE_ERROR("Peer device not connected");
  551. }
  552. return status;
  553. }
  554. #endif