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