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