1 /******************************************************************************
3 * Copyright (C) 2002-2012 Broadcom Corporation
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 ******************************************************************************/
19 /******************************************************************************
21 * this file contains the connection interface functions
23 ******************************************************************************/
30 #include "bt_common.h"
46 #include "osi/include/osi.h"
48 static UINT8 find_conn_by_cid (UINT16 cid);
49 static void hidh_conn_retry (UINT8 dhandle);
51 /********************************************************************************/
52 /* L O C A L F U N C T I O N P R O T O T Y P E S */
53 /********************************************************************************/
54 static void hidh_l2cif_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid,
55 UINT16 psm, UINT8 l2cap_id);
56 static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result);
57 static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
58 static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
59 static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
60 static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
61 static void hidh_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result);
62 static void hidh_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested);
64 static const tL2CAP_APPL_INFO hst_reg_info =
66 hidh_l2cif_connect_ind,
67 hidh_l2cif_connect_cfm,
69 hidh_l2cif_config_ind,
70 hidh_l2cif_config_cfm,
71 hidh_l2cif_disconnect_ind,
72 hidh_l2cif_disconnect_cfm,
76 NULL /* tL2CA_TX_COMPLETE_CB */
79 /*******************************************************************************
81 ** Function hidh_l2cif_reg
83 ** Description This function initializes the SDP unit.
87 *******************************************************************************/
88 tHID_STATUS hidh_conn_reg (void)
92 /* Initialize the L2CAP configuration. We only care about MTU and flush */
93 memset(&hh_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
95 hh_cb.l2cap_cfg.mtu_present = TRUE;
96 hh_cb.l2cap_cfg.mtu = HID_HOST_MTU;
97 hh_cb.l2cap_cfg.flush_to_present = TRUE;
98 hh_cb.l2cap_cfg.flush_to = HID_HOST_FLUSH_TO;
100 /* Now, register with L2CAP */
101 if (!L2CA_Register (HID_PSM_CONTROL, (tL2CAP_APPL_INFO *) &hst_reg_info))
103 HIDH_TRACE_ERROR ("HID-Host Control Registration failed");
104 return (HID_ERR_L2CAP_FAILED) ;
106 if (!L2CA_Register (HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO *) &hst_reg_info))
108 L2CA_Deregister( HID_PSM_CONTROL ) ;
109 HIDH_TRACE_ERROR ("HID-Host Interrupt Registration failed");
110 return (HID_ERR_L2CAP_FAILED) ;
113 for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
115 hh_cb.devices[xx].in_use = FALSE ;
116 hh_cb.devices[xx].conn.conn_state = HID_CONN_STATE_UNUSED;
119 return (HID_SUCCESS);
122 /*******************************************************************************
124 ** Function hidh_conn_disconnect
126 ** Description This function disconnects a connection.
128 ** Returns TRUE if disconnect started, FALSE if already disconnected
130 *******************************************************************************/
131 tHID_STATUS hidh_conn_disconnect (UINT8 dhandle)
133 tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn;
135 HIDH_TRACE_EVENT ("HID-Host disconnect");
137 if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0))
139 p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
141 /* Set l2cap idle timeout to 0 (so ACL link is disconnected
142 * immediately after last channel is closed) */
143 L2CA_SetIdleTimeoutByBdAddr(hh_cb.devices[dhandle].addr, 0, BT_TRANSPORT_BR_EDR);
144 /* Disconnect both interrupt and control channels */
145 if (p_hcon->intr_cid)
146 L2CA_DisconnectReq (p_hcon->intr_cid);
147 else if (p_hcon->ctrl_cid)
148 L2CA_DisconnectReq (p_hcon->ctrl_cid);
152 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
155 return (HID_SUCCESS);
158 /*******************************************************************************
160 ** Function hidh_sec_check_complete_term
162 ** Description HID security check complete callback function.
164 ** Returns Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
165 ** send security block L2C connection response.
167 *******************************************************************************/
168 void hidh_sec_check_complete_term (BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, UINT8 res)
170 tHID_HOST_DEV_CTB *p_dev= (tHID_HOST_DEV_CTB *) p_ref_data;
174 if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
176 p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
178 p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
180 /* Send response to the L2CAP layer. */
181 L2CA_ConnectRsp (p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
183 /* Send a Configuration Request. */
184 L2CA_ConfigReq (p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
187 /* security check fail */
188 else if (res != BTM_SUCCESS)
190 p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */
191 p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
192 L2CA_ConnectRsp (p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
196 /*******************************************************************************
198 ** Function hidh_l2cif_connect_ind
200 ** Description This function handles an inbound connection indication
201 ** from L2CAP. This is the case where we are acting as a
206 *******************************************************************************/
207 static void hidh_l2cif_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid, UINT16 psm, UINT8 l2cap_id)
210 BOOLEAN bAccept = TRUE;
211 UINT8 i = HID_HOST_MAX_DEVICES;
212 tHID_HOST_DEV_CTB *p_dev;
214 HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP conn ind, PSM: 0x%04x CID 0x%x", psm, l2cap_cid);
216 /* always add incoming connection device into HID database by default */
217 if (HID_HostAddDev(bd_addr, HID_SEC_REQUIRED, &i) != HID_SUCCESS)
219 L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_SECURITY_BLOCK, 0);
223 p_hcon = &hh_cb.devices[i].conn;
224 p_dev = &hh_cb.devices[i];
226 /* Check we are in the correct state for this */
227 if (psm == HID_PSM_INTERRUPT)
229 if (p_hcon->ctrl_cid == 0)
231 HIDH_TRACE_WARNING ("HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel");
234 if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
236 HIDH_TRACE_WARNING ("HID-Host Rcvd INTR L2CAP conn ind, wrong state: %d",
241 else /* CTRL channel */
243 #if defined(HID_HOST_ACPT_NEW_CONN) && (HID_HOST_ACPT_NEW_CONN == TRUE)
244 p_hcon->ctrl_cid = p_hcon->intr_cid = 0;
245 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
247 if (p_hcon->conn_state != HID_CONN_STATE_UNUSED)
249 HIDH_TRACE_WARNING ("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: %d",
258 L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_RESOURCES, 0);
262 if (psm == HID_PSM_CONTROL)
264 p_hcon->conn_flags = 0;
265 p_hcon->ctrl_cid = l2cap_cid;
266 p_hcon->ctrl_id = l2cap_id;
267 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' */
269 p_hcon->conn_state = HID_CONN_STATE_SECURITY;
270 if(btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
271 FALSE, BTM_SEC_PROTO_HID,
272 (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
273 &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED)
275 L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
281 /* Transition to the next appropriate state, configuration */
282 p_hcon->conn_state = HID_CONN_STATE_CONFIG;
283 p_hcon->intr_cid = l2cap_cid;
285 /* Send response to the L2CAP layer. */
286 L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
288 /* Send a Configuration Request. */
289 L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
291 HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x CID 0x%x",
295 /*******************************************************************************
297 ** Function hidh_proc_repage_timeout
299 ** Description This function handles timeout (to page device).
303 *******************************************************************************/
304 void hidh_proc_repage_timeout(timer_entry_t *p_te)
306 tHID_HOST_DEV_CTB *device;
307 UINT8 dhandle = PTR_TO_UINT(p_te->param);
309 hidh_conn_initiate(dhandle);
311 device = &hh_cb.devices[dhandle];
312 device->conn_tries++;
314 hh_cb.callback(dhandle, device->addr, HID_HDEV_EVT_RETRYING,
315 device->conn_tries, NULL ) ;
318 /*******************************************************************************
320 ** Function hidh_sec_check_complete_orig
322 ** Description This function checks to see if security procedures are being
323 ** carried out or not..
327 *******************************************************************************/
328 void hidh_sec_check_complete_orig (BD_ADDR bd_addr, tBT_TRANSPORT transport, void *p_ref_data, UINT8 res)
330 tHID_HOST_DEV_CTB *p_dev = (tHID_HOST_DEV_CTB *) p_ref_data;
335 // TODO(armansito): This kind of math to determine a device handle is way
336 // too dirty and unnecessary. Why can't |p_dev| store it's handle?
337 dhandle = (PTR_TO_UINT(p_dev) - PTR_TO_UINT(&(hh_cb.devices[0])))/ sizeof(tHID_HOST_DEV_CTB);
338 if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
340 HIDH_TRACE_EVENT ("HID-Host Originator security pass.");
341 p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
343 /* Transition to the next appropriate state, configuration */
344 p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
345 L2CA_ConfigReq (p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
346 HIDH_TRACE_EVENT ("HID-Host Got Control conn cnf, sent cfg req, CID: 0x%x", p_dev->conn.ctrl_cid);
350 if( res != BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
352 #if (HID_HOST_MAX_CONN_RETRY > 0)
353 if( res == BTM_DEVICE_TIMEOUT )
355 if( p_dev->conn_tries <= HID_HOST_MAX_CONN_RETRY )
357 hidh_conn_retry (dhandle);
362 p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */
363 hidh_conn_disconnect(dhandle);
368 /*******************************************************************************
370 ** Function hidh_l2cif_connect_cfm
372 ** Description This function handles the connect confirm events
373 ** from L2CAP. This is the case when we are acting as a
374 ** client and have sent a connect request.
378 *******************************************************************************/
379 static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result)
382 tHID_CONN *p_hcon = NULL;
384 tHID_HOST_DEV_CTB *p_dev = NULL;
386 /* Find CCB based on CID, and verify we are in a state to accept this message */
387 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
389 p_dev = &hh_cb.devices[dhandle];
390 p_hcon = &hh_cb.devices[dhandle].conn;
394 || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG))
395 || ((l2cap_cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL))
396 || ((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
397 && (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING)))
399 HIDH_TRACE_WARNING ("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
403 if (result != L2CAP_CONN_OK)
405 if (l2cap_cid == p_hcon->ctrl_cid)
406 p_hcon->ctrl_cid = 0;
408 p_hcon->intr_cid = 0;
410 hidh_conn_disconnect(dhandle);
412 #if (HID_HOST_MAX_CONN_RETRY > 0)
413 if( (hh_cb.devices[dhandle].conn_tries <= HID_HOST_MAX_CONN_RETRY) &&
414 (result == HCI_ERR_CONNECTION_TOUT || result == HCI_ERR_UNSPECIFIED ||
415 result == HCI_ERR_PAGE_TIMEOUT) )
417 hidh_conn_retry(dhandle);
422 reason = HID_L2CAP_CONN_FAIL | (UINT32) result ;
423 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
427 /* receive Control Channel connect confirmation */
428 if (l2cap_cid == p_hcon->ctrl_cid)
430 /* check security requirement */
431 p_hcon->conn_state = HID_CONN_STATE_SECURITY;
432 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" */
434 btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
435 TRUE, BTM_SEC_PROTO_HID,
436 (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
437 &hidh_sec_check_complete_orig, p_dev);
441 p_hcon->conn_state = HID_CONN_STATE_CONFIG;
442 /* Send a Configuration Request. */
443 L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
444 HIDH_TRACE_EVENT ("HID-Host got Interrupt conn cnf, sent cfg req, CID: 0x%x", l2cap_cid);
450 /*******************************************************************************
452 ** Function hidh_l2cif_config_ind
454 ** Description This function processes the L2CAP configuration indication
459 *******************************************************************************/
460 static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
463 tHID_CONN *p_hcon = NULL;
466 /* Find CCB based on CID */
467 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
469 p_hcon = &hh_cb.devices[dhandle].conn;
474 HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
478 HIDH_TRACE_EVENT ("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
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;
484 p_hcon->rem_mtu_size = p_cfg->mtu;
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;
491 L2CA_ConfigRsp (l2cap_cid, p_cfg);
493 if (l2cap_cid == p_hcon->ctrl_cid)
495 p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
496 if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
497 (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE))
499 /* Connect interrupt channel */
500 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
501 if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0)
503 HIDH_TRACE_WARNING ("HID-Host INTR Originate failed");
504 reason = HID_L2CAP_REQ_FAIL ;
505 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
506 hidh_conn_disconnect (dhandle);
507 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
512 /* Transition to the next appropriate state, waiting for connection confirm on interrupt channel. */
513 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
518 p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
520 /* If all configuration is complete, change state and tell management we are up */
521 if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
522 && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
524 p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
525 /* Reset disconnect reason to success, as connection successful */
526 p_hcon->disc_reason = HID_SUCCESS;
528 hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
529 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
534 /*******************************************************************************
536 ** Function hidh_l2cif_config_cfm
538 ** Description This function processes the L2CAP configuration confirmation
543 *******************************************************************************/
544 static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
547 tHID_CONN *p_hcon = NULL;
550 HIDH_TRACE_EVENT ("HID-Host Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid, p_cfg->result);
552 /* Find CCB based on CID */
553 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
554 p_hcon = &hh_cb.devices[dhandle].conn;
558 HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
562 /* If configuration failed, disconnect the channel(s) */
563 if (p_cfg->result != L2CAP_CFG_OK)
565 hidh_conn_disconnect (dhandle);
566 reason = HID_L2CAP_CFG_FAIL | (UINT32) p_cfg->result ;
567 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
571 if (l2cap_cid == p_hcon->ctrl_cid)
573 p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
574 if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
575 (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE))
577 /* Connect interrupt channel */
578 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
579 if ((p_hcon->intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0)
581 HIDH_TRACE_WARNING ("HID-Host INTR Originate failed");
582 reason = HID_L2CAP_REQ_FAIL ;
583 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
584 hidh_conn_disconnect (dhandle);
585 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
590 /* Transition to the next appropriate state, waiting for connection confirm on interrupt channel. */
591 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
596 p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
598 /* If all configuration is complete, change state and tell management we are up */
599 if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
600 && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
602 p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
603 /* Reset disconnect reason to success, as connection successful */
604 p_hcon->disc_reason = HID_SUCCESS;
606 hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
607 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
612 /*******************************************************************************
614 ** Function hidh_l2cif_disconnect_ind
616 ** Description This function handles a disconnect event from L2CAP. If
617 ** requested to, we ack the disconnect before dropping the CCB
621 *******************************************************************************/
622 static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed)
625 tHID_CONN *p_hcon = NULL;
626 UINT16 disc_res = HCI_SUCCESS;
627 UINT16 hid_close_evt_reason;
629 /* Find CCB based on CID */
630 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
631 p_hcon = &hh_cb.devices[dhandle].conn;
635 HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x", l2cap_cid);
640 L2CA_DisconnectRsp (l2cap_cid);
642 HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
644 p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
646 if (l2cap_cid == p_hcon->ctrl_cid)
647 p_hcon->ctrl_cid = 0;
649 p_hcon->intr_cid = 0;
651 if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
653 hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
654 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
657 disc_res = btm_get_acl_disc_reason_code();
659 #if (HID_HOST_MAX_CONN_RETRY > 0)
660 if( (disc_res == HCI_ERR_CONNECTION_TOUT || disc_res == HCI_ERR_UNSPECIFIED) &&
661 (!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) &&
662 (hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE))
664 hh_cb.devices[dhandle].conn_tries = 0;
665 hh_cb.devices[dhandle].conn.timer_entry.param = UINT_TO_PTR(dhandle);
666 btu_start_timer (&(hh_cb.devices[dhandle].conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
667 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, disc_res, NULL);
672 /* Set reason code for HID_HDEV_EVT_CLOSE */
673 hid_close_evt_reason = p_hcon->disc_reason;
675 /* If we got baseband sent HCI_DISCONNECT_COMPLETE_EVT due to security failure, then set reason to HID_ERR_AUTH_FAILED */
676 if ((disc_res == HCI_ERR_AUTH_FAILURE) ||
677 (disc_res == HCI_ERR_KEY_MISSING) ||
678 (disc_res == HCI_ERR_HOST_REJECT_SECURITY) ||
679 (disc_res == HCI_ERR_PAIRING_NOT_ALLOWED) ||
680 (disc_res == HCI_ERR_UNIT_KEY_USED) ||
681 (disc_res == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
682 (disc_res == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) ||
683 (disc_res == HCI_ERR_REPEATED_ATTEMPTS))
685 hid_close_evt_reason = HID_ERR_AUTH_FAILED;
688 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, hid_close_evt_reason, NULL ) ;
694 /*******************************************************************************
696 ** Function hidh_l2cif_disconnect_cfm
698 ** Description This function handles a disconnect confirm event from L2CAP.
702 *******************************************************************************/
703 static void hidh_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result)
706 tHID_CONN *p_hcon = NULL;
709 /* Find CCB based on CID */
710 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
711 p_hcon = &hh_cb.devices[dhandle].conn;
715 HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
719 HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
721 if (l2cap_cid == p_hcon->ctrl_cid)
722 p_hcon->ctrl_cid = 0;
725 p_hcon->intr_cid = 0;
726 if (p_hcon->ctrl_cid)
728 HIDH_TRACE_EVENT ("HID-Host Initiating L2CAP Ctrl disconnection");
729 L2CA_DisconnectReq (p_hcon->ctrl_cid);
733 if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
735 hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
736 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
737 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, p_hcon->disc_reason, NULL ) ;
742 /*******************************************************************************
744 ** Function hidh_l2cif_cong_ind
746 ** Description This function handles a congestion status event from L2CAP.
750 *******************************************************************************/
751 static void hidh_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested)
754 tHID_CONN *p_hcon = NULL;
756 /* Find CCB based on CID */
757 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
758 p_hcon = &hh_cb.devices[dhandle].conn;
762 HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid);
766 HIDH_TRACE_EVENT ("HID-Host Rcvd L2CAP congestion status, CID: 0x%x Cong: %d", l2cap_cid, congested);
769 p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
772 p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
778 /*******************************************************************************
780 ** Function hidh_l2cif_data_ind
782 ** Description This function is called when data is received from L2CAP.
783 ** if we are the originator of the connection, we are the SDP
784 ** client, and the received message is queued up for the client.
786 ** If we are the destination of the connection, we are the SDP
787 ** server, so the message is passed to the server processing
792 *******************************************************************************/
793 static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
795 UINT8 *p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
796 UINT8 ttype, param, rep_type, evt;
798 tHID_CONN *p_hcon = NULL;
800 HIDH_TRACE_DEBUG ("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x%04x]", l2cap_cid);
802 /* Find CCB based on CID */
803 if ((dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES)
804 p_hcon = &hh_cb.devices[dhandle].conn;
808 HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
814 ttype = HID_GET_TRANS_FROM_HDR(*p_data);
815 param = HID_GET_PARAM_FROM_HDR(*p_data);
816 rep_type = param & HID_PAR_REP_TYPE_MASK;
819 /* Get rid of the data type */
825 case HID_TRANS_HANDSHAKE:
826 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_HANDSHAKE, param, NULL);
830 case HID_TRANS_CONTROL:
833 case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
834 hidh_conn_disconnect( dhandle ) ;
835 /* Device is unplugging from us. Tell USB */
836 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_VC_UNPLUG, 0, NULL);
847 evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
848 HID_HDEV_EVT_INTR_DATA : HID_HDEV_EVT_CTRL_DATA;
849 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
852 case HID_TRANS_DATAC:
853 evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
854 HID_HDEV_EVT_INTR_DATC : HID_HDEV_EVT_CTRL_DATC;
855 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
865 /*******************************************************************************
867 ** Function hidh_conn_snd_data
869 ** Description This function is sends out data.
871 ** Returns tHID_STATUS
873 *******************************************************************************/
874 tHID_STATUS hidh_conn_snd_data (UINT8 dhandle, UINT8 trans_type, UINT8 param,
875 UINT16 data, UINT8 report_id, BT_HDR *buf)
877 tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn;
881 BOOLEAN seg_req = FALSE;
886 BOOLEAN blank_datc = FALSE;
888 if (!BTM_IsAclConnectionUp(hh_cb.devices[dhandle].addr, BT_TRANSPORT_BR_EDR))
891 osi_freebuf ((void *)buf);
892 return( HID_ERR_NO_CONNECTION );
895 if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED)
898 osi_freebuf ((void *)buf);
899 return( HID_ERR_CONGESTED );
904 case HID_TRANS_CONTROL:
905 case HID_TRANS_GET_REPORT:
906 case HID_TRANS_SET_REPORT:
907 case HID_TRANS_GET_PROTOCOL:
908 case HID_TRANS_SET_PROTOCOL:
909 case HID_TRANS_GET_IDLE:
910 case HID_TRANS_SET_IDLE:
911 cid = p_hcon->ctrl_cid;
912 buf_size = HID_CONTROL_BUF_SIZE;
915 cid = p_hcon->intr_cid;
916 buf_size = HID_INTERRUPT_BUF_SIZE;
919 return (HID_ERR_INVALID_PARAM) ;
922 if( trans_type == HID_TRANS_SET_IDLE )
924 else if( (trans_type == HID_TRANS_GET_REPORT) && (param & 0x08) )
929 if ( buf == NULL || blank_datc )
931 p_buf = (BT_HDR *)osi_getbuf(buf_size);
933 return (HID_ERR_NO_RESOURCES);
935 p_buf->offset = L2CAP_MIN_OFFSET;
941 else if ( (buf->len > (p_hcon->rem_mtu_size - 1)))
943 p_buf = (BT_HDR *)osi_getbuf(buf_size);
945 return (HID_ERR_NO_RESOURCES);
947 p_buf->offset = L2CAP_MIN_OFFSET;
949 data_size = buf->len;
950 bytes_copied = p_hcon->rem_mtu_size - 1;
957 data_size = buf->len;
958 bytes_copied = buf->len;
961 p_out = (UINT8 *)(p_buf + 1) + p_buf->offset;
962 *p_out++ = HID_BUILD_HDR(trans_type, param);
964 /* If report ID required for this device */
965 if( (trans_type == HID_TRANS_GET_REPORT) && (report_id != 0) )
968 data_size = bytes_copied = 1;
974 memcpy (p_out, (((UINT8 *)(buf+1)) + buf->offset), bytes_copied);
975 buf->offset += bytes_copied;
976 buf->len -= bytes_copied;
978 else if( use_data == 1)
980 *(p_out+bytes_copied) = data & 0xff;
982 else if( use_data == 2 )
984 *(p_out+bytes_copied) = data & 0xff;
985 *(p_out+bytes_copied+1) = (data >> 8) & 0xff ;
988 p_buf->len = bytes_copied + 1 + use_data;
989 data_size -= bytes_copied;
991 /* Send the buffer through L2CAP */
992 if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) || (!L2CA_DataWrite (cid, p_buf)))
993 return (HID_ERR_CONGESTED);
996 trans_type = HID_TRANS_DATAC;
997 else if( bytes_copied == (p_hcon->rem_mtu_size - 1) )
999 trans_type = HID_TRANS_DATAC;
1003 } while ((data_size != 0) || blank_datc ) ;
1005 return (HID_SUCCESS);
1007 /*******************************************************************************
1009 ** Function hidh_conn_initiate
1011 ** Description This function is called by the management to create a connection.
1015 *******************************************************************************/
1016 tHID_STATUS hidh_conn_initiate (UINT8 dhandle)
1018 UINT8 service_id = BTM_SEC_SERVICE_HIDH_NOSEC_CTRL;
1019 UINT32 mx_chan_id = HID_NOSEC_CHN;
1021 tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
1023 if( p_dev->conn.conn_state != HID_CONN_STATE_UNUSED )
1024 return( HID_ERR_CONN_IN_PROCESS );
1026 p_dev->conn.ctrl_cid = 0;
1027 p_dev->conn.intr_cid = 0;
1028 p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection Attempt was made but failed */
1030 /* We are the originator of this connection */
1031 p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
1033 if(p_dev->attr_mask & HID_SEC_REQUIRED)
1035 service_id = BTM_SEC_SERVICE_HIDH_SEC_CTRL;
1036 mx_chan_id = HID_SEC_CHN;
1038 BTM_SetOutService (p_dev->addr, service_id, mx_chan_id);
1040 /* Check if L2CAP started the connection process */
1041 if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq (HID_PSM_CONTROL, p_dev->addr)) == 0)
1043 HIDH_TRACE_WARNING ("HID-Host Originate failed");
1044 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
1045 HID_ERR_L2CAP_FAILED, NULL ) ;
1049 /* Transition to the next appropriate state, waiting for connection confirm on control channel. */
1050 p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
1053 return( HID_SUCCESS );
1057 /*******************************************************************************
1059 ** Function find_conn_by_cid
1061 ** Description This function finds a connection control block based on CID
1063 ** Returns address of control block, or NULL if not found
1065 *******************************************************************************/
1066 static UINT8 find_conn_by_cid (UINT16 cid)
1070 for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
1072 if ((hh_cb.devices[xx].in_use) && (hh_cb.devices[xx].conn.conn_state != HID_CONN_STATE_UNUSED)
1073 && ((hh_cb.devices[xx].conn.ctrl_cid == cid) || (hh_cb.devices[xx].conn.intr_cid == cid)))
1080 void hidh_conn_dereg( void )
1082 L2CA_Deregister (HID_PSM_CONTROL);
1083 L2CA_Deregister (HID_PSM_INTERRUPT);
1086 /*******************************************************************************
1088 ** Function hidh_conn_retry
1090 ** Description This function is called to retry a failed connection.
1094 *******************************************************************************/
1095 static void hidh_conn_retry( UINT8 dhandle )
1097 tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
1099 p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
1100 p_dev->conn.timer_entry.param = UINT_TO_PTR(dhandle);
1101 #if (HID_HOST_REPAGE_WIN > 0)
1102 btu_start_timer (&(p_dev->conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
1104 hidh_proc_repage_timeout( &(p_dev->conn.timer_entry) );