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