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