hidd_conn.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. /******************************************************************************
  2. *
  3. * Copyright (C) 2016 The Android Open Source Project
  4. * Copyright (C) 2002-2012 Broadcom Corporation
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at:
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. ******************************************************************************/
  19. /******************************************************************************
  20. *
  21. * this file contains the connection interface functions
  22. *
  23. ******************************************************************************/
  24. #include "btm_int.h"
  25. #include "hid_conn.h"
  26. #include "hid_int.h"
  27. #include "osi/allocator.h"
  28. #include "osi/osi.h"
  29. #include "stack/btm_api.h"
  30. #include "stack/btu.h"
  31. #include "stack/hidd_api.h"
  32. #include "stack/hiddefs.h"
  33. #include "stack/l2c_api.h"
  34. #include "stack/l2cdefs.h"
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #if (HID_DEV_INCLUDED == TRUE)
  39. static void hidd_l2cif_connect_ind(BD_ADDR bd_addr, uint16_t cid, uint16_t psm, uint8_t id);
  40. static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result);
  41. static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO *p_cfg);
  42. static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO *p_cfg);
  43. static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed);
  44. static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result);
  45. static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR *p_msg);
  46. static void hidd_l2cif_cong_ind(uint16_t cid, bool congested);
  47. static const tL2CAP_APPL_INFO dev_reg_info = {hidd_l2cif_connect_ind,
  48. hidd_l2cif_connect_cfm,
  49. NULL,
  50. hidd_l2cif_config_ind,
  51. hidd_l2cif_config_cfm,
  52. hidd_l2cif_disconnect_ind,
  53. hidd_l2cif_disconnect_cfm,
  54. NULL,
  55. hidd_l2cif_data_ind,
  56. hidd_l2cif_cong_ind,
  57. NULL};
  58. /*******************************************************************************
  59. *
  60. * Function hidd_check_config_done
  61. *
  62. * Description Checks if connection is configured and callback can be fired
  63. *
  64. * Returns void
  65. *
  66. ******************************************************************************/
  67. static void hidd_check_config_done(void)
  68. {
  69. tHID_CONN *p_hcon;
  70. p_hcon = &hd_cb.device.conn;
  71. if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED) &&
  72. (p_hcon->conn_state == HID_CONN_STATE_CONFIG)) {
  73. p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
  74. hd_cb.device.state = HIDD_DEV_CONNECTED;
  75. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_OPEN, 0, NULL);
  76. // send outstanding data on intr
  77. if (hd_cb.pending_data) {
  78. L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data);
  79. hd_cb.pending_data = NULL;
  80. }
  81. }
  82. }
  83. /*******************************************************************************
  84. *
  85. * Function hidh_sec_check_complete_term
  86. *
  87. * Description HID security check complete callback function.
  88. *
  89. * Returns Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
  90. * send security block L2C connection response.
  91. *
  92. ******************************************************************************/
  93. static void hidd_sec_check_complete(UNUSED_ATTR BD_ADDR bd_addr, UNUSED_ATTR tBT_TRANSPORT transport, void *p_ref_data,
  94. uint8_t res)
  95. {
  96. tHID_DEV_DEV_CTB *p_dev = (tHID_DEV_DEV_CTB *)p_ref_data;
  97. if (res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) {
  98. p_dev->conn.disc_reason = HID_SUCCESS;
  99. p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
  100. L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
  101. L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
  102. } else if (res != BTM_SUCCESS) {
  103. HIDD_TRACE_WARNING("%s: connection rejected by security", __func__);
  104. p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
  105. p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
  106. L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_SECURITY_BLOCK,
  107. L2CAP_CONN_OK);
  108. return;
  109. }
  110. }
  111. /*******************************************************************************
  112. *
  113. * Function hidd_sec_check_complete_orig
  114. *
  115. * Description HID security check complete callback function (device
  116. *originated)
  117. *
  118. * Returns void
  119. *
  120. ******************************************************************************/
  121. void hidd_sec_check_complete_orig(UNUSED_ATTR BD_ADDR bd_addr, UNUSED_ATTR tBT_TRANSPORT transport, void *p_ref_data,
  122. uint8_t res)
  123. {
  124. tHID_DEV_DEV_CTB *p_dev = (tHID_DEV_DEV_CTB *)p_ref_data;
  125. if (p_dev->conn.conn_state != HID_CONN_STATE_SECURITY) {
  126. HIDD_TRACE_WARNING("%s: invalid state (%02x)", __func__, p_dev->conn.conn_state);
  127. return;
  128. }
  129. if (res == BTM_SUCCESS) {
  130. HIDD_TRACE_EVENT("%s: security ok", __func__);
  131. p_dev->conn.disc_reason = HID_SUCCESS;
  132. p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
  133. L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
  134. } else {
  135. HIDD_TRACE_WARNING("%s: security check failed (%02x)", __func__, res);
  136. p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
  137. hidd_conn_disconnect();
  138. }
  139. }
  140. /*******************************************************************************
  141. *
  142. * Function hidd_l2cif_connect_ind
  143. *
  144. * Description Handles incoming L2CAP connection (we act as server)
  145. *
  146. * Returns void
  147. *
  148. ******************************************************************************/
  149. static void hidd_l2cif_connect_ind(BD_ADDR bd_addr, uint16_t cid, uint16_t psm, uint8_t id)
  150. {
  151. tHID_CONN *p_hcon;
  152. tHID_DEV_DEV_CTB *p_dev;
  153. bool accept = TRUE; // accept by default
  154. HIDD_TRACE_EVENT("%s: psm=%04x cid=%04x id=%02x", __func__, psm, cid, id);
  155. p_dev = &hd_cb.device;
  156. if (!hd_cb.allow_incoming) {
  157. HIDD_TRACE_WARNING("%s: incoming connections not allowed, rejecting", __func__);
  158. L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
  159. return;
  160. }
  161. if (p_dev->in_use && memcmp(bd_addr, p_dev->addr, sizeof(BD_ADDR))) {
  162. HIDD_TRACE_WARNING("%s: incoming connections from different device, rejecting", __func__);
  163. L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
  164. return;
  165. } else if (!p_dev->in_use) {
  166. p_dev->in_use = TRUE;
  167. memcpy(p_dev->addr, bd_addr, sizeof(BD_ADDR));
  168. p_dev->state = HIDD_DEV_NO_CONN;
  169. }
  170. p_hcon = &hd_cb.device.conn;
  171. switch (psm) {
  172. case HID_PSM_INTERRUPT:
  173. if (p_hcon->ctrl_cid == 0) {
  174. accept = FALSE;
  175. HIDD_TRACE_WARNING("%s: incoming INTR without CTRL, rejecting", __func__);
  176. }
  177. if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) {
  178. accept = FALSE;
  179. HIDD_TRACE_WARNING("%s: incoming INTR in invalid state (%d), rejecting", __func__, p_hcon->conn_state);
  180. }
  181. break;
  182. case HID_PSM_CONTROL:
  183. if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) {
  184. accept = FALSE;
  185. HIDD_TRACE_WARNING("%s: incoming CTRL in invalid state (%d), rejecting", __func__, p_hcon->conn_state);
  186. }
  187. break;
  188. default:
  189. accept = FALSE;
  190. HIDD_TRACE_ERROR("%s: received invalid PSM, rejecting", __func__);
  191. break;
  192. }
  193. if (!accept) {
  194. L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
  195. return;
  196. }
  197. // for CTRL we need to go through security and we reply in callback from there
  198. if (psm == HID_PSM_CONTROL) {
  199. p_hcon->conn_flags = 0;
  200. p_hcon->ctrl_cid = cid;
  201. p_hcon->ctrl_id = id;
  202. p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
  203. p_hcon->conn_state = HID_CONN_STATE_SECURITY;
  204. if (btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, FALSE, BTM_SEC_PROTO_HID, HIDD_NOSEC_CHN,
  205. &hidd_sec_check_complete, p_dev) == BTM_CMD_STARTED) {
  206. L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
  207. }
  208. return;
  209. }
  210. // for INTR we go directly to config state
  211. p_hcon->conn_state = HID_CONN_STATE_CONFIG;
  212. p_hcon->intr_cid = cid;
  213. L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
  214. L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
  215. }
  216. /*******************************************************************************
  217. *
  218. * Function hidd_l2cif_connect_cfm
  219. *
  220. * Description Handles L2CAP connection response (we act as client)
  221. *
  222. * Returns void
  223. *
  224. ******************************************************************************/
  225. static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result)
  226. {
  227. tHID_DEV_DEV_CTB *p_dev = &hd_cb.device;
  228. tHID_CONN *p_hcon = &hd_cb.device.conn;
  229. HIDD_TRACE_EVENT("%s: cid=%04x result=%d, conn_state=%d", __func__, cid, result, p_hcon->conn_state);
  230. if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
  231. HIDD_TRACE_WARNING("%s: unknown cid", __func__);
  232. return;
  233. }
  234. if (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) ||
  235. ((cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL && (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING_INTR))) ||
  236. ((cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) && (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING_CTRL))) {
  237. HIDD_TRACE_WARNING("%s: unexpected, cid:0x%04x, ctrl_cid:0x%04x, intr_cid:0x%04x, conn_state:%d", __func__, cid,
  238. p_hcon->ctrl_cid, p_hcon->intr_cid, p_hcon->conn_state);
  239. return;
  240. }
  241. if (result != L2CAP_CONN_OK) {
  242. HIDD_TRACE_WARNING("%s: connection failed, now disconnect", __func__);
  243. if (cid == p_hcon->ctrl_cid)
  244. p_hcon->ctrl_cid = 0;
  245. else
  246. p_hcon->intr_cid = 0;
  247. hidd_conn_disconnect();
  248. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_L2CAP_CONN_FAIL | (uint32_t)result, NULL);
  249. return;
  250. }
  251. /* CTRL connect conf */
  252. if (cid == p_hcon->ctrl_cid) {
  253. p_hcon->conn_state = HID_CONN_STATE_SECURITY;
  254. p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* in case disconnected before sec completed */
  255. btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, TRUE, BTM_SEC_PROTO_HID, HIDD_SEC_CHN,
  256. &hidd_sec_check_complete_orig, p_dev);
  257. } else {
  258. p_hcon->conn_state = HID_CONN_STATE_CONFIG;
  259. L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
  260. }
  261. return;
  262. }
  263. /*******************************************************************************
  264. *
  265. * Function hidd_l2cif_config_ind
  266. *
  267. * Description Handles incoming L2CAP configuration request
  268. *
  269. * Returns void
  270. *
  271. ******************************************************************************/
  272. static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO *p_cfg)
  273. {
  274. tHID_CONN *p_hcon;
  275. HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
  276. p_hcon = &hd_cb.device.conn;
  277. if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
  278. HIDD_TRACE_WARNING("%s: unknown cid", __func__);
  279. return;
  280. }
  281. if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_DEV_MTU_SIZE))
  282. p_hcon->rem_mtu_size = HID_DEV_MTU_SIZE;
  283. else
  284. p_hcon->rem_mtu_size = p_cfg->mtu;
  285. // accept without changes
  286. p_cfg->flush_to_present = FALSE;
  287. p_cfg->mtu_present = FALSE;
  288. p_cfg->result = L2CAP_CFG_OK;
  289. if (cid == p_hcon->intr_cid && hd_cb.use_in_qos && !p_cfg->qos_present) {
  290. p_cfg->qos_present = TRUE;
  291. memcpy(&p_cfg->qos, &hd_cb.in_qos, sizeof(FLOW_SPEC));
  292. }
  293. L2CA_ConfigRsp(cid, p_cfg);
  294. // update flags
  295. if (cid == p_hcon->ctrl_cid) {
  296. p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
  297. if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) {
  298. p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
  299. if ((p_hcon->intr_cid = L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
  300. p_hcon->conn_state = HID_CONN_STATE_UNUSED;
  301. hidd_conn_disconnect();
  302. HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR", __func__);
  303. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL);
  304. return;
  305. } else {
  306. p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
  307. }
  308. }
  309. } else {
  310. p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
  311. }
  312. hidd_check_config_done();
  313. }
  314. /*******************************************************************************
  315. *
  316. * Function hidd_l2cif_config_cfm
  317. *
  318. * Description Handles incoming L2CAP configuration response
  319. *
  320. * Returns void
  321. *
  322. ******************************************************************************/
  323. static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO *p_cfg)
  324. {
  325. tHID_CONN *p_hcon;
  326. uint32_t reason;
  327. HIDD_TRACE_EVENT("%s: cid=%04x pcfg->result=%d", __func__, cid, p_cfg->result);
  328. p_hcon = &hd_cb.device.conn;
  329. if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
  330. HIDD_TRACE_WARNING("%s: unknown cid", __func__);
  331. return;
  332. }
  333. if (p_hcon->intr_cid == cid && p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS && p_cfg->qos_present) {
  334. tL2CAP_CFG_INFO new_qos;
  335. // QoS parameters not accepted for intr, try again with host proposal
  336. memcpy(&new_qos, &hd_cb.l2cap_intr_cfg, sizeof(new_qos));
  337. memcpy(&new_qos.qos, &p_cfg->qos, sizeof(FLOW_SPEC));
  338. new_qos.qos_present = TRUE;
  339. HIDD_TRACE_WARNING("%s: config failed, retry", __func__);
  340. L2CA_ConfigReq(cid, &new_qos);
  341. return;
  342. } else if (p_hcon->intr_cid == cid && p_cfg->result == L2CAP_CFG_UNKNOWN_OPTIONS) {
  343. // QoS not understood by remote device, try configuring without QoS
  344. HIDD_TRACE_WARNING("%s: config failed, retry without QoS", __func__);
  345. L2CA_ConfigReq(cid, &hd_cb.l2cap_cfg);
  346. return;
  347. } else if (p_cfg->result != L2CAP_CFG_OK) {
  348. HIDD_TRACE_WARNING("%s: config failed, disconnecting", __func__);
  349. hidd_conn_disconnect();
  350. reason = HID_L2CAP_CFG_FAIL | (uint32_t)p_cfg->result;
  351. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, reason, NULL);
  352. return;
  353. }
  354. // update flags
  355. if (cid == p_hcon->ctrl_cid) {
  356. p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
  357. if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) {
  358. p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
  359. if ((p_hcon->intr_cid = L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
  360. p_hcon->conn_state = HID_CONN_STATE_UNUSED;
  361. hidd_conn_disconnect();
  362. HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR", __func__);
  363. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL);
  364. return;
  365. } else {
  366. p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
  367. }
  368. }
  369. } else {
  370. p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
  371. }
  372. hidd_check_config_done();
  373. }
  374. /*******************************************************************************
  375. *
  376. * Function hidd_l2cif_disconnect_ind
  377. *
  378. * Description Handler incoming L2CAP disconnection request
  379. *
  380. * Returns void
  381. *
  382. ******************************************************************************/
  383. static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed)
  384. {
  385. tHID_CONN *p_hcon;
  386. HIDD_TRACE_EVENT("%s: cid=%04x ack_needed=%d", __func__, cid, ack_needed);
  387. p_hcon = &hd_cb.device.conn;
  388. if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
  389. HIDD_TRACE_WARNING("%s: unknown cid", __func__);
  390. return;
  391. }
  392. if (ack_needed)
  393. L2CA_DisconnectRsp(cid);
  394. if (cid == p_hcon->ctrl_cid) {
  395. p_hcon->ctrl_cid = 0;
  396. p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_CTRL;
  397. } else {
  398. p_hcon->intr_cid = 0;
  399. p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_INTR;
  400. }
  401. if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
  402. HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
  403. // clean any outstanding data on intr
  404. if (hd_cb.pending_data) {
  405. osi_free(hd_cb.pending_data);
  406. hd_cb.pending_data = NULL;
  407. }
  408. hd_cb.device.state = HIDD_DEV_NO_CONN;
  409. p_hcon->conn_state = HID_CONN_STATE_UNUSED;
  410. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, p_hcon->disc_reason, NULL);
  411. }
  412. }
  413. /*******************************************************************************
  414. *
  415. * Function hidd_l2cif_disconnect_cfm
  416. *
  417. * Description Handles L2CAP disconection response
  418. *
  419. * Returns void
  420. *
  421. ******************************************************************************/
  422. static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result)
  423. {
  424. tHID_CONN *p_hcon;
  425. HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result);
  426. p_hcon = &hd_cb.device.conn;
  427. if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
  428. HIDD_TRACE_WARNING("%s: unknown cid", __func__);
  429. return;
  430. }
  431. if (cid == p_hcon->ctrl_cid) {
  432. p_hcon->ctrl_cid = 0;
  433. } else {
  434. p_hcon->intr_cid = 0;
  435. // now disconnect CTRL
  436. L2CA_DisconnectReq(p_hcon->ctrl_cid);
  437. }
  438. if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
  439. HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
  440. hd_cb.device.state = HIDD_DEV_NO_CONN;
  441. p_hcon->conn_state = HID_CONN_STATE_UNUSED;
  442. if (hd_cb.pending_vc_unplug) {
  443. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_VC_UNPLUG, p_hcon->disc_reason, NULL);
  444. hd_cb.pending_vc_unplug = FALSE;
  445. } else {
  446. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, p_hcon->disc_reason, NULL);
  447. }
  448. }
  449. }
  450. /*******************************************************************************
  451. *
  452. * Function hidd_l2cif_cong_ind
  453. *
  454. * Description Handles L2CAP congestion status event
  455. *
  456. * Returns void
  457. *
  458. ******************************************************************************/
  459. static void hidd_l2cif_cong_ind(uint16_t cid, bool congested)
  460. {
  461. tHID_CONN *p_hcon;
  462. HIDD_TRACE_EVENT("%s: cid=%04x congested=%d", __func__, cid, congested);
  463. p_hcon = &hd_cb.device.conn;
  464. if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
  465. HIDD_TRACE_WARNING("%s: unknown cid", __func__);
  466. return;
  467. }
  468. if (congested) {
  469. p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
  470. } else {
  471. p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
  472. }
  473. }
  474. /*******************************************************************************
  475. *
  476. * Function hidd_l2cif_data_ind
  477. *
  478. * Description Handler incoming data on L2CAP channel
  479. *
  480. * Returns void
  481. *
  482. ******************************************************************************/
  483. static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR *p_msg)
  484. {
  485. tHID_CONN *p_hcon;
  486. uint8_t *p_data = (uint8_t *)(p_msg + 1) + p_msg->offset;
  487. uint8_t msg_type, param;
  488. bool err = FALSE;
  489. HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
  490. p_hcon = &hd_cb.device.conn;
  491. if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
  492. HIDD_TRACE_WARNING("%s: unknown cid", __func__);
  493. osi_free(p_msg);
  494. return;
  495. }
  496. msg_type = HID_GET_TRANS_FROM_HDR(*p_data);
  497. param = HID_GET_PARAM_FROM_HDR(*p_data);
  498. if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
  499. // skip HID header
  500. p_msg->offset++;
  501. p_msg->len--;
  502. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_INTR_DATA, 0, p_msg);
  503. return;
  504. }
  505. switch (msg_type) {
  506. case HID_TRANS_GET_REPORT:
  507. // at this stage we don't know if Report Id shall be included in request
  508. // so we pass complete packet in callback and let other code analyze this
  509. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_GET_REPORT, !!(param & HID_PAR_GET_REP_BUFSIZE_FOLLOWS), p_msg);
  510. break;
  511. case HID_TRANS_SET_REPORT:
  512. // as above
  513. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_REPORT, 0, p_msg);
  514. break;
  515. case HID_TRANS_GET_IDLE:
  516. hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, HID_PAR_REP_TYPE_OTHER, hd_cb.device.idle_time, 0, NULL);
  517. osi_free(p_msg);
  518. break;
  519. case HID_TRANS_SET_IDLE:
  520. if (p_msg->len != 2) {
  521. HIDD_TRACE_ERROR("%s: invalid len (%d) set idle request received", __func__, p_msg->len);
  522. err = TRUE;
  523. } else {
  524. hd_cb.device.idle_time = p_data[1];
  525. HIDD_TRACE_DEBUG("%s: idle_time = %d", __func__, hd_cb.device.idle_time);
  526. if (hd_cb.device.idle_time) {
  527. HIDD_TRACE_WARNING("%s: idle_time of %d ms not supported by HID Device", __func__,
  528. (hd_cb.device.idle_time * 4));
  529. err = TRUE;
  530. }
  531. }
  532. if (!err) {
  533. hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_SUCCESS, 0, 0, NULL);
  534. } else {
  535. hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM, 0, 0, NULL);
  536. }
  537. osi_free(p_msg);
  538. break;
  539. case HID_TRANS_GET_PROTOCOL:
  540. hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, HID_PAR_REP_TYPE_OTHER, !hd_cb.device.boot_mode, 0, NULL);
  541. osi_free(p_msg);
  542. break;
  543. case HID_TRANS_SET_PROTOCOL:
  544. hd_cb.device.boot_mode = !(param & HID_PAR_PROTOCOL_MASK);
  545. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_PROTOCOL, param & HID_PAR_PROTOCOL_MASK, NULL);
  546. hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_SUCCESS, 0, 0, NULL);
  547. osi_free(p_msg);
  548. break;
  549. case HID_TRANS_CONTROL:
  550. switch (param) {
  551. case HID_PAR_CONTROL_SUSPEND:
  552. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SUSPEND, 0, NULL);
  553. break;
  554. case HID_PAR_CONTROL_EXIT_SUSPEND:
  555. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_EXIT_SUSPEND, 0, NULL);
  556. break;
  557. case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
  558. hidd_conn_disconnect();
  559. // set flag so we can notify properly when disconnected
  560. hd_cb.pending_vc_unplug = TRUE;
  561. break;
  562. }
  563. osi_free(p_msg);
  564. break;
  565. case HID_TRANS_DATA:
  566. default:
  567. HIDD_TRACE_WARNING("%s: got unsupported msg (%d)", __func__, msg_type);
  568. hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ, 0, 0, NULL);
  569. osi_free(p_msg);
  570. break;
  571. }
  572. }
  573. /*******************************************************************************
  574. *
  575. * Function hidd_conn_reg
  576. *
  577. * Description Registers L2CAP channels
  578. *
  579. * Returns void
  580. *
  581. ******************************************************************************/
  582. tHID_STATUS hidd_conn_reg(void)
  583. {
  584. HIDD_TRACE_API("%s", __func__);
  585. memset(&hd_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
  586. hd_cb.l2cap_cfg.mtu_present = TRUE;
  587. hd_cb.l2cap_cfg.mtu = HID_DEV_MTU_SIZE;
  588. hd_cb.l2cap_cfg.flush_to_present = TRUE;
  589. hd_cb.l2cap_cfg.flush_to = HID_DEV_FLUSH_TO;
  590. memset(&hd_cb.l2cap_intr_cfg, 0, sizeof(tL2CAP_CFG_INFO));
  591. hd_cb.l2cap_intr_cfg.mtu_present = TRUE;
  592. hd_cb.l2cap_intr_cfg.mtu = HID_DEV_MTU_SIZE;
  593. hd_cb.l2cap_intr_cfg.flush_to_present = TRUE;
  594. hd_cb.l2cap_intr_cfg.flush_to = HID_DEV_FLUSH_TO;
  595. if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO *)&dev_reg_info)) {
  596. HIDD_TRACE_ERROR("HID Control (device) registration failed");
  597. return (HID_ERR_L2CAP_FAILED);
  598. }
  599. if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO *)&dev_reg_info)) {
  600. L2CA_Deregister(HID_PSM_CONTROL);
  601. HIDD_TRACE_ERROR("HID Interrupt (device) registration failed");
  602. return (HID_ERR_L2CAP_FAILED);
  603. }
  604. return (HID_SUCCESS);
  605. }
  606. /*******************************************************************************
  607. *
  608. * Function hidd_conn_dereg
  609. *
  610. * Description Deregisters L2CAP channels
  611. *
  612. * Returns void
  613. *
  614. ******************************************************************************/
  615. void hidd_conn_dereg(void)
  616. {
  617. HIDD_TRACE_API("%s", __func__);
  618. L2CA_Deregister(HID_PSM_CONTROL);
  619. L2CA_Deregister(HID_PSM_INTERRUPT);
  620. }
  621. /*******************************************************************************
  622. *
  623. * Function hidd_conn_initiate
  624. *
  625. * Description Initiates HID connection to plugged device
  626. *
  627. * Returns HID_SUCCESS
  628. *
  629. ******************************************************************************/
  630. tHID_STATUS hidd_conn_initiate(void)
  631. {
  632. tHID_DEV_DEV_CTB *p_dev = &hd_cb.device;
  633. HIDD_TRACE_API("%s", __func__);
  634. if (!p_dev->in_use) {
  635. HIDD_TRACE_WARNING("%s: no virtual cable established", __func__);
  636. return (HID_ERR_NOT_REGISTERED);
  637. }
  638. if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) {
  639. HIDD_TRACE_WARNING("%s: connection already in progress", __func__);
  640. return (HID_ERR_CONN_IN_PROCESS);
  641. }
  642. p_dev->conn.ctrl_cid = 0;
  643. p_dev->conn.intr_cid = 0;
  644. p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL;
  645. p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
  646. BTM_SetOutService(p_dev->addr, BTM_SEC_SERVICE_HIDD_SEC_CTRL, HIDD_SEC_CHN);
  647. /* Check if L2CAP started the connection process */
  648. if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq(HID_PSM_CONTROL, p_dev->addr)) == 0) {
  649. HIDD_TRACE_WARNING("%s: could not start L2CAP connection", __func__);
  650. hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL);
  651. } else {
  652. p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
  653. }
  654. return (HID_SUCCESS);
  655. }
  656. /*******************************************************************************
  657. *
  658. * Function hidd_conn_disconnect
  659. *
  660. * Description Disconnects existing HID connection
  661. *
  662. * Returns HID_SUCCESS
  663. *
  664. ******************************************************************************/
  665. tHID_STATUS hidd_conn_disconnect(void)
  666. {
  667. tHID_CONN *p_hcon;
  668. HIDD_TRACE_API("%s", __func__);
  669. // clean any outstanding data on intr
  670. if (hd_cb.pending_data) {
  671. osi_free(hd_cb.pending_data);
  672. hd_cb.pending_data = NULL;
  673. }
  674. p_hcon = &hd_cb.device.conn;
  675. if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
  676. /* Set l2cap idle timeout to 0 (so ACL link is disconnected
  677. * immediately after last channel is closed) */
  678. L2CA_SetIdleTimeoutByBdAddr(hd_cb.device.addr, 0, BT_TRANSPORT_BR_EDR);
  679. if (p_hcon->intr_cid) {
  680. p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_INTR;
  681. L2CA_DisconnectReq(p_hcon->intr_cid);
  682. } else if (p_hcon->ctrl_cid) {
  683. p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_CTRL;
  684. L2CA_DisconnectReq(p_hcon->ctrl_cid);
  685. }
  686. } else {
  687. HIDD_TRACE_WARNING("%s: already disconnected", __func__);
  688. p_hcon->conn_state = HID_CONN_STATE_UNUSED;
  689. }
  690. return (HID_SUCCESS);
  691. }
  692. /*******************************************************************************
  693. *
  694. * Function hidd_conn_send_data
  695. *
  696. * Description Sends data to host
  697. *
  698. * Returns tHID_STATUS
  699. *
  700. ******************************************************************************/
  701. tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param, uint8_t data, uint16_t len,
  702. uint8_t *p_data)
  703. {
  704. tHID_CONN *p_hcon;
  705. BT_HDR *p_buf;
  706. uint8_t *p_out;
  707. uint16_t cid;
  708. uint16_t buf_size;
  709. HIDD_TRACE_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__, channel, msg_type, len);
  710. p_hcon = &hd_cb.device.conn;
  711. if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
  712. return HID_ERR_CONGESTED;
  713. }
  714. switch (msg_type) {
  715. case HID_TRANS_HANDSHAKE:
  716. case HID_TRANS_CONTROL:
  717. cid = p_hcon->ctrl_cid;
  718. buf_size = HID_CONTROL_BUF_SIZE;
  719. break;
  720. case HID_TRANS_DATA:
  721. if (channel == HID_CHANNEL_CTRL) {
  722. cid = p_hcon->ctrl_cid;
  723. buf_size = HID_CONTROL_BUF_SIZE;
  724. } else {
  725. cid = p_hcon->intr_cid;
  726. buf_size = HID_INTERRUPT_BUF_SIZE;
  727. }
  728. break;
  729. default:
  730. return (HID_ERR_INVALID_PARAM);
  731. }
  732. p_buf = (BT_HDR *)osi_malloc(buf_size);
  733. if (p_buf == NULL)
  734. return (HID_ERR_NO_RESOURCES);
  735. p_buf->offset = L2CAP_MIN_OFFSET;
  736. p_out = (uint8_t *)(p_buf + 1) + p_buf->offset;
  737. *p_out = HID_BUILD_HDR(msg_type, param);
  738. p_out++;
  739. p_buf->len = 1; // start with header only
  740. // add report id prefix only if non-zero (which is reserved)
  741. if (msg_type == HID_TRANS_DATA && (data || param == HID_PAR_REP_TYPE_OTHER)) {
  742. *p_out = data; // report_id
  743. p_out++;
  744. p_buf->len++;
  745. }
  746. if (len > 0 && p_data != NULL) {
  747. memcpy(p_out, p_data, len);
  748. p_buf->len += len;
  749. }
  750. // check if connected
  751. if (hd_cb.device.state != HIDD_DEV_CONNECTED) {
  752. // for DATA on intr we hold transfer and try to reconnect
  753. if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
  754. // drop previous data, we do not queue it for now
  755. if (hd_cb.pending_data) {
  756. osi_free(hd_cb.pending_data);
  757. }
  758. hd_cb.pending_data = p_buf;
  759. if (hd_cb.device.conn.conn_state == HID_CONN_STATE_UNUSED) {
  760. hidd_conn_initiate();
  761. }
  762. return HID_SUCCESS;
  763. }
  764. return HID_ERR_NO_CONNECTION;
  765. }
  766. #ifdef REPORT_TRANSFER_TIMESTAMP
  767. if (report_transfer) {
  768. HIDD_TRACE_ERROR("%s: report sent", __func__);
  769. }
  770. #endif
  771. HIDD_TRACE_VERBOSE("%s: report sent", __func__);
  772. if (!L2CA_DataWrite(cid, p_buf))
  773. return (HID_ERR_CONGESTED);
  774. return (HID_SUCCESS);
  775. }
  776. #endif