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