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