1 /****************************************************************************** 2 * 3 * Copyright (C) 2002-2012 Broadcom Corporation 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19 /****************************************************************************** 20 * 21 * this file contains the connection interface functions 22 * 23 ******************************************************************************/ 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 #include "bt_common.h" 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 "hidh_api.h" 43 #include "hidh_int.h" 44 45 #include "osi/include/osi.h" 46 47 extern fixed_queue_t* btu_general_alarm_queue; 48 49 static uint8_t find_conn_by_cid(uint16_t cid); 50 static void hidh_conn_retry(uint8_t dhandle); 51 52 /******************************************************************************/ 53 /* L O C A L F U N C T I O N P R O T O T Y P E S */ 54 /******************************************************************************/ 55 static void hidh_l2cif_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid, 56 uint16_t psm, uint8_t l2cap_id); 57 static void hidh_l2cif_connect_cfm(uint16_t l2cap_cid, uint16_t result); 58 static void hidh_l2cif_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg); 59 static void hidh_l2cif_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg); 60 static void hidh_l2cif_disconnect_ind(uint16_t l2cap_cid, bool ack_needed); 61 static void hidh_l2cif_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg); 62 static void hidh_l2cif_disconnect_cfm(uint16_t l2cap_cid, uint16_t result); 63 static void hidh_l2cif_cong_ind(uint16_t l2cap_cid, bool congested); 64 65 static const tL2CAP_APPL_INFO hst_reg_info = { 66 hidh_l2cif_connect_ind, 67 hidh_l2cif_connect_cfm, 68 NULL, 69 hidh_l2cif_config_ind, 70 hidh_l2cif_config_cfm, 71 hidh_l2cif_disconnect_ind, 72 hidh_l2cif_disconnect_cfm, 73 NULL, 74 hidh_l2cif_data_ind, 75 hidh_l2cif_cong_ind, 76 NULL /* tL2CA_TX_COMPLETE_CB */ 77 }; 78 79 /******************************************************************************* 80 * 81 * Function hidh_l2cif_reg 82 * 83 * Description This function initializes the SDP unit. 84 * 85 * Returns void 86 * 87 ******************************************************************************/ 88 tHID_STATUS hidh_conn_reg(void) { 89 int xx; 90 91 /* Initialize the L2CAP configuration. We only care about MTU and flush */ 92 memset(&hh_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO)); 93 94 hh_cb.l2cap_cfg.mtu_present = true; 95 hh_cb.l2cap_cfg.mtu = HID_HOST_MTU; 96 hh_cb.l2cap_cfg.flush_to_present = true; 97 hh_cb.l2cap_cfg.flush_to = HID_HOST_FLUSH_TO; 98 99 /* Now, register with L2CAP */ 100 if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&hst_reg_info)) { 101 HIDH_TRACE_ERROR("HID-Host Control Registration failed"); 102 return (HID_ERR_L2CAP_FAILED); 103 } 104 if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&hst_reg_info)) { 105 L2CA_Deregister(HID_PSM_CONTROL); 106 HIDH_TRACE_ERROR("HID-Host Interrupt Registration failed"); 107 return (HID_ERR_L2CAP_FAILED); 108 } 109 110 for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++) { 111 hh_cb.devices[xx].in_use = false; 112 hh_cb.devices[xx].conn.conn_state = HID_CONN_STATE_UNUSED; 113 } 114 115 return (HID_SUCCESS); 116 } 117 118 /******************************************************************************* 119 * 120 * Function hidh_conn_disconnect 121 * 122 * Description This function disconnects a connection. 123 * 124 * Returns true if disconnect started, false if already disconnected 125 * 126 ******************************************************************************/ 127 tHID_STATUS hidh_conn_disconnect(uint8_t dhandle) { 128 tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn; 129 130 HIDH_TRACE_EVENT("HID-Host disconnect"); 131 132 if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) { 133 p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING; 134 135 /* Set l2cap idle timeout to 0 (so ACL link is disconnected 136 * immediately after last channel is closed) */ 137 L2CA_SetIdleTimeoutByBdAddr(hh_cb.devices[dhandle].addr, 0, 138 BT_TRANSPORT_BR_EDR); 139 /* Disconnect both interrupt and control channels */ 140 if (p_hcon->intr_cid) 141 L2CA_DisconnectReq(p_hcon->intr_cid); 142 else if (p_hcon->ctrl_cid) 143 L2CA_DisconnectReq(p_hcon->ctrl_cid); 144 } else { 145 p_hcon->conn_state = HID_CONN_STATE_UNUSED; 146 } 147 148 return (HID_SUCCESS); 149 } 150 151 /******************************************************************************* 152 * 153 * Function hidh_sec_check_complete_term 154 * 155 * Description HID security check complete callback function. 156 * 157 * Returns Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise 158 * send security block L2C connection response. 159 * 160 ******************************************************************************/ 161 void hidh_sec_check_complete_term(UNUSED_ATTR BD_ADDR bd_addr, 162 UNUSED_ATTR tBT_TRANSPORT transport, 163 void* p_ref_data, uint8_t res) { 164 tHID_HOST_DEV_CTB* p_dev = (tHID_HOST_DEV_CTB*)p_ref_data; 165 166 if (res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) { 167 p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset 168 disc_reason (from 169 HID_ERR_AUTH_FAILED) */ 170 171 p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR; 172 173 /* Send response to the L2CAP layer. */ 174 L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, 175 L2CAP_CONN_OK, L2CAP_CONN_OK); 176 177 /* Send a Configuration Request. */ 178 L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg); 179 180 } 181 /* security check fail */ 182 else if (res != BTM_SUCCESS) { 183 p_dev->conn.disc_reason = 184 HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */ 185 p_dev->conn.conn_state = HID_CONN_STATE_UNUSED; 186 L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, 187 L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK); 188 } 189 } 190 191 /******************************************************************************* 192 * 193 * Function hidh_l2cif_connect_ind 194 * 195 * Description This function handles an inbound connection indication 196 * from L2CAP. This is the case where we are acting as a 197 * server. 198 * 199 * Returns void 200 * 201 ******************************************************************************/ 202 static void hidh_l2cif_connect_ind(BD_ADDR bd_addr, uint16_t l2cap_cid, 203 uint16_t psm, uint8_t l2cap_id) { 204 tHID_CONN* p_hcon; 205 bool bAccept = true; 206 uint8_t i = HID_HOST_MAX_DEVICES; 207 tHID_HOST_DEV_CTB* p_dev; 208 209 HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP conn ind, PSM: 0x%04x CID 0x%x", psm, 210 l2cap_cid); 211 212 /* always add incoming connection device into HID database by default */ 213 if (HID_HostAddDev(bd_addr, HID_SEC_REQUIRED, &i) != HID_SUCCESS) { 214 L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_SECURITY_BLOCK, 0); 215 return; 216 } 217 218 p_hcon = &hh_cb.devices[i].conn; 219 p_dev = &hh_cb.devices[i]; 220 221 /* Check we are in the correct state for this */ 222 if (psm == HID_PSM_INTERRUPT) { 223 if (p_hcon->ctrl_cid == 0) { 224 HIDH_TRACE_WARNING( 225 "HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel"); 226 bAccept = false; 227 } 228 if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) { 229 HIDH_TRACE_WARNING("HID-Host Rcvd INTR L2CAP conn ind, wrong state: %d", 230 p_hcon->conn_state); 231 bAccept = false; 232 } 233 } else /* CTRL channel */ 234 { 235 #if (HID_HOST_ACPT_NEW_CONN == TRUE) 236 p_hcon->ctrl_cid = p_hcon->intr_cid = 0; 237 p_hcon->conn_state = HID_CONN_STATE_UNUSED; 238 #else 239 if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) { 240 HIDH_TRACE_WARNING("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: %d", 241 p_hcon->conn_state); 242 bAccept = false; 243 } 244 #endif 245 } 246 247 if (!bAccept) { 248 L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_RESOURCES, 0); 249 return; 250 } 251 252 if (psm == HID_PSM_CONTROL) { 253 p_hcon->conn_flags = 0; 254 p_hcon->ctrl_cid = l2cap_cid; 255 p_hcon->ctrl_id = l2cap_id; 256 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs 257 before security is completed, 258 then set CLOSE_EVT reason code 259 to 'connection failure' */ 260 261 p_hcon->conn_state = HID_CONN_STATE_SECURITY; 262 if (btm_sec_mx_access_request( 263 p_dev->addr, HID_PSM_CONTROL, false, BTM_SEC_PROTO_HID, 264 (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN, 265 &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED) { 266 L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, 267 L2CAP_CONN_OK); 268 } 269 270 return; 271 } 272 273 /* Transition to the next appropriate state, configuration */ 274 p_hcon->conn_state = HID_CONN_STATE_CONFIG; 275 p_hcon->intr_cid = l2cap_cid; 276 277 /* Send response to the L2CAP layer. */ 278 L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK); 279 280 /* Send a Configuration Request. */ 281 L2CA_ConfigReq(l2cap_cid, &hh_cb.l2cap_cfg); 282 283 HIDH_TRACE_EVENT( 284 "HID-Host Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x CID 0x%x", 285 psm, l2cap_cid); 286 } 287 288 void hidh_process_repage_timer_timeout(void* data) { 289 uint8_t dhandle = PTR_TO_UINT(data); 290 hidh_try_repage(dhandle); 291 } 292 293 /******************************************************************************* 294 * 295 * Function hidh_try_repage 296 * 297 * Description This function processes timeout (to page device). 298 * 299 * Returns void 300 * 301 ******************************************************************************/ 302 void hidh_try_repage(uint8_t dhandle) { 303 tHID_HOST_DEV_CTB* device; 304 305 hidh_conn_initiate(dhandle); 306 307 device = &hh_cb.devices[dhandle]; 308 device->conn_tries++; 309 310 hh_cb.callback(dhandle, device->addr, HID_HDEV_EVT_RETRYING, 311 device->conn_tries, NULL); 312 } 313 314 /******************************************************************************* 315 * 316 * Function hidh_sec_check_complete_orig 317 * 318 * Description This function checks to see if security procedures are being 319 * carried out or not.. 320 * 321 * Returns void 322 * 323 ******************************************************************************/ 324 void hidh_sec_check_complete_orig(UNUSED_ATTR BD_ADDR bd_addr, 325 UNUSED_ATTR tBT_TRANSPORT transport, 326 void* p_ref_data, uint8_t res) { 327 tHID_HOST_DEV_CTB* p_dev = (tHID_HOST_DEV_CTB*)p_ref_data; 328 uint8_t dhandle; 329 330 // TODO(armansito): This kind of math to determine a device handle is way 331 // too dirty and unnecessary. Why can't |p_dev| store it's handle? 332 dhandle = (PTR_TO_UINT(p_dev) - PTR_TO_UINT(&(hh_cb.devices[0]))) / 333 sizeof(tHID_HOST_DEV_CTB); 334 if (res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) { 335 HIDH_TRACE_EVENT("HID-Host Originator security pass."); 336 p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset 337 disc_reason (from 338 HID_ERR_AUTH_FAILED) */ 339 340 /* Transition to the next appropriate state, configuration */ 341 p_dev->conn.conn_state = HID_CONN_STATE_CONFIG; 342 L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg); 343 HIDH_TRACE_EVENT("HID-Host Got Control conn cnf, sent cfg req, CID: 0x%x", 344 p_dev->conn.ctrl_cid); 345 } 346 347 if (res != BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) { 348 #if (HID_HOST_MAX_CONN_RETRY > 0) 349 if (res == BTM_DEVICE_TIMEOUT) { 350 if (p_dev->conn_tries <= HID_HOST_MAX_CONN_RETRY) { 351 hidh_conn_retry(dhandle); 352 return; 353 } 354 } 355 #endif 356 p_dev->conn.disc_reason = 357 HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */ 358 hidh_conn_disconnect(dhandle); 359 } 360 } 361 362 /******************************************************************************* 363 * 364 * Function hidh_l2cif_connect_cfm 365 * 366 * Description This function handles the connect confirm events 367 * from L2CAP. This is the case when we are acting as a 368 * client and have sent a connect request. 369 * 370 * Returns void 371 * 372 ******************************************************************************/ 373 static void hidh_l2cif_connect_cfm(uint16_t l2cap_cid, uint16_t result) { 374 uint8_t dhandle; 375 tHID_CONN* p_hcon = NULL; 376 uint32_t reason; 377 tHID_HOST_DEV_CTB* p_dev = NULL; 378 379 /* Find CCB based on CID, and verify we are in a state to accept this message 380 */ 381 dhandle = find_conn_by_cid(l2cap_cid); 382 if (dhandle < HID_HOST_MAX_DEVICES) { 383 p_dev = &hh_cb.devices[dhandle]; 384 p_hcon = &hh_cb.devices[dhandle].conn; 385 } 386 387 if ((p_hcon == NULL) || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG)) || 388 ((l2cap_cid == p_hcon->ctrl_cid) && 389 (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL)) || 390 ((l2cap_cid == p_hcon->intr_cid) && 391 (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) && 392 (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING))) { 393 HIDH_TRACE_WARNING("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", 394 l2cap_cid); 395 return; 396 } 397 398 if (result != L2CAP_CONN_OK) { 399 if (l2cap_cid == p_hcon->ctrl_cid) 400 p_hcon->ctrl_cid = 0; 401 else 402 p_hcon->intr_cid = 0; 403 404 hidh_conn_disconnect(dhandle); 405 406 #if (HID_HOST_MAX_CONN_RETRY > 0) 407 if ((hh_cb.devices[dhandle].conn_tries <= HID_HOST_MAX_CONN_RETRY) && 408 (result == HCI_ERR_CONNECTION_TOUT || result == HCI_ERR_UNSPECIFIED || 409 result == HCI_ERR_PAGE_TIMEOUT)) { 410 hidh_conn_retry(dhandle); 411 } else 412 #endif 413 { 414 reason = HID_L2CAP_CONN_FAIL | (uint32_t)result; 415 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, 416 reason, NULL); 417 } 418 return; 419 } 420 /* receive Control Channel connect confirmation */ 421 if (l2cap_cid == p_hcon->ctrl_cid) { 422 /* check security requirement */ 423 p_hcon->conn_state = HID_CONN_STATE_SECURITY; 424 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs 425 before security is completed, 426 then set CLOSE_EVT reason code 427 to "connection failure" */ 428 429 btm_sec_mx_access_request( 430 p_dev->addr, HID_PSM_CONTROL, true, BTM_SEC_PROTO_HID, 431 (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN, 432 &hidh_sec_check_complete_orig, p_dev); 433 } else { 434 p_hcon->conn_state = HID_CONN_STATE_CONFIG; 435 /* Send a Configuration Request. */ 436 L2CA_ConfigReq(l2cap_cid, &hh_cb.l2cap_cfg); 437 HIDH_TRACE_EVENT("HID-Host got Interrupt conn cnf, sent cfg req, CID: 0x%x", 438 l2cap_cid); 439 } 440 441 return; 442 } 443 444 /******************************************************************************* 445 * 446 * Function hidh_l2cif_config_ind 447 * 448 * Description This function processes the L2CAP configuration indication 449 * event. 450 * 451 * Returns void 452 * 453 ******************************************************************************/ 454 static void hidh_l2cif_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) { 455 uint8_t dhandle; 456 tHID_CONN* p_hcon = NULL; 457 uint32_t reason; 458 459 /* Find CCB based on CID */ 460 dhandle = find_conn_by_cid(l2cap_cid); 461 if (dhandle < HID_HOST_MAX_DEVICES) { 462 p_hcon = &hh_cb.devices[dhandle].conn; 463 } 464 465 if (p_hcon == NULL) { 466 HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", 467 l2cap_cid); 468 return; 469 } 470 471 HIDH_TRACE_EVENT("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid); 472 473 /* Remember the remote MTU size */ 474 if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_HOST_MTU)) 475 p_hcon->rem_mtu_size = HID_HOST_MTU; 476 else 477 p_hcon->rem_mtu_size = p_cfg->mtu; 478 479 /* For now, always accept configuration from the other side */ 480 p_cfg->flush_to_present = false; 481 p_cfg->mtu_present = false; 482 p_cfg->result = L2CAP_CFG_OK; 483 484 L2CA_ConfigRsp(l2cap_cid, p_cfg); 485 486 if (l2cap_cid == p_hcon->ctrl_cid) { 487 p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE; 488 if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && 489 (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) { 490 /* Connect interrupt channel */ 491 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for 492 CLOSE_EVT: Connection 493 Attempt was made but failed 494 */ 495 p_hcon->intr_cid = 496 L2CA_ConnectReq(HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr); 497 if (p_hcon->intr_cid == 0) { 498 HIDH_TRACE_WARNING("HID-Host INTR Originate failed"); 499 reason = HID_L2CAP_REQ_FAIL; 500 p_hcon->conn_state = HID_CONN_STATE_UNUSED; 501 hidh_conn_disconnect(dhandle); 502 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, 503 reason, NULL); 504 return; 505 } else { 506 /* Transition to the next appropriate state, waiting for connection 507 * confirm on interrupt channel. */ 508 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR; 509 } 510 } 511 } else 512 p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE; 513 514 /* If all configuration is complete, change state and tell management we are 515 * up */ 516 if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == 517 HID_CONN_FLAGS_ALL_CONFIGURED) && 518 (p_hcon->conn_state == HID_CONN_STATE_CONFIG)) { 519 p_hcon->conn_state = HID_CONN_STATE_CONNECTED; 520 /* Reset disconnect reason to success, as connection successful */ 521 p_hcon->disc_reason = HID_SUCCESS; 522 523 hh_cb.devices[dhandle].state = HID_DEV_CONNECTED; 524 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, 525 NULL); 526 } 527 } 528 529 /******************************************************************************* 530 * 531 * Function hidh_l2cif_config_cfm 532 * 533 * Description This function processes the L2CAP configuration confirmation 534 * event. 535 * 536 * Returns void 537 * 538 ******************************************************************************/ 539 static void hidh_l2cif_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) { 540 uint8_t dhandle; 541 tHID_CONN* p_hcon = NULL; 542 uint32_t reason; 543 544 HIDH_TRACE_EVENT("HID-Host Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid, 545 p_cfg->result); 546 547 /* Find CCB based on CID */ 548 dhandle = find_conn_by_cid(l2cap_cid); 549 if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn; 550 551 if (p_hcon == NULL) { 552 HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", 553 l2cap_cid); 554 return; 555 } 556 557 /* If configuration failed, disconnect the channel(s) */ 558 if (p_cfg->result != L2CAP_CFG_OK) { 559 hidh_conn_disconnect(dhandle); 560 reason = HID_L2CAP_CFG_FAIL | (uint32_t)p_cfg->result; 561 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, 562 reason, NULL); 563 return; 564 } 565 566 if (l2cap_cid == p_hcon->ctrl_cid) { 567 p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE; 568 if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && 569 (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) { 570 /* Connect interrupt channel */ 571 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for 572 CLOSE_EVT: Connection 573 Attempt was made but failed 574 */ 575 p_hcon->intr_cid = 576 L2CA_ConnectReq(HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr); 577 if (p_hcon->intr_cid == 0) { 578 HIDH_TRACE_WARNING("HID-Host INTR Originate failed"); 579 reason = HID_L2CAP_REQ_FAIL; 580 p_hcon->conn_state = HID_CONN_STATE_UNUSED; 581 hidh_conn_disconnect(dhandle); 582 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, 583 reason, NULL); 584 return; 585 } else { 586 /* Transition to the next appropriate state, waiting for connection 587 * confirm on interrupt channel. */ 588 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR; 589 } 590 } 591 } else 592 p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE; 593 594 /* If all configuration is complete, change state and tell management we are 595 * up */ 596 if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == 597 HID_CONN_FLAGS_ALL_CONFIGURED) && 598 (p_hcon->conn_state == HID_CONN_STATE_CONFIG)) { 599 p_hcon->conn_state = HID_CONN_STATE_CONNECTED; 600 /* Reset disconnect reason to success, as connection successful */ 601 p_hcon->disc_reason = HID_SUCCESS; 602 603 hh_cb.devices[dhandle].state = HID_DEV_CONNECTED; 604 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, 605 NULL); 606 } 607 } 608 609 /******************************************************************************* 610 * 611 * Function hidh_l2cif_disconnect_ind 612 * 613 * Description This function handles a disconnect event from L2CAP. If 614 * requested to, we ack the disconnect before dropping the CCB 615 * 616 * Returns void 617 * 618 ******************************************************************************/ 619 static void hidh_l2cif_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) { 620 uint8_t dhandle; 621 tHID_CONN* p_hcon = NULL; 622 uint16_t disc_res = HCI_SUCCESS; 623 uint16_t hid_close_evt_reason; 624 625 /* Find CCB based on CID */ 626 dhandle = find_conn_by_cid(l2cap_cid); 627 if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn; 628 629 if (p_hcon == NULL) { 630 HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x", 631 l2cap_cid); 632 return; 633 } 634 635 if (ack_needed) L2CA_DisconnectRsp(l2cap_cid); 636 637 HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid); 638 639 p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING; 640 641 if (l2cap_cid == p_hcon->ctrl_cid) 642 p_hcon->ctrl_cid = 0; 643 else 644 p_hcon->intr_cid = 0; 645 646 if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) { 647 hh_cb.devices[dhandle].state = HID_DEV_NO_CONN; 648 p_hcon->conn_state = HID_CONN_STATE_UNUSED; 649 650 if (!ack_needed) disc_res = btm_get_acl_disc_reason_code(); 651 652 #if (HID_HOST_MAX_CONN_RETRY > 0) 653 if ((disc_res == HCI_ERR_CONNECTION_TOUT || 654 disc_res == HCI_ERR_UNSPECIFIED) && 655 (!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) && 656 (hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE)) { 657 hh_cb.devices[dhandle].conn_tries = 0; 658 period_ms_t interval_ms = HID_HOST_REPAGE_WIN * 1000; 659 alarm_set_on_queue(hh_cb.devices[dhandle].conn.process_repage_timer, 660 interval_ms, hidh_process_repage_timer_timeout, 661 UINT_TO_PTR(dhandle), btu_general_alarm_queue); 662 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, 663 disc_res, NULL); 664 } else 665 #endif 666 { 667 /* Set reason code for HID_HDEV_EVT_CLOSE */ 668 hid_close_evt_reason = p_hcon->disc_reason; 669 670 /* If we got baseband sent HCI_DISCONNECT_COMPLETE_EVT due to security 671 * failure, then set reason to HID_ERR_AUTH_FAILED */ 672 if ((disc_res == HCI_ERR_AUTH_FAILURE) || 673 (disc_res == HCI_ERR_KEY_MISSING) || 674 (disc_res == HCI_ERR_HOST_REJECT_SECURITY) || 675 (disc_res == HCI_ERR_PAIRING_NOT_ALLOWED) || 676 (disc_res == HCI_ERR_UNIT_KEY_USED) || 677 (disc_res == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) || 678 (disc_res == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) || 679 (disc_res == HCI_ERR_REPEATED_ATTEMPTS)) { 680 hid_close_evt_reason = HID_ERR_AUTH_FAILED; 681 } 682 683 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, 684 hid_close_evt_reason, NULL); 685 } 686 } 687 } 688 689 /******************************************************************************* 690 * 691 * Function hidh_l2cif_disconnect_cfm 692 * 693 * Description This function handles a disconnect confirm event from L2CAP. 694 * 695 * Returns void 696 * 697 ******************************************************************************/ 698 static void hidh_l2cif_disconnect_cfm(uint16_t l2cap_cid, 699 UNUSED_ATTR uint16_t result) { 700 uint8_t dhandle; 701 tHID_CONN* p_hcon = NULL; 702 703 /* Find CCB based on CID */ 704 dhandle = find_conn_by_cid(l2cap_cid); 705 if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn; 706 707 if (p_hcon == NULL) { 708 HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x%x", 709 l2cap_cid); 710 return; 711 } 712 713 HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid); 714 715 if (l2cap_cid == p_hcon->ctrl_cid) 716 p_hcon->ctrl_cid = 0; 717 else { 718 p_hcon->intr_cid = 0; 719 if (p_hcon->ctrl_cid) { 720 HIDH_TRACE_EVENT("HID-Host Initiating L2CAP Ctrl disconnection"); 721 L2CA_DisconnectReq(p_hcon->ctrl_cid); 722 } 723 } 724 725 if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) { 726 hh_cb.devices[dhandle].state = HID_DEV_NO_CONN; 727 p_hcon->conn_state = HID_CONN_STATE_UNUSED; 728 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, 729 p_hcon->disc_reason, NULL); 730 } 731 } 732 733 /******************************************************************************* 734 * 735 * Function hidh_l2cif_cong_ind 736 * 737 * Description This function handles a congestion status event from L2CAP. 738 * 739 * Returns void 740 * 741 ******************************************************************************/ 742 static void hidh_l2cif_cong_ind(uint16_t l2cap_cid, bool congested) { 743 uint8_t dhandle; 744 tHID_CONN* p_hcon = NULL; 745 746 /* Find CCB based on CID */ 747 dhandle = find_conn_by_cid(l2cap_cid); 748 if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn; 749 750 if (p_hcon == NULL) { 751 HIDH_TRACE_WARNING( 752 "HID-Host Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid); 753 return; 754 } 755 756 HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP congestion status, CID: 0x%x Cong: %d", 757 l2cap_cid, congested); 758 759 if (congested) 760 p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED; 761 else { 762 p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED; 763 } 764 } 765 766 /******************************************************************************* 767 * 768 * Function hidh_l2cif_data_ind 769 * 770 * Description This function is called when data is received from L2CAP. 771 * if we are the originator of the connection, we are the SDP 772 * client, and the received message is queued up for the 773 * client. 774 * 775 * If we are the destination of the connection, we are the SDP 776 * server, so the message is passed to the server processing 777 * function. 778 * 779 * Returns void 780 * 781 ******************************************************************************/ 782 static void hidh_l2cif_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) { 783 uint8_t* p_data = (uint8_t*)(p_msg + 1) + p_msg->offset; 784 uint8_t ttype, param, rep_type, evt; 785 uint8_t dhandle; 786 tHID_CONN* p_hcon = NULL; 787 788 HIDH_TRACE_DEBUG("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x%04x]", 789 l2cap_cid); 790 791 /* Find CCB based on CID */ 792 dhandle = find_conn_by_cid(l2cap_cid); 793 if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn; 794 795 if (p_hcon == NULL) { 796 HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP data, unknown CID: 0x%x", 797 l2cap_cid); 798 osi_free(p_msg); 799 return; 800 } 801 802 ttype = HID_GET_TRANS_FROM_HDR(*p_data); 803 param = HID_GET_PARAM_FROM_HDR(*p_data); 804 rep_type = param & HID_PAR_REP_TYPE_MASK; 805 p_data++; 806 807 /* Get rid of the data type */ 808 p_msg->len--; 809 p_msg->offset++; 810 811 switch (ttype) { 812 case HID_TRANS_HANDSHAKE: 813 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, 814 HID_HDEV_EVT_HANDSHAKE, param, NULL); 815 osi_free(p_msg); 816 break; 817 818 case HID_TRANS_CONTROL: 819 switch (param) { 820 case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG: 821 hidh_conn_disconnect(dhandle); 822 /* Device is unplugging from us. Tell USB */ 823 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, 824 HID_HDEV_EVT_VC_UNPLUG, 0, NULL); 825 break; 826 827 default: 828 break; 829 } 830 osi_free(p_msg); 831 break; 832 833 case HID_TRANS_DATA: 834 evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) 835 ? HID_HDEV_EVT_INTR_DATA 836 : HID_HDEV_EVT_CTRL_DATA; 837 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type, 838 p_msg); 839 break; 840 841 case HID_TRANS_DATAC: 842 evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) 843 ? HID_HDEV_EVT_INTR_DATC 844 : HID_HDEV_EVT_CTRL_DATC; 845 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type, 846 p_msg); 847 break; 848 849 default: 850 osi_free(p_msg); 851 break; 852 } 853 } 854 855 /******************************************************************************* 856 * 857 * Function hidh_conn_snd_data 858 * 859 * Description This function is sends out data. 860 * 861 * Returns tHID_STATUS 862 * 863 ******************************************************************************/ 864 tHID_STATUS hidh_conn_snd_data(uint8_t dhandle, uint8_t trans_type, 865 uint8_t param, uint16_t data, uint8_t report_id, 866 BT_HDR* buf) { 867 tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn; 868 BT_HDR* p_buf; 869 uint8_t* p_out; 870 uint16_t bytes_copied; 871 bool seg_req = false; 872 uint16_t data_size; 873 uint16_t cid; 874 uint16_t buf_size; 875 uint8_t use_data = 0; 876 bool blank_datc = false; 877 878 if (!BTM_IsAclConnectionUp(hh_cb.devices[dhandle].addr, 879 BT_TRANSPORT_BR_EDR)) { 880 osi_free(buf); 881 return HID_ERR_NO_CONNECTION; 882 } 883 884 if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) { 885 osi_free(buf); 886 return HID_ERR_CONGESTED; 887 } 888 889 switch (trans_type) { 890 case HID_TRANS_CONTROL: 891 case HID_TRANS_GET_REPORT: 892 case HID_TRANS_SET_REPORT: 893 case HID_TRANS_GET_PROTOCOL: 894 case HID_TRANS_SET_PROTOCOL: 895 case HID_TRANS_GET_IDLE: 896 case HID_TRANS_SET_IDLE: 897 cid = p_hcon->ctrl_cid; 898 buf_size = HID_CONTROL_BUF_SIZE; 899 break; 900 case HID_TRANS_DATA: 901 cid = p_hcon->intr_cid; 902 buf_size = HID_INTERRUPT_BUF_SIZE; 903 break; 904 default: 905 return (HID_ERR_INVALID_PARAM); 906 } 907 908 if (trans_type == HID_TRANS_SET_IDLE) 909 use_data = 1; 910 else if ((trans_type == HID_TRANS_GET_REPORT) && (param & 0x08)) 911 use_data = 2; 912 913 do { 914 if (buf == NULL || blank_datc) { 915 p_buf = (BT_HDR*)osi_malloc(buf_size); 916 917 p_buf->offset = L2CAP_MIN_OFFSET; 918 seg_req = false; 919 data_size = 0; 920 bytes_copied = 0; 921 blank_datc = false; 922 } else if ((buf->len > (p_hcon->rem_mtu_size - 1))) { 923 p_buf = (BT_HDR*)osi_malloc(buf_size); 924 925 p_buf->offset = L2CAP_MIN_OFFSET; 926 seg_req = true; 927 data_size = buf->len; 928 bytes_copied = p_hcon->rem_mtu_size - 1; 929 } else { 930 p_buf = buf; 931 p_buf->offset -= 1; 932 seg_req = false; 933 data_size = buf->len; 934 bytes_copied = buf->len; 935 } 936 937 p_out = (uint8_t*)(p_buf + 1) + p_buf->offset; 938 *p_out++ = HID_BUILD_HDR(trans_type, param); 939 940 /* If report ID required for this device */ 941 if ((trans_type == HID_TRANS_GET_REPORT) && (report_id != 0)) { 942 *p_out = report_id; 943 data_size = bytes_copied = 1; 944 } 945 946 if (seg_req) { 947 memcpy(p_out, (((uint8_t*)(buf + 1)) + buf->offset), bytes_copied); 948 buf->offset += bytes_copied; 949 buf->len -= bytes_copied; 950 } else if (use_data == 1) { 951 *(p_out + bytes_copied) = data & 0xff; 952 } else if (use_data == 2) { 953 *(p_out + bytes_copied) = data & 0xff; 954 *(p_out + bytes_copied + 1) = (data >> 8) & 0xff; 955 } 956 957 p_buf->len = bytes_copied + 1 + use_data; 958 data_size -= bytes_copied; 959 960 /* Send the buffer through L2CAP */ 961 if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) || 962 (!L2CA_DataWrite(cid, p_buf))) 963 return (HID_ERR_CONGESTED); 964 965 if (data_size) 966 trans_type = HID_TRANS_DATAC; 967 else if (bytes_copied == (p_hcon->rem_mtu_size - 1)) { 968 trans_type = HID_TRANS_DATAC; 969 blank_datc = true; 970 } 971 972 } while ((data_size != 0) || blank_datc); 973 974 return (HID_SUCCESS); 975 } 976 /******************************************************************************* 977 * 978 * Function hidh_conn_initiate 979 * 980 * Description This function is called by the management to create a 981 * connection. 982 * 983 * Returns void 984 * 985 ******************************************************************************/ 986 tHID_STATUS hidh_conn_initiate(uint8_t dhandle) { 987 uint8_t service_id = BTM_SEC_SERVICE_HIDH_NOSEC_CTRL; 988 uint32_t mx_chan_id = HID_NOSEC_CHN; 989 990 tHID_HOST_DEV_CTB* p_dev = &hh_cb.devices[dhandle]; 991 992 if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) 993 return (HID_ERR_CONN_IN_PROCESS); 994 995 p_dev->conn.ctrl_cid = 0; 996 p_dev->conn.intr_cid = 0; 997 p_dev->conn.disc_reason = 998 HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection 999 Attempt was made but failed */ 1000 1001 /* We are the originator of this connection */ 1002 p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG; 1003 1004 if (p_dev->attr_mask & HID_SEC_REQUIRED) { 1005 service_id = BTM_SEC_SERVICE_HIDH_SEC_CTRL; 1006 mx_chan_id = HID_SEC_CHN; 1007 } 1008 BTM_SetOutService(p_dev->addr, service_id, mx_chan_id); 1009 1010 /* Check if L2CAP started the connection process */ 1011 p_dev->conn.ctrl_cid = L2CA_ConnectReq(HID_PSM_CONTROL, p_dev->addr); 1012 if (p_dev->conn.ctrl_cid == 0) { 1013 HIDH_TRACE_WARNING("HID-Host Originate failed"); 1014 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, 1015 HID_ERR_L2CAP_FAILED, NULL); 1016 } else { 1017 /* Transition to the next appropriate state, waiting for connection confirm 1018 * on control channel. */ 1019 p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL; 1020 } 1021 1022 return (HID_SUCCESS); 1023 } 1024 1025 /******************************************************************************* 1026 * 1027 * Function find_conn_by_cid 1028 * 1029 * Description This function finds a connection control block based on CID 1030 * 1031 * Returns address of control block, or NULL if not found 1032 * 1033 ******************************************************************************/ 1034 static uint8_t find_conn_by_cid(uint16_t cid) { 1035 uint8_t xx; 1036 1037 for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++) { 1038 if ((hh_cb.devices[xx].in_use) && 1039 (hh_cb.devices[xx].conn.conn_state != HID_CONN_STATE_UNUSED) && 1040 ((hh_cb.devices[xx].conn.ctrl_cid == cid) || 1041 (hh_cb.devices[xx].conn.intr_cid == cid))) 1042 break; 1043 } 1044 1045 return (xx); 1046 } 1047 1048 void hidh_conn_dereg(void) { 1049 L2CA_Deregister(HID_PSM_CONTROL); 1050 L2CA_Deregister(HID_PSM_INTERRUPT); 1051 } 1052 1053 /******************************************************************************* 1054 * 1055 * Function hidh_conn_retry 1056 * 1057 * Description This function is called to retry a failed connection. 1058 * 1059 * Returns void 1060 * 1061 ******************************************************************************/ 1062 static void hidh_conn_retry(uint8_t dhandle) { 1063 tHID_HOST_DEV_CTB* p_dev = &hh_cb.devices[dhandle]; 1064 1065 p_dev->conn.conn_state = HID_CONN_STATE_UNUSED; 1066 #if (HID_HOST_REPAGE_WIN > 0) 1067 period_ms_t interval_ms = HID_HOST_REPAGE_WIN * 1000; 1068 alarm_set_on_queue(p_dev->conn.process_repage_timer, interval_ms, 1069 hidh_process_repage_timer_timeout, UINT_TO_PTR(dhandle), 1070 btu_general_alarm_queue); 1071 #else 1072 hidh_try_repage(dhandle); 1073 #endif 1074 } 1075