1 /******************************************************************************
2 *
3 * Copyright (C) 2016 The Android Open Source Project
4 * Copyright (C) 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 <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "bt_types.h"
31
32 #include "l2c_api.h"
33 #include "l2cdefs.h"
34
35 #include "btm_api.h"
36 #include "btm_int.h"
37 #include "btu.h"
38
39 #include "hiddefs.h"
40
41 #include "bt_utils.h"
42 #include "hidd_api.h"
43 #include "hidd_int.h"
44
45 #include "osi/include/osi.h"
46
47 static void hidd_l2cif_connect_ind(const RawAddress& bd_addr, uint16_t cid,
48 uint16_t psm, uint8_t id);
49 static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result);
50 static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
51 static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
52 static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed);
53 static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result);
54 static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg);
55 static void hidd_l2cif_cong_ind(uint16_t cid, bool congested);
56
57 static const tL2CAP_APPL_INFO dev_reg_info = {hidd_l2cif_connect_ind,
58 hidd_l2cif_connect_cfm,
59 NULL,
60 hidd_l2cif_config_ind,
61 hidd_l2cif_config_cfm,
62 hidd_l2cif_disconnect_ind,
63 hidd_l2cif_disconnect_cfm,
64 NULL,
65 hidd_l2cif_data_ind,
66 hidd_l2cif_cong_ind,
67 NULL};
68
69 /*******************************************************************************
70 *
71 * Function hidd_check_config_done
72 *
73 * Description Checks if connection is configured and callback can be fired
74 *
75 * Returns void
76 *
77 ******************************************************************************/
hidd_check_config_done()78 static void hidd_check_config_done() {
79 tHID_CONN* p_hcon;
80
81 p_hcon = &hd_cb.device.conn;
82
83 if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) ==
84 HID_CONN_FLAGS_ALL_CONFIGURED) &&
85 (p_hcon->conn_state == HID_CONN_STATE_CONFIG)) {
86 p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
87
88 hd_cb.device.state = HIDD_DEV_CONNECTED;
89
90 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_OPEN, 0, NULL);
91
92 // send outstanding data on intr
93 if (hd_cb.pending_data) {
94 L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data);
95 hd_cb.pending_data = NULL;
96 }
97 }
98 }
99
100 /*******************************************************************************
101 *
102 * Function hidh_sec_check_complete_term
103 *
104 * Description HID security check complete callback function.
105 *
106 * Returns Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
107 * send security block L2C connection response.
108 *
109 ******************************************************************************/
hidd_sec_check_complete(UNUSED_ATTR const RawAddress * bd_addr,UNUSED_ATTR tBT_TRANSPORT transport,void * p_ref_data,uint8_t res)110 static void hidd_sec_check_complete(UNUSED_ATTR const RawAddress* bd_addr,
111 UNUSED_ATTR tBT_TRANSPORT transport,
112 void* p_ref_data, uint8_t res) {
113 tHID_DEV_DEV_CTB* p_dev = (tHID_DEV_DEV_CTB*)p_ref_data;
114
115 if (res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) {
116 p_dev->conn.disc_reason = HID_SUCCESS;
117 p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
118
119 L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid,
120 L2CAP_CONN_OK, L2CAP_CONN_OK);
121 L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
122 } else if (res != BTM_SUCCESS) {
123 HIDD_TRACE_WARNING("%s: connection rejected by security", __func__);
124
125 p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
126 p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
127 L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid,
128 L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
129 return;
130 }
131 }
132
133 /*******************************************************************************
134 *
135 * Function hidd_sec_check_complete_orig
136 *
137 * Description HID security check complete callback function (device
138 *originated)
139 *
140 * Returns void
141 *
142 ******************************************************************************/
hidd_sec_check_complete_orig(UNUSED_ATTR const RawAddress * bd_addr,UNUSED_ATTR tBT_TRANSPORT transport,void * p_ref_data,uint8_t res)143 void hidd_sec_check_complete_orig(UNUSED_ATTR const RawAddress* bd_addr,
144 UNUSED_ATTR tBT_TRANSPORT transport,
145 void* p_ref_data, uint8_t res) {
146 tHID_DEV_DEV_CTB* p_dev = (tHID_DEV_DEV_CTB*)p_ref_data;
147
148 if (p_dev->conn.conn_state != HID_CONN_STATE_SECURITY) {
149 HIDD_TRACE_WARNING("%s: invalid state (%02x)", __func__,
150 p_dev->conn.conn_state);
151 return;
152 }
153
154 if (res == BTM_SUCCESS) {
155 HIDD_TRACE_EVENT("%s: security ok", __func__);
156 p_dev->conn.disc_reason = HID_SUCCESS;
157
158 p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
159 L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
160 } else {
161 HIDD_TRACE_WARNING("%s: security check failed (%02x)", __func__, res);
162 p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
163 hidd_conn_disconnect();
164 }
165 }
166
167 /*******************************************************************************
168 *
169 * Function hidd_l2cif_connect_ind
170 *
171 * Description Handles incoming L2CAP connection (we act as server)
172 *
173 * Returns void
174 *
175 ******************************************************************************/
hidd_l2cif_connect_ind(const RawAddress & bd_addr,uint16_t cid,uint16_t psm,uint8_t id)176 static void hidd_l2cif_connect_ind(const RawAddress& bd_addr, uint16_t cid,
177 uint16_t psm, uint8_t id) {
178 tHID_CONN* p_hcon;
179 tHID_DEV_DEV_CTB* p_dev;
180 bool accept = TRUE; // accept by default
181
182 HIDD_TRACE_EVENT("%s: psm=%04x cid=%04x id=%02x", __func__, psm, cid, id);
183
184 p_dev = &hd_cb.device;
185
186 if (!hd_cb.allow_incoming) {
187 HIDD_TRACE_WARNING("%s: incoming connections not allowed, rejecting",
188 __func__);
189 L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
190 return;
191 }
192
193 if (p_dev->in_use && bd_addr != p_dev->addr) {
194 HIDD_TRACE_WARNING(
195 "%s: incoming connections from different device, rejecting", __func__);
196 L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
197 return;
198 } else if (!p_dev->in_use) {
199 p_dev->in_use = TRUE;
200 p_dev->addr = bd_addr;
201 p_dev->state = HIDD_DEV_NO_CONN;
202 }
203
204 p_hcon = &hd_cb.device.conn;
205
206 switch (psm) {
207 case HID_PSM_INTERRUPT:
208 if (p_hcon->ctrl_cid == 0) {
209 accept = FALSE;
210 HIDD_TRACE_WARNING("%s: incoming INTR without CTRL, rejecting",
211 __func__);
212 }
213
214 if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) {
215 accept = FALSE;
216 HIDD_TRACE_WARNING("%s: incoming INTR in invalid state (%d), rejecting",
217 __func__, p_hcon->conn_state);
218 }
219
220 break;
221
222 case HID_PSM_CONTROL:
223 if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) {
224 accept = FALSE;
225 HIDD_TRACE_WARNING("%s: incoming CTRL in invalid state (%d), rejecting",
226 __func__, p_hcon->conn_state);
227 }
228
229 break;
230
231 default:
232 accept = FALSE;
233 HIDD_TRACE_ERROR("%s: received invalid PSM, rejecting", __func__);
234 break;
235 }
236
237 if (!accept) {
238 L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
239 return;
240 }
241
242 // for CTRL we need to go through security and we reply in callback from there
243 if (psm == HID_PSM_CONTROL) {
244 p_hcon->conn_flags = 0;
245 p_hcon->ctrl_cid = cid;
246 p_hcon->ctrl_id = id;
247 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
248
249 p_hcon->conn_state = HID_CONN_STATE_SECURITY;
250 if (btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, FALSE,
251 BTM_SEC_PROTO_HID, HIDD_NOSEC_CHN,
252 &hidd_sec_check_complete,
253 p_dev) == BTM_CMD_STARTED) {
254 L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
255 }
256
257 return;
258 }
259
260 // for INTR we go directly to config state
261 p_hcon->conn_state = HID_CONN_STATE_CONFIG;
262 p_hcon->intr_cid = cid;
263
264 L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
265 L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
266 }
267
268 /*******************************************************************************
269 *
270 * Function hidd_l2cif_connect_cfm
271 *
272 * Description Handles L2CAP connection response (we act as client)
273 *
274 * Returns void
275 *
276 ******************************************************************************/
hidd_l2cif_connect_cfm(uint16_t cid,uint16_t result)277 static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result) {
278 tHID_DEV_DEV_CTB* p_dev = &hd_cb.device;
279 tHID_CONN* p_hcon = &hd_cb.device.conn;
280
281 HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result);
282
283 if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
284 HIDD_TRACE_WARNING("%s: unknown cid", __func__);
285 return;
286 }
287
288 if (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) ||
289 ((cid == p_hcon->ctrl_cid) &&
290 (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL)) ||
291 ((cid == p_hcon->intr_cid) &&
292 (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR))) {
293 HIDD_TRACE_WARNING("%s: unexpected", __func__);
294 return;
295 }
296
297 if (result != L2CAP_CONN_OK) {
298 HIDD_TRACE_WARNING("%s: connection failed, now disconnect", __func__);
299
300 if (cid == p_hcon->ctrl_cid)
301 p_hcon->ctrl_cid = 0;
302 else
303 p_hcon->intr_cid = 0;
304
305 hidd_conn_disconnect();
306
307 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
308 HID_L2CAP_CONN_FAIL | (uint32_t)result, NULL);
309 return;
310 }
311
312 /* CTRL connect conf */
313 if (cid == p_hcon->ctrl_cid) {
314 p_hcon->conn_state = HID_CONN_STATE_SECURITY;
315 p_hcon->disc_reason =
316 HID_L2CAP_CONN_FAIL; /* in case disconnected before sec completed */
317
318 btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, TRUE,
319 BTM_SEC_PROTO_HID, HIDD_SEC_CHN,
320 &hidd_sec_check_complete_orig, p_dev);
321 } else {
322 p_hcon->conn_state = HID_CONN_STATE_CONFIG;
323 L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
324 }
325
326 return;
327 }
328
329 /*******************************************************************************
330 *
331 * Function hidd_l2cif_config_ind
332 *
333 * Description Handles incoming L2CAP configuration request
334 *
335 * Returns void
336 *
337 ******************************************************************************/
hidd_l2cif_config_ind(uint16_t cid,tL2CAP_CFG_INFO * p_cfg)338 static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
339 tHID_CONN* p_hcon;
340
341 HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
342
343 p_hcon = &hd_cb.device.conn;
344
345 if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
346 HIDD_TRACE_WARNING("%s: unknown cid", __func__);
347 return;
348 }
349
350 if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_DEV_MTU_SIZE))
351 p_hcon->rem_mtu_size = HID_DEV_MTU_SIZE;
352 else
353 p_hcon->rem_mtu_size = p_cfg->mtu;
354
355 // accept without changes
356 p_cfg->flush_to_present = FALSE;
357 p_cfg->mtu_present = FALSE;
358 p_cfg->result = L2CAP_CFG_OK;
359
360 if (cid == p_hcon->intr_cid && hd_cb.use_in_qos && !p_cfg->qos_present) {
361 p_cfg->qos_present = TRUE;
362 memcpy(&p_cfg->qos, &hd_cb.in_qos, sizeof(FLOW_SPEC));
363 }
364
365 L2CA_ConfigRsp(cid, p_cfg);
366
367 // update flags
368 if (cid == p_hcon->ctrl_cid) {
369 p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
370
371 if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
372 (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) {
373 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
374 if ((p_hcon->intr_cid =
375 L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
376 hidd_conn_disconnect();
377 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
378
379 HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR",
380 __func__);
381 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
382 HID_ERR_L2CAP_FAILED, NULL);
383 return;
384 } else {
385 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
386 }
387 }
388 } else {
389 p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
390 }
391
392 hidd_check_config_done();
393 }
394
395 /*******************************************************************************
396 *
397 * Function hidd_l2cif_config_cfm
398 *
399 * Description Handles incoming L2CAP configuration response
400 *
401 * Returns void
402 *
403 ******************************************************************************/
hidd_l2cif_config_cfm(uint16_t cid,tL2CAP_CFG_INFO * p_cfg)404 static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
405 tHID_CONN* p_hcon;
406 uint32_t reason;
407
408 HIDD_TRACE_EVENT("%s: cid=%04x pcfg->result=%d", __func__, cid,
409 p_cfg->result);
410
411 p_hcon = &hd_cb.device.conn;
412
413 if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
414 HIDD_TRACE_WARNING("%s: unknown cid", __func__);
415 return;
416 }
417
418 if (p_hcon->intr_cid == cid &&
419 p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS && p_cfg->qos_present) {
420 tL2CAP_CFG_INFO new_qos;
421
422 // QoS parameters not accepted for intr, try again with host proposal
423
424 memcpy(&new_qos, &hd_cb.l2cap_intr_cfg, sizeof(new_qos));
425 memcpy(&new_qos.qos, &p_cfg->qos, sizeof(FLOW_SPEC));
426 new_qos.qos_present = TRUE;
427
428 HIDD_TRACE_WARNING("%s: config failed, retry", __func__);
429
430 L2CA_ConfigReq(cid, &new_qos);
431 return;
432 } else if (p_hcon->intr_cid == cid &&
433 p_cfg->result == L2CAP_CFG_UNKNOWN_OPTIONS) {
434 // QoS not understood by remote device, try configuring without QoS
435
436 HIDD_TRACE_WARNING("%s: config failed, retry without QoS", __func__);
437
438 L2CA_ConfigReq(cid, &hd_cb.l2cap_cfg);
439 return;
440 } else if (p_cfg->result != L2CAP_CFG_OK) {
441 HIDD_TRACE_WARNING("%s: config failed, disconnecting", __func__);
442
443 hidd_conn_disconnect();
444 reason = HID_L2CAP_CFG_FAIL | (uint32_t)p_cfg->result;
445
446 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, reason, NULL);
447 return;
448 }
449
450 // update flags
451 if (cid == p_hcon->ctrl_cid) {
452 p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
453
454 if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
455 (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) {
456 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
457 if ((p_hcon->intr_cid =
458 L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
459 hidd_conn_disconnect();
460 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
461
462 HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR",
463 __func__);
464 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
465 HID_ERR_L2CAP_FAILED, NULL);
466 return;
467 } else {
468 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
469 }
470 }
471 } else {
472 p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
473 }
474
475 hidd_check_config_done();
476 }
477
478 /*******************************************************************************
479 *
480 * Function hidd_l2cif_disconnect_ind
481 *
482 * Description Handler incoming L2CAP disconnection request
483 *
484 * Returns void
485 *
486 ******************************************************************************/
hidd_l2cif_disconnect_ind(uint16_t cid,bool ack_needed)487 static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed) {
488 tHID_CONN* p_hcon;
489
490 HIDD_TRACE_EVENT("%s: cid=%04x ack_needed=%d", __func__, cid, ack_needed);
491
492 p_hcon = &hd_cb.device.conn;
493
494 if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
495 (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
496 HIDD_TRACE_WARNING("%s: unknown cid", __func__);
497 return;
498 }
499
500 if (ack_needed) L2CA_DisconnectRsp(cid);
501
502 p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
503
504 if (cid == p_hcon->ctrl_cid)
505 p_hcon->ctrl_cid = 0;
506 else
507 p_hcon->intr_cid = 0;
508
509 if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
510 HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
511
512 // clean any outstanding data on intr
513 if (hd_cb.pending_data) {
514 osi_free(hd_cb.pending_data);
515 hd_cb.pending_data = NULL;
516 }
517
518 hd_cb.device.state = HIDD_DEV_NO_CONN;
519 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
520
521 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, p_hcon->disc_reason,
522 NULL);
523 }
524 }
525
526 /*******************************************************************************
527 *
528 * Function hidd_l2cif_disconnect_cfm
529 *
530 * Description Handles L2CAP disconection response
531 *
532 * Returns void
533 *
534 ******************************************************************************/
hidd_l2cif_disconnect_cfm(uint16_t cid,uint16_t result)535 static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result) {
536 tHID_CONN* p_hcon;
537
538 HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result);
539
540 p_hcon = &hd_cb.device.conn;
541
542 if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
543 (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
544 HIDD_TRACE_WARNING("%s: unknown cid", __func__);
545 return;
546 }
547
548 if (cid == p_hcon->ctrl_cid) {
549 p_hcon->ctrl_cid = 0;
550 } else {
551 p_hcon->intr_cid = 0;
552
553 // now disconnect CTRL
554 L2CA_DisconnectReq(p_hcon->ctrl_cid);
555 }
556
557 if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
558 HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
559
560 hd_cb.device.state = HIDD_DEV_NO_CONN;
561 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
562
563 if (hd_cb.pending_vc_unplug) {
564 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_VC_UNPLUG,
565 p_hcon->disc_reason, NULL);
566 hd_cb.pending_vc_unplug = FALSE;
567 } else {
568 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
569 p_hcon->disc_reason, NULL);
570 }
571 }
572 }
573
574 /*******************************************************************************
575 *
576 * Function hidd_l2cif_cong_ind
577 *
578 * Description Handles L2CAP congestion status event
579 *
580 * Returns void
581 *
582 ******************************************************************************/
hidd_l2cif_cong_ind(uint16_t cid,bool congested)583 static void hidd_l2cif_cong_ind(uint16_t cid, bool congested) {
584 tHID_CONN* p_hcon;
585
586 HIDD_TRACE_EVENT("%s: cid=%04x congested=%d", __func__, cid, congested);
587
588 p_hcon = &hd_cb.device.conn;
589
590 if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
591 (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
592 HIDD_TRACE_WARNING("%s: unknown cid", __func__);
593 return;
594 }
595
596 if (congested) {
597 p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
598 } else {
599 p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
600 }
601 }
602
603 /*******************************************************************************
604 *
605 * Function hidd_l2cif_data_ind
606 *
607 * Description Handler incoming data on L2CAP channel
608 *
609 * Returns void
610 *
611 ******************************************************************************/
hidd_l2cif_data_ind(uint16_t cid,BT_HDR * p_msg)612 static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg) {
613 tHID_CONN* p_hcon;
614 uint8_t* p_data = (uint8_t*)(p_msg + 1) + p_msg->offset;
615 uint8_t msg_type, param;
616 bool err = FALSE;
617
618 HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
619
620 p_hcon = &hd_cb.device.conn;
621
622 if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
623 (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
624 HIDD_TRACE_WARNING("%s: unknown cid", __func__);
625 osi_free(p_msg);
626 return;
627 }
628
629 msg_type = HID_GET_TRANS_FROM_HDR(*p_data);
630 param = HID_GET_PARAM_FROM_HDR(*p_data);
631
632 if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
633 // skip HID header
634 p_msg->offset++;
635 p_msg->len--;
636
637 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_INTR_DATA, 0, p_msg);
638 return;
639 }
640
641 switch (msg_type) {
642 case HID_TRANS_GET_REPORT:
643 // at this stage we don't know if Report Id shall be included in request
644 // so we pass complete packet in callback and let other code analyze this
645 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_GET_REPORT,
646 !!(param & HID_PAR_GET_REP_BUFSIZE_FOLLOWS), p_msg);
647 break;
648
649 case HID_TRANS_SET_REPORT:
650 // as above
651 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_REPORT, 0, p_msg);
652 break;
653
654 case HID_TRANS_GET_IDLE:
655 hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA,
656 HID_PAR_REP_TYPE_OTHER, hd_cb.device.idle_time, 0,
657 NULL);
658 osi_free(p_msg);
659 break;
660
661 case HID_TRANS_SET_IDLE:
662 if (p_msg->len != 2) {
663 HIDD_TRACE_ERROR("%s: invalid len (%d) set idle request received",
664 __func__, p_msg->len);
665 err = TRUE;
666 } else {
667 hd_cb.device.idle_time = p_data[1];
668 HIDD_TRACE_DEBUG("%s: idle_time = %d", __func__,
669 hd_cb.device.idle_time);
670 if (hd_cb.device.idle_time) {
671 HIDD_TRACE_WARNING(
672 "%s: idle_time of %d ms not supported by HID Device", __func__,
673 (hd_cb.device.idle_time * 4));
674 err = TRUE;
675 }
676 }
677 if (!err) {
678 hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
679 HID_PAR_HANDSHAKE_RSP_SUCCESS, 0, 0, NULL);
680 } else {
681 hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
682 HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM, 0, 0,
683 NULL);
684 }
685 osi_free(p_msg);
686 break;
687
688 case HID_TRANS_GET_PROTOCOL:
689 hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA,
690 HID_PAR_REP_TYPE_OTHER, !hd_cb.device.boot_mode, 0,
691 NULL);
692 osi_free(p_msg);
693 break;
694
695 case HID_TRANS_SET_PROTOCOL:
696 hd_cb.device.boot_mode = !(param & HID_PAR_PROTOCOL_MASK);
697 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_PROTOCOL,
698 param & HID_PAR_PROTOCOL_MASK, NULL);
699 hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_SUCCESS,
700 0, 0, NULL);
701 osi_free(p_msg);
702 break;
703
704 case HID_TRANS_CONTROL:
705 switch (param) {
706 case HID_PAR_CONTROL_SUSPEND:
707 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SUSPEND, 0, NULL);
708 break;
709
710 case HID_PAR_CONTROL_EXIT_SUSPEND:
711 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_EXIT_SUSPEND, 0,
712 NULL);
713 break;
714
715 case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
716 hidd_conn_disconnect();
717
718 // set flag so we can notify properly when disconnected
719 hd_cb.pending_vc_unplug = TRUE;
720 break;
721 }
722
723 osi_free(p_msg);
724 break;
725
726 case HID_TRANS_DATA:
727 default:
728 HIDD_TRACE_WARNING("%s: got unsupported msg (%d)", __func__, msg_type);
729 hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
730 HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ, 0, 0,
731 NULL);
732 osi_free(p_msg);
733 break;
734 }
735 }
736
737 /*******************************************************************************
738 *
739 * Function hidd_conn_reg
740 *
741 * Description Registers L2CAP channels
742 *
743 * Returns void
744 *
745 ******************************************************************************/
hidd_conn_reg(void)746 tHID_STATUS hidd_conn_reg(void) {
747 HIDD_TRACE_API("%s", __func__);
748
749 memset(&hd_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
750
751 hd_cb.l2cap_cfg.mtu_present = TRUE;
752 hd_cb.l2cap_cfg.mtu = HID_DEV_MTU_SIZE;
753 hd_cb.l2cap_cfg.flush_to_present = TRUE;
754 hd_cb.l2cap_cfg.flush_to = HID_DEV_FLUSH_TO;
755
756 memset(&hd_cb.l2cap_intr_cfg, 0, sizeof(tL2CAP_CFG_INFO));
757 hd_cb.l2cap_intr_cfg.mtu_present = TRUE;
758 hd_cb.l2cap_intr_cfg.mtu = HID_DEV_MTU_SIZE;
759 hd_cb.l2cap_intr_cfg.flush_to_present = TRUE;
760 hd_cb.l2cap_intr_cfg.flush_to = HID_DEV_FLUSH_TO;
761
762 if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&dev_reg_info)) {
763 HIDD_TRACE_ERROR("HID Control (device) registration failed");
764 return (HID_ERR_L2CAP_FAILED);
765 }
766
767 if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&dev_reg_info)) {
768 L2CA_Deregister(HID_PSM_CONTROL);
769 HIDD_TRACE_ERROR("HID Interrupt (device) registration failed");
770 return (HID_ERR_L2CAP_FAILED);
771 }
772
773 return (HID_SUCCESS);
774 }
775
776 /*******************************************************************************
777 *
778 * Function hidd_conn_dereg
779 *
780 * Description Deregisters L2CAP channels
781 *
782 * Returns void
783 *
784 ******************************************************************************/
hidd_conn_dereg(void)785 void hidd_conn_dereg(void) {
786 HIDD_TRACE_API("%s", __func__);
787
788 L2CA_Deregister(HID_PSM_CONTROL);
789 L2CA_Deregister(HID_PSM_INTERRUPT);
790 }
791
792 /*******************************************************************************
793 *
794 * Function hidd_conn_initiate
795 *
796 * Description Initiates HID connection to plugged device
797 *
798 * Returns HID_SUCCESS
799 *
800 ******************************************************************************/
hidd_conn_initiate(void)801 tHID_STATUS hidd_conn_initiate(void) {
802 tHID_DEV_DEV_CTB* p_dev = &hd_cb.device;
803
804 HIDD_TRACE_API("%s", __func__);
805
806 if (!p_dev->in_use) {
807 HIDD_TRACE_WARNING("%s: no virtual cable established", __func__);
808 return (HID_ERR_NOT_REGISTERED);
809 }
810
811 if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) {
812 HIDD_TRACE_WARNING("%s: connection already in progress", __func__);
813 return (HID_ERR_CONN_IN_PROCESS);
814 }
815
816 p_dev->conn.ctrl_cid = 0;
817 p_dev->conn.intr_cid = 0;
818 p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL;
819
820 p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
821
822 BTM_SetOutService(p_dev->addr, BTM_SEC_SERVICE_HIDD_SEC_CTRL, HIDD_SEC_CHN);
823
824 /* Check if L2CAP started the connection process */
825 if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq(HID_PSM_CONTROL, p_dev->addr)) ==
826 0) {
827 HIDD_TRACE_WARNING("%s: could not start L2CAP connection", __func__);
828 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED,
829 NULL);
830 } else {
831 p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
832 }
833
834 return (HID_SUCCESS);
835 }
836
837 /*******************************************************************************
838 *
839 * Function hidd_conn_disconnect
840 *
841 * Description Disconnects existing HID connection
842 *
843 * Returns HID_SUCCESS
844 *
845 ******************************************************************************/
hidd_conn_disconnect(void)846 tHID_STATUS hidd_conn_disconnect(void) {
847 tHID_CONN* p_hcon;
848
849 HIDD_TRACE_API("%s", __func__);
850
851 // clean any outstanding data on intr
852 if (hd_cb.pending_data) {
853 osi_free(hd_cb.pending_data);
854 hd_cb.pending_data = NULL;
855 }
856
857 p_hcon = &hd_cb.device.conn;
858
859 if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
860 p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
861
862 /* Set l2cap idle timeout to 0 (so ACL link is disconnected
863 * immediately after last channel is closed) */
864 L2CA_SetIdleTimeoutByBdAddr(hd_cb.device.addr, 0, BT_TRANSPORT_BR_EDR);
865
866 if (p_hcon->intr_cid) {
867 L2CA_DisconnectReq(p_hcon->intr_cid);
868 } else if (p_hcon->ctrl_cid) {
869 L2CA_DisconnectReq(p_hcon->ctrl_cid);
870 }
871 } else {
872 HIDD_TRACE_WARNING("%s: already disconnected", __func__);
873 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
874 }
875
876 return (HID_SUCCESS);
877 }
878
879 /*******************************************************************************
880 *
881 * Function hidd_conn_send_data
882 *
883 * Description Sends data to host
884 *
885 * Returns tHID_STATUS
886 *
887 ******************************************************************************/
hidd_conn_send_data(uint8_t channel,uint8_t msg_type,uint8_t param,uint8_t data,uint16_t len,uint8_t * p_data)888 tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type,
889 uint8_t param, uint8_t data, uint16_t len,
890 uint8_t* p_data) {
891 tHID_CONN* p_hcon;
892 BT_HDR* p_buf;
893 uint8_t* p_out;
894 uint16_t cid;
895 uint16_t buf_size;
896
897 HIDD_TRACE_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__,
898 channel, msg_type, len);
899
900 p_hcon = &hd_cb.device.conn;
901
902 if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
903 return HID_ERR_CONGESTED;
904 }
905
906 switch (msg_type) {
907 case HID_TRANS_HANDSHAKE:
908 case HID_TRANS_CONTROL:
909 cid = p_hcon->ctrl_cid;
910 buf_size = HID_CONTROL_BUF_SIZE;
911 break;
912 case HID_TRANS_DATA:
913 if (channel == HID_CHANNEL_CTRL) {
914 cid = p_hcon->ctrl_cid;
915 buf_size = HID_CONTROL_BUF_SIZE;
916 } else {
917 cid = p_hcon->intr_cid;
918 buf_size = HID_INTERRUPT_BUF_SIZE;
919 }
920 break;
921 default:
922 return (HID_ERR_INVALID_PARAM);
923 }
924
925 p_buf = (BT_HDR*)osi_malloc(buf_size);
926 if (p_buf == NULL) return (HID_ERR_NO_RESOURCES);
927
928 p_buf->offset = L2CAP_MIN_OFFSET;
929
930 p_out = (uint8_t*)(p_buf + 1) + p_buf->offset;
931
932 *p_out = HID_BUILD_HDR(msg_type, param);
933 p_out++;
934
935 p_buf->len = 1; // start with header only
936
937 // add report id prefix only if non-zero (which is reserved)
938 if (msg_type == HID_TRANS_DATA && (data || param == HID_PAR_REP_TYPE_OTHER)) {
939 *p_out = data; // report_id
940 p_out++;
941 p_buf->len++;
942 }
943
944 if (len > 0 && p_data != NULL) {
945 memcpy(p_out, p_data, len);
946 p_buf->len += len;
947 }
948
949 // check if connected
950 if (hd_cb.device.state != HIDD_DEV_CONNECTED) {
951 // for DATA on intr we hold transfer and try to reconnect
952 if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
953 // drop previous data, we do not queue it for now
954 if (hd_cb.pending_data) {
955 osi_free(hd_cb.pending_data);
956 }
957
958 hd_cb.pending_data = p_buf;
959
960 if (hd_cb.device.conn.conn_state == HID_CONN_STATE_UNUSED) {
961 hidd_conn_initiate();
962 }
963
964 return HID_SUCCESS;
965 }
966
967 return HID_ERR_NO_CONNECTION;
968 }
969
970 #ifdef REPORT_TRANSFER_TIMESTAMP
971 if (report_transfer) {
972 HIDD_TRACE_ERROR("%s: report sent", __func__);
973 }
974 #endif
975 HIDD_TRACE_VERBOSE("%s: report sent", __func__);
976
977 if (!L2CA_DataWrite(cid, p_buf)) return (HID_ERR_CONGESTED);
978
979 return (HID_SUCCESS);
980 }
981