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