Home | History | Annotate | Download | only in hid
      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