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