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