1 /******************************************************************************
2 *
3 * Copyright 2002-2012 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 the connection interface functions
22 *
23 ******************************************************************************/
24
25 #include <base/functional/callback.h>
26 #include <base/strings/stringprintf.h>
27 #include <bluetooth/log.h>
28 #include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h>
29 #include <string.h>
30
31 #include "bta/include/bta_sec_api.h"
32 #include "hiddefs.h"
33 #include "hidh_api.h"
34 #include "hidh_int.h"
35 #include "internal_include/bt_target.h"
36 #include "l2c_api.h"
37 #include "l2cdefs.h"
38 #include "osi/include/allocator.h"
39 #include "osi/include/osi.h"
40 #include "stack/include/acl_api.h"
41 #include "stack/include/bt_hdr.h"
42 #include "stack/include/bt_psm_types.h"
43 #include "stack/include/btm_log_history.h"
44 #include "stack/include/stack_metrics_logging.h"
45 #include "types/raw_address.h"
46
47 using namespace bluetooth;
48
49 namespace {
50 constexpr char kBtmLogTag[] = "HIDH";
51 constexpr uint8_t kHID_HOST_MAX_DEVICES = HID_HOST_MAX_DEVICES;
52 }
53
54 static uint8_t find_conn_by_cid(uint16_t cid);
55 static void hidh_conn_retry(uint8_t dhandle);
56
57 /******************************************************************************/
58 /* L O C A L F U N C T I O N P R O T O T Y P E S */
59 /******************************************************************************/
60 static void hidh_l2cif_connect_ind(const RawAddress& bd_addr,
61 uint16_t l2cap_cid, uint16_t psm,
62 uint8_t l2cap_id);
63 static void hidh_l2cif_connect_cfm(uint16_t l2cap_cid, uint16_t result);
64 static void hidh_l2cif_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
65 static void hidh_l2cif_config_cfm(uint16_t l2cap_cid, uint16_t result,
66 tL2CAP_CFG_INFO* p_cfg);
67 static void hidh_l2cif_disconnect_ind(uint16_t l2cap_cid, bool ack_needed);
68 static void hidh_l2cif_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg);
69 static void hidh_l2cif_disconnect(uint16_t l2cap_cid);
70 static void hidh_l2cif_cong_ind(uint16_t l2cap_cid, bool congested);
71 static void hidh_on_l2cap_error(uint16_t l2cap_cid, uint16_t result);
72
73 static const tL2CAP_APPL_INFO hst_reg_info = {
74 .pL2CA_ConnectInd_Cb = hidh_l2cif_connect_ind,
75 .pL2CA_ConnectCfm_Cb = hidh_l2cif_connect_cfm,
76 .pL2CA_ConfigInd_Cb = hidh_l2cif_config_ind,
77 .pL2CA_ConfigCfm_Cb = hidh_l2cif_config_cfm,
78 .pL2CA_DisconnectInd_Cb = hidh_l2cif_disconnect_ind,
79 .pL2CA_DataInd_Cb = hidh_l2cif_data_ind,
80 .pL2CA_CongestionStatus_Cb = hidh_l2cif_cong_ind,
81 .pL2CA_TxComplete_Cb = nullptr,
82 .pL2CA_Error_Cb = hidh_on_l2cap_error,
83 .pL2CA_CreditBasedConnectInd_Cb = nullptr,
84 .pL2CA_CreditBasedConnectCfm_Cb = nullptr,
85 .pL2CA_CreditBasedReconfigCompleted_Cb = nullptr,
86 .pL2CA_CreditBasedCollisionInd_Cb = nullptr,
87 };
88 static void hidh_try_repage(uint8_t dhandle);
89
90 /*******************************************************************************
91 *
92 * Function hidh_l2cif_reg
93 *
94 * Description This function initializes the SDP unit.
95 *
96 * Returns void
97 *
98 ******************************************************************************/
hidh_conn_reg(void)99 tHID_STATUS hidh_conn_reg(void) {
100 int xx;
101
102 /* Initialize the L2CAP configuration. We only care about MTU and flush */
103 memset(&hh_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
104
105 hh_cb.l2cap_cfg.mtu_present = true;
106 hh_cb.l2cap_cfg.mtu = HID_HOST_MTU;
107
108 /* Now, register with L2CAP */
109 if (!L2CA_RegisterWithSecurity(
110 HID_PSM_CONTROL, hst_reg_info, false /* enable_snoop */, nullptr,
111 HID_HOST_MTU, 0, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) {
112 log::error("HID-Host Control Registration failed");
113 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
114 HIDH_ERR_L2CAP_FAILED_AT_REGISTER_CONTROL,
115 1);
116 return (HID_ERR_L2CAP_FAILED);
117 }
118 if (!L2CA_RegisterWithSecurity(
119 HID_PSM_INTERRUPT, hst_reg_info, false /* enable_snoop */, nullptr,
120 HID_HOST_MTU, 0, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) {
121 L2CA_Deregister(HID_PSM_CONTROL);
122 log::error("HID-Host Interrupt Registration failed");
123 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
124 HIDH_ERR_L2CAP_FAILED_AT_REGISTER_INTERRUPT,
125 1);
126 return (HID_ERR_L2CAP_FAILED);
127 }
128
129 for (xx = 0; xx < kHID_HOST_MAX_DEVICES; xx++) {
130 hh_cb.devices[xx].in_use = false;
131 hh_cb.devices[xx].conn.conn_state = HID_CONN_STATE_UNUSED;
132 }
133
134 return (HID_SUCCESS);
135 }
136
137 /*******************************************************************************
138 *
139 * Function hidh_conn_disconnect
140 *
141 * Description This function disconnects a connection.
142 *
143 * Returns true if disconnect started, false if already disconnected
144 *
145 ******************************************************************************/
hidh_conn_disconnect(uint8_t dhandle)146 tHID_STATUS hidh_conn_disconnect(uint8_t dhandle) {
147 tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn;
148
149 if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
150 p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
151
152 /* Set l2cap idle timeout to 0 (so ACL link is disconnected
153 * immediately after last channel is closed) */
154 if (!L2CA_SetIdleTimeoutByBdAddr(hh_cb.devices[dhandle].addr, 0,
155 BT_TRANSPORT_BR_EDR)) {
156 log::warn("Unable to set L2CAP idle timeout peer:{}",
157 hh_cb.devices[dhandle].addr);
158 }
159 /* Disconnect both interrupt and control channels */
160 if (p_hcon->intr_cid)
161 hidh_l2cif_disconnect(p_hcon->intr_cid);
162 else if (p_hcon->ctrl_cid)
163 hidh_l2cif_disconnect(p_hcon->ctrl_cid);
164
165 BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Disconnecting",
166 "local initiated");
167 } else {
168 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
169 }
170 return HID_SUCCESS;
171 }
172
173 /*******************************************************************************
174 *
175 * Function hidh_l2cif_connect_ind
176 *
177 * Description This function handles an inbound connection indication
178 * from L2CAP. This is the case where we are acting as a
179 * server.
180 *
181 * Returns void
182 *
183 ******************************************************************************/
hidh_l2cif_connect_ind(const RawAddress & bd_addr,uint16_t l2cap_cid,uint16_t psm,uint8_t l2cap_id)184 static void hidh_l2cif_connect_ind(const RawAddress& bd_addr,
185 uint16_t l2cap_cid, uint16_t psm,
186 uint8_t l2cap_id) {
187 bool bAccept = true;
188 uint8_t i = kHID_HOST_MAX_DEVICES;
189
190 log::verbose("HID-Host Rcvd L2CAP conn ind, PSM: 0x{:04x} CID 0x{:x}", psm,
191 l2cap_cid);
192
193 /* always add incoming connection device into HID database by default */
194 if (HID_HostAddDev(bd_addr, HID_SEC_REQUIRED, &i) != HID_SUCCESS) {
195 if (!L2CA_DisconnectReq(l2cap_cid)) {
196 log::warn("Unable to send L2CAP disconnect request peer:{} cid:{}",
197 bd_addr, l2cap_cid);
198 }
199 return;
200 }
201
202 tHID_CONN* p_hcon = &hh_cb.devices[i].conn;
203
204 BTM_LogHistory(
205 kBtmLogTag, hh_cb.devices[i].addr, "Connect request",
206 base::StringPrintf("%s state:%s",
207 (psm == HID_PSM_CONTROL) ? "control" : "interrupt",
208 hid_conn::state_text(p_hcon->conn_state).c_str()));
209
210 /* Check we are in the correct state for this */
211 if (psm == HID_PSM_INTERRUPT) {
212 if (p_hcon->ctrl_cid == 0) {
213 log::warn("HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel");
214 bAccept = false;
215 }
216 if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) {
217 log::warn("HID-Host Rcvd INTR L2CAP conn ind, wrong state: {}",
218 p_hcon->conn_state);
219 bAccept = false;
220 }
221 } else /* CTRL channel */
222 {
223 #if (HID_HOST_ACPT_NEW_CONN == TRUE)
224 p_hcon->ctrl_cid = p_hcon->intr_cid = 0;
225 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
226 #else
227 if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) {
228 log::warn("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: {}",
229 p_hcon->conn_state);
230 bAccept = false;
231 }
232 #endif
233 }
234
235 if (!bAccept) {
236 if (!L2CA_DisconnectReq(l2cap_cid)) {
237 log::warn("Unable to send L2CAP disconnect request peer:{} cid:{}",
238 bd_addr, l2cap_cid);
239 }
240 return;
241 }
242
243 if (psm == HID_PSM_CONTROL) {
244 p_hcon->conn_flags = 0;
245 p_hcon->ctrl_cid = l2cap_cid;
246 p_hcon->disc_reason = HID_SUCCESS; /* Authentication passed. Reset
247 disc_reason (from
248 HID_ERR_AUTH_FAILED) */
249 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
250 BTM_LogHistory(kBtmLogTag, hh_cb.devices[i].addr, "Connecting",
251 "waiting for interrupt channel");
252 return;
253 }
254
255 /* Transition to the next appropriate state, configuration */
256 p_hcon->conn_state = HID_CONN_STATE_CONFIG;
257 p_hcon->intr_cid = l2cap_cid;
258
259 log::verbose(
260 "HID-Host Rcvd L2CAP conn ind, sent config req, PSM: 0x{:04x} CID "
261 "0x{:x}",
262 psm, l2cap_cid);
263 }
264
hidh_process_repage_timer_timeout(void * data)265 static void hidh_process_repage_timer_timeout(void* data) {
266 uint8_t dhandle = PTR_TO_UINT(data);
267 hidh_try_repage(dhandle);
268 }
269
270 /*******************************************************************************
271 *
272 * Function hidh_try_repage
273 *
274 * Description This function processes timeout (to page device).
275 *
276 * Returns void
277 *
278 ******************************************************************************/
hidh_try_repage(uint8_t dhandle)279 static void hidh_try_repage(uint8_t dhandle) {
280 tHID_HOST_DEV_CTB* device;
281
282 hidh_conn_initiate(dhandle);
283
284 device = &hh_cb.devices[dhandle];
285 device->conn_tries++;
286
287 hh_cb.callback(dhandle, device->addr, HID_HDEV_EVT_RETRYING,
288 device->conn_tries, NULL);
289 }
290
hidh_on_l2cap_error(uint16_t l2cap_cid,uint16_t result)291 static void hidh_on_l2cap_error(uint16_t l2cap_cid, uint16_t result) {
292 auto dhandle = find_conn_by_cid(l2cap_cid);
293 if (dhandle == kHID_HOST_MAX_DEVICES) {
294 log::warn("Received error for unknown device cid:0x{:04x} reason:{}",
295 l2cap_cid, hci_reason_code_text(to_hci_reason_code(result)));
296 return;
297 }
298
299 hidh_conn_disconnect(dhandle);
300
301 if (result != L2CAP_CFG_FAILED_NO_REASON) {
302 #if (HID_HOST_MAX_CONN_RETRY > 0)
303 if ((hh_cb.devices[dhandle].conn_tries <= HID_HOST_MAX_CONN_RETRY) &&
304 (result == HCI_ERR_CONNECTION_TOUT || result == HCI_ERR_UNSPECIFIED ||
305 result == HCI_ERR_PAGE_TIMEOUT)) {
306 hidh_conn_retry(dhandle);
307 } else
308 #endif
309 {
310 uint32_t reason = HID_L2CAP_CONN_FAIL | (uint32_t)result;
311 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
312 reason, NULL);
313 }
314 } else {
315 uint32_t reason = HID_L2CAP_CFG_FAIL | (uint32_t)result;
316 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
317 reason, NULL);
318 }
319 }
320
321 /*******************************************************************************
322 *
323 * Function hidh_l2cif_connect_cfm
324 *
325 * Description This function handles the connect confirm events
326 * from L2CAP. This is the case when we are acting as a
327 * client and have sent a connect request.
328 *
329 * Returns void
330 *
331 ******************************************************************************/
hidh_l2cif_connect_cfm(uint16_t l2cap_cid,uint16_t result)332 static void hidh_l2cif_connect_cfm(uint16_t l2cap_cid, uint16_t result) {
333 uint8_t dhandle;
334 tHID_CONN* p_hcon = NULL;
335
336 /* Find CCB based on CID, and verify we are in a state to accept this message
337 */
338 dhandle = find_conn_by_cid(l2cap_cid);
339 if (dhandle < kHID_HOST_MAX_DEVICES) {
340 p_hcon = &hh_cb.devices[dhandle].conn;
341 }
342
343 if ((p_hcon == NULL) || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG)) ||
344 ((l2cap_cid == p_hcon->ctrl_cid) &&
345 (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL)) ||
346 ((l2cap_cid == p_hcon->intr_cid) &&
347 (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) &&
348 (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING))) {
349 log::warn("HID-Host Rcvd unexpected conn cnf, CID 0x{:x}", l2cap_cid);
350 return;
351 }
352
353 if (result != L2CAP_CONN_OK) {
354 // TODO: We need to provide the real HCI status if we want to retry.
355 log::error("invoked with non OK status");
356 return;
357 }
358 /* receive Control Channel connect confirmation */
359 if (l2cap_cid == p_hcon->ctrl_cid) {
360 /* check security requirement */
361 p_hcon->disc_reason = HID_SUCCESS; /* Authentication passed. Reset
362 disc_reason (from
363 HID_ERR_AUTH_FAILED) */
364
365 /* Transition to the next appropriate state, configuration */
366 p_hcon->conn_state = HID_CONN_STATE_CONFIG;
367 } else {
368 p_hcon->conn_state = HID_CONN_STATE_CONFIG;
369 }
370 BTM_LogHistory(
371 kBtmLogTag, hh_cb.devices[dhandle].addr, "Configuring",
372 base::StringPrintf("control:0x%04x interrupt:0x%04x state:%s",
373 p_hcon->ctrl_cid, p_hcon->intr_cid,
374 hid_conn::state_text(p_hcon->conn_state).c_str()));
375 return;
376 }
377
378 /*******************************************************************************
379 *
380 * Function hidh_l2cif_config_ind
381 *
382 * Description This function processes the L2CAP configuration indication
383 * event.
384 *
385 * Returns void
386 *
387 ******************************************************************************/
hidh_l2cif_config_ind(uint16_t l2cap_cid,tL2CAP_CFG_INFO * p_cfg)388 static void hidh_l2cif_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
389 uint8_t dhandle;
390 tHID_CONN* p_hcon = NULL;
391
392 /* Find CCB based on CID */
393 dhandle = find_conn_by_cid(l2cap_cid);
394 if (dhandle < kHID_HOST_MAX_DEVICES) {
395 p_hcon = &hh_cb.devices[dhandle].conn;
396 }
397
398 if (p_hcon == NULL) {
399 log::warn("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x{:x}", l2cap_cid);
400 return;
401 }
402
403 log::verbose("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x{:x}", l2cap_cid);
404
405 /* Remember the remote MTU size */
406 if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_HOST_MTU))
407 p_hcon->rem_mtu_size = HID_HOST_MTU;
408 else
409 p_hcon->rem_mtu_size = p_cfg->mtu;
410 }
411
412 /*******************************************************************************
413 *
414 * Function hidh_l2cif_config_cfm
415 *
416 * Description This function processes the L2CAP configuration confirmation
417 * event.
418 *
419 * Returns void
420 *
421 ******************************************************************************/
hidh_l2cif_config_cfm(uint16_t l2cap_cid,uint16_t initiator,tL2CAP_CFG_INFO * p_cfg)422 static void hidh_l2cif_config_cfm(uint16_t l2cap_cid, uint16_t initiator,
423 tL2CAP_CFG_INFO* p_cfg) {
424 hidh_l2cif_config_ind(l2cap_cid, p_cfg);
425
426 uint8_t dhandle;
427 tHID_CONN* p_hcon = NULL;
428 uint32_t reason;
429
430 log::verbose("HID-Host Rcvd cfg cfm, CID: 0x{:x}", l2cap_cid);
431
432 /* Find CCB based on CID */
433 dhandle = find_conn_by_cid(l2cap_cid);
434 if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
435
436 if (p_hcon == NULL) {
437 log::warn("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x{:x}", l2cap_cid);
438 return;
439 }
440
441 if (l2cap_cid == p_hcon->ctrl_cid) {
442 if (p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) {
443 /* Connect interrupt channel */
444 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for
445 CLOSE_EVT: Connection
446 Attempt was made but failed
447 */
448 p_hcon->intr_cid = L2CA_ConnectReqWithSecurity(
449 HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr,
450 BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
451 if (p_hcon->intr_cid == 0) {
452 log::warn("HID-Host INTR Originate failed");
453 reason = HID_L2CAP_REQ_FAIL;
454 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
455 BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Failed");
456 hidh_conn_disconnect(dhandle);
457 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
458 reason, NULL);
459 return;
460 } else {
461 /* Transition to the next appropriate state, waiting for connection
462 * confirm on interrupt channel. */
463 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
464 BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Connecting",
465 "interrupt channel");
466 }
467 }
468 }
469
470 /* If all configuration is complete, change state and tell management we are
471 * up */
472 if (p_hcon->conn_state == HID_CONN_STATE_CONFIG) {
473 p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
474 /* Reset disconnect reason to success, as connection successful */
475 p_hcon->disc_reason = HID_SUCCESS;
476
477 hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
478 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0,
479 NULL);
480 BTM_LogHistory(
481 kBtmLogTag, hh_cb.devices[dhandle].addr, "Connected",
482 base::StringPrintf("control:0x%04x interrupt:0x%04x state:%s",
483 p_hcon->ctrl_cid, p_hcon->intr_cid,
484 hid_conn::state_text(p_hcon->conn_state).c_str()));
485 }
486 }
487
488 /*******************************************************************************
489 *
490 * Function hidh_l2cif_disconnect_ind
491 *
492 * Description This function handles a disconnect event from L2CAP. If
493 * requested to, we ack the disconnect before dropping the CCB
494 *
495 * Returns void
496 *
497 ******************************************************************************/
hidh_l2cif_disconnect_ind(uint16_t l2cap_cid,bool ack_needed)498 static void hidh_l2cif_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) {
499 uint8_t dhandle;
500 tHID_CONN* p_hcon = NULL;
501 tHCI_REASON disc_res = HCI_SUCCESS;
502 uint16_t hid_close_evt_reason;
503
504 /* Find CCB based on CID */
505 dhandle = find_conn_by_cid(l2cap_cid);
506 if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
507
508 if (p_hcon == NULL) {
509 log::warn("HID-Host Rcvd L2CAP disc, unknown CID: 0x{:x}", l2cap_cid);
510 return;
511 }
512
513 log::verbose("HID-Host Rcvd L2CAP disc, CID: 0x{:x}", l2cap_cid);
514
515 p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
516 BTM_LogHistory(
517 kBtmLogTag, hh_cb.devices[dhandle].addr, "Disconnecting",
518 base::StringPrintf("%s channel", (l2cap_cid == p_hcon->ctrl_cid)
519 ? "control"
520 : "interrupt"));
521
522 if (l2cap_cid == p_hcon->ctrl_cid)
523 p_hcon->ctrl_cid = 0;
524 else
525 p_hcon->intr_cid = 0;
526
527 if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
528 hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
529 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
530
531 if (!ack_needed) disc_res = btm_get_acl_disc_reason_code();
532
533 #if (HID_HOST_MAX_CONN_RETRY > 0)
534 if ((disc_res == HCI_ERR_CONNECTION_TOUT ||
535 disc_res == HCI_ERR_UNSPECIFIED) &&
536 (!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) &&
537 (hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE)) {
538 hh_cb.devices[dhandle].conn_tries = 0;
539 uint64_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
540 alarm_set_on_mloop(hh_cb.devices[dhandle].conn.process_repage_timer,
541 interval_ms, hidh_process_repage_timer_timeout,
542 UINT_TO_PTR(dhandle));
543 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
544 disc_res, NULL);
545 } else
546 #endif
547 {
548 /* Set reason code for HID_HDEV_EVT_CLOSE */
549 hid_close_evt_reason = p_hcon->disc_reason;
550
551 /* If we got baseband sent HCI_DISCONNECT_COMPLETE_EVT due to security
552 * failure, then set reason to HID_ERR_AUTH_FAILED */
553 if ((disc_res == HCI_ERR_AUTH_FAILURE) ||
554 (disc_res == HCI_ERR_KEY_MISSING) ||
555 (disc_res == HCI_ERR_HOST_REJECT_SECURITY) ||
556 (disc_res == HCI_ERR_PAIRING_NOT_ALLOWED) ||
557 (disc_res == HCI_ERR_UNIT_KEY_USED) ||
558 (disc_res == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
559 (disc_res == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) ||
560 (disc_res == HCI_ERR_REPEATED_ATTEMPTS)) {
561 log_counter_metrics(
562 android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_AUTH_FAILED,
563 1);
564 hid_close_evt_reason = HID_ERR_AUTH_FAILED;
565 }
566
567 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
568 hid_close_evt_reason, NULL);
569 }
570 }
571 }
572
hidh_l2cif_disconnect(uint16_t l2cap_cid)573 static void hidh_l2cif_disconnect(uint16_t l2cap_cid) {
574 if (!L2CA_DisconnectReq(l2cap_cid)) {
575 log::warn("Unable to send L2CAP disconnect request cid:{}", l2cap_cid);
576 }
577
578 /* Find CCB based on CID */
579 const uint8_t dhandle = find_conn_by_cid(l2cap_cid);
580 if (dhandle == kHID_HOST_MAX_DEVICES) {
581 log::warn("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x{:x}", l2cap_cid);
582 return;
583 }
584
585 tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn;
586 if (l2cap_cid == p_hcon->ctrl_cid) {
587 p_hcon->ctrl_cid = 0;
588 } else {
589 p_hcon->intr_cid = 0;
590 if (p_hcon->ctrl_cid) {
591 log::verbose("HID-Host Initiating L2CAP Ctrl disconnection");
592 if (!L2CA_DisconnectReq(p_hcon->ctrl_cid)) {
593 log::warn("Unable to send L2CAP disconnect request cid:{}",
594 p_hcon->ctrl_cid);
595 }
596 p_hcon->ctrl_cid = 0;
597 }
598 }
599
600 if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
601 hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
602 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
603 BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Disconnected");
604 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
605 p_hcon->disc_reason, NULL);
606 }
607 }
608
609 /*******************************************************************************
610 *
611 * Function hidh_l2cif_cong_ind
612 *
613 * Description This function handles a congestion status event from L2CAP.
614 *
615 * Returns void
616 *
617 ******************************************************************************/
hidh_l2cif_cong_ind(uint16_t l2cap_cid,bool congested)618 static void hidh_l2cif_cong_ind(uint16_t l2cap_cid, bool congested) {
619 uint8_t dhandle;
620 tHID_CONN* p_hcon = NULL;
621
622 /* Find CCB based on CID */
623 dhandle = find_conn_by_cid(l2cap_cid);
624 if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
625
626 if (p_hcon == NULL) {
627 log::warn("HID-Host Rcvd L2CAP congestion status, unknown CID: 0x{:x}",
628 l2cap_cid);
629 return;
630 }
631
632 log::verbose("HID-Host Rcvd L2CAP congestion status, CID: 0x{:x} Cong: {}",
633 l2cap_cid, congested);
634
635 if (congested)
636 p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
637 else {
638 p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
639 }
640 }
641
642 /*******************************************************************************
643 *
644 * Function hidh_l2cif_data_ind
645 *
646 * Description This function is called when data is received from L2CAP.
647 * if we are the originator of the connection, we are the SDP
648 * client, and the received message is queued up for the
649 * client.
650 *
651 * If we are the destination of the connection, we are the SDP
652 * server, so the message is passed to the server processing
653 * function.
654 *
655 * Returns void
656 *
657 ******************************************************************************/
hidh_l2cif_data_ind(uint16_t l2cap_cid,BT_HDR * p_msg)658 static void hidh_l2cif_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) {
659 uint8_t* p_data = (uint8_t*)(p_msg + 1) + p_msg->offset;
660 uint8_t ttype, param, rep_type, evt;
661 uint8_t dhandle;
662 tHID_CONN* p_hcon = NULL;
663
664 log::verbose("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x{:04x}]", l2cap_cid);
665
666 /* Find CCB based on CID */
667 dhandle = find_conn_by_cid(l2cap_cid);
668 if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
669
670 if (p_hcon == NULL) {
671 log::warn("HID-Host Rcvd L2CAP data, unknown CID: 0x{:x}", l2cap_cid);
672 osi_free(p_msg);
673 return;
674 }
675
676 if (p_msg->len < 1) {
677 log::warn("Rcvd L2CAP data, invalid length {}, should be >= 1", p_msg->len);
678 osi_free(p_msg);
679 return;
680 }
681
682 ttype = HID_GET_TRANS_FROM_HDR(*p_data);
683 param = HID_GET_PARAM_FROM_HDR(*p_data);
684 rep_type = param & HID_PAR_REP_TYPE_MASK;
685 p_data++;
686
687 /* Get rid of the data type */
688 p_msg->len--;
689 p_msg->offset++;
690
691 switch (ttype) {
692 case HID_TRANS_HANDSHAKE:
693 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr,
694 HID_HDEV_EVT_HANDSHAKE, param, NULL);
695 osi_free(p_msg);
696 break;
697
698 case HID_TRANS_CONTROL:
699 switch (param) {
700 case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
701 hidh_conn_disconnect(dhandle);
702 /* Device is unplugging from us. Tell USB */
703 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr,
704 HID_HDEV_EVT_VC_UNPLUG, 0, NULL);
705 break;
706
707 default:
708 break;
709 }
710 osi_free(p_msg);
711 break;
712
713 case HID_TRANS_DATA:
714 evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid)
715 ? HID_HDEV_EVT_INTR_DATA
716 : HID_HDEV_EVT_CTRL_DATA;
717 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type,
718 p_msg);
719 break;
720
721 case HID_TRANS_DATAC:
722 evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid)
723 ? HID_HDEV_EVT_INTR_DATC
724 : HID_HDEV_EVT_CTRL_DATC;
725 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type,
726 p_msg);
727 break;
728
729 default:
730 osi_free(p_msg);
731 break;
732 }
733 }
734
735 /*******************************************************************************
736 *
737 * Function hidh_conn_snd_data
738 *
739 * Description This function is sends out data.
740 *
741 * Returns tHID_STATUS
742 *
743 ******************************************************************************/
hidh_conn_snd_data(uint8_t dhandle,uint8_t trans_type,uint8_t param,uint16_t data,uint8_t report_id,BT_HDR * buf)744 tHID_STATUS hidh_conn_snd_data(uint8_t dhandle, uint8_t trans_type,
745 uint8_t param, uint16_t data, uint8_t report_id,
746 BT_HDR* buf) {
747 tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn;
748 BT_HDR* p_buf;
749 uint8_t* p_out;
750 uint16_t bytes_copied;
751 bool seg_req = false;
752 uint16_t data_size;
753 uint16_t cid;
754 uint16_t buf_size;
755 uint8_t use_data = 0;
756 bool blank_datc = false;
757
758 if (!BTM_IsAclConnectionUp(hh_cb.devices[dhandle].addr,
759 BT_TRANSPORT_BR_EDR)) {
760 osi_free(buf);
761 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
762 HIDH_ERR_NO_CONNECTION_AT_SEND_DATA,
763 1);
764 return HID_ERR_NO_CONNECTION;
765 }
766
767 if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
768 osi_free(buf);
769 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
770 HIDH_ERR_CONGESTED_AT_FLAG_CHECK,
771 1);
772 return HID_ERR_CONGESTED;
773 }
774
775 switch (trans_type) {
776 case HID_TRANS_CONTROL:
777 case HID_TRANS_GET_REPORT:
778 case HID_TRANS_SET_REPORT:
779 case HID_TRANS_GET_PROTOCOL:
780 case HID_TRANS_SET_PROTOCOL:
781 case HID_TRANS_GET_IDLE:
782 case HID_TRANS_SET_IDLE:
783 cid = p_hcon->ctrl_cid;
784 buf_size = HID_CONTROL_BUF_SIZE;
785 break;
786 case HID_TRANS_DATA:
787 cid = p_hcon->intr_cid;
788 buf_size = HID_INTERRUPT_BUF_SIZE;
789 break;
790 default:
791 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
792 HIDH_ERR_INVALID_PARAM_AT_SEND_DATA,
793 1);
794 return (HID_ERR_INVALID_PARAM);
795 }
796
797 if (trans_type == HID_TRANS_SET_IDLE)
798 use_data = 1;
799 else if ((trans_type == HID_TRANS_GET_REPORT) && (param & 0x08))
800 use_data = 2;
801
802 do {
803 if (buf == NULL || blank_datc) {
804 p_buf = (BT_HDR*)osi_malloc(buf_size);
805
806 p_buf->offset = L2CAP_MIN_OFFSET;
807 seg_req = false;
808 data_size = 0;
809 bytes_copied = 0;
810 blank_datc = false;
811 } else if ((buf->len > (p_hcon->rem_mtu_size - 1))) {
812 p_buf = (BT_HDR*)osi_malloc(buf_size);
813
814 p_buf->offset = L2CAP_MIN_OFFSET;
815 seg_req = true;
816 data_size = buf->len;
817 bytes_copied = p_hcon->rem_mtu_size - 1;
818 } else {
819 p_buf = buf;
820 p_buf->offset -= 1;
821 seg_req = false;
822 data_size = buf->len;
823 bytes_copied = buf->len;
824 }
825
826 p_out = (uint8_t*)(p_buf + 1) + p_buf->offset;
827 *p_out++ = HID_BUILD_HDR(trans_type, param);
828
829 /* If report ID required for this device */
830 if ((trans_type == HID_TRANS_GET_REPORT) && (report_id != 0)) {
831 *p_out = report_id;
832 data_size = bytes_copied = 1;
833 }
834
835 if (seg_req) {
836 memcpy(p_out, (((uint8_t*)(buf + 1)) + buf->offset), bytes_copied);
837 buf->offset += bytes_copied;
838 buf->len -= bytes_copied;
839 } else if (use_data == 1) {
840 *(p_out + bytes_copied) = data & 0xff;
841 } else if (use_data == 2) {
842 *(p_out + bytes_copied) = data & 0xff;
843 *(p_out + bytes_copied + 1) = (data >> 8) & 0xff;
844 }
845
846 p_buf->len = bytes_copied + 1 + use_data;
847 data_size -= bytes_copied;
848
849 /* Send the buffer through L2CAP */
850 if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) ||
851 (!L2CA_DataWrite(cid, p_buf))) {
852 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
853 HIDH_ERR_CONGESTED_AT_SEND_DATA,
854 1);
855 return (HID_ERR_CONGESTED);
856 }
857
858 if (data_size)
859 trans_type = HID_TRANS_DATAC;
860 else if (bytes_copied == (p_hcon->rem_mtu_size - 1)) {
861 trans_type = HID_TRANS_DATAC;
862 blank_datc = true;
863 }
864
865 } while ((data_size != 0) || blank_datc);
866
867 return (HID_SUCCESS);
868 }
869 /*******************************************************************************
870 *
871 * Function hidh_conn_initiate
872 *
873 * Description This function is called by the management to create a
874 * connection.
875 *
876 * Returns void
877 *
878 ******************************************************************************/
hidh_conn_initiate(uint8_t dhandle)879 tHID_STATUS hidh_conn_initiate(uint8_t dhandle) {
880 tHID_HOST_DEV_CTB* p_dev = &hh_cb.devices[dhandle];
881
882 if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) {
883 log_counter_metrics(
884 android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_CONN_IN_PROCESS,
885 1);
886 return (HID_ERR_CONN_IN_PROCESS);
887 }
888
889 p_dev->conn.ctrl_cid = 0;
890 p_dev->conn.intr_cid = 0;
891 p_dev->conn.disc_reason =
892 HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection
893 Attempt was made but failed */
894
895 /* We are the originator of this connection */
896 p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
897
898 /* Check if L2CAP started the connection process */
899 p_dev->conn.ctrl_cid = L2CA_ConnectReqWithSecurity(
900 HID_PSM_CONTROL, p_dev->addr, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
901 if (p_dev->conn.ctrl_cid == 0) {
902 log::warn("HID-Host Originate failed");
903 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
904 HID_ERR_L2CAP_FAILED, NULL);
905 log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
906 HIDH_ERR_L2CAP_FAILED_AT_INITIATE,
907 1);
908 } else {
909 /* Transition to the next appropriate state, waiting for connection confirm
910 * on control channel. */
911 p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
912 BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Connecting",
913 "control channel");
914 }
915
916 return (HID_SUCCESS);
917 }
918
919 /*******************************************************************************
920 *
921 * Function find_conn_by_cid
922 *
923 * Description This function finds a connection control block based on CID.
924 *
925 * Returns index of control block, or kHID_HOST_MAX_DEVICES if not
926 * found.
927 *
928 ******************************************************************************/
find_conn_by_cid(uint16_t cid)929 static uint8_t find_conn_by_cid(uint16_t cid) {
930 uint8_t xx;
931
932 for (xx = 0; xx < kHID_HOST_MAX_DEVICES; xx++) {
933 if ((hh_cb.devices[xx].in_use) &&
934 (hh_cb.devices[xx].conn.conn_state != HID_CONN_STATE_UNUSED) &&
935 ((hh_cb.devices[xx].conn.ctrl_cid == cid) ||
936 (hh_cb.devices[xx].conn.intr_cid == cid)))
937 break;
938 }
939
940 return (xx);
941 }
942
hidh_conn_dereg(void)943 void hidh_conn_dereg(void) {
944 L2CA_Deregister(HID_PSM_CONTROL);
945 L2CA_Deregister(HID_PSM_INTERRUPT);
946 }
947
948 /*******************************************************************************
949 *
950 * Function hidh_conn_retry
951 *
952 * Description This function is called to retry a failed connection.
953 *
954 * Returns void
955 *
956 ******************************************************************************/
hidh_conn_retry(uint8_t dhandle)957 static void hidh_conn_retry(uint8_t dhandle) {
958 tHID_HOST_DEV_CTB* p_dev = &hh_cb.devices[dhandle];
959
960 p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
961 #if (HID_HOST_REPAGE_WIN > 0)
962 uint64_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
963 alarm_set_on_mloop(p_dev->conn.process_repage_timer, interval_ms,
964 hidh_process_repage_timer_timeout, UINT_TO_PTR(dhandle));
965 #else
966 hidh_try_repage(dhandle);
967 #endif
968 }
969