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