Home | History | Annotate | Download | only in hid
      1 /******************************************************************************
      2  *
      3  *  Copyright 2016 The Android Open Source Project
      4  *  Copyright 2002-2012 Broadcom Corporation
      5  *
      6  *  Licensed under the Apache License, Version 2.0 (the "License");
      7  *  you may not use this file except in compliance with the License.
      8  *  You may obtain a copy of the License at:
      9  *
     10  *  http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  *  Unless required by applicable law or agreed to in writing, software
     13  *  distributed under the License is distributed on an "AS IS" BASIS,
     14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  *  See the License for the specific language governing permissions and
     16  *  limitations under the License.
     17  *
     18  ******************************************************************************/
     19 
     20 /******************************************************************************
     21  *
     22  *  this file contains the connection interface functions
     23  *
     24  ******************************************************************************/
     25 
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 #include <string.h>
     29 
     30 #include "bt_types.h"
     31 
     32 #include "l2c_api.h"
     33 #include "l2cdefs.h"
     34 
     35 #include "btm_api.h"
     36 #include "btm_int.h"
     37 #include "btu.h"
     38 
     39 #include "hiddefs.h"
     40 
     41 #include "bt_utils.h"
     42 #include "hidd_api.h"
     43 #include "hidd_int.h"
     44 
     45 #include "osi/include/osi.h"
     46 
     47 static void hidd_l2cif_connect_ind(const RawAddress& bd_addr, uint16_t cid,
     48                                    uint16_t psm, uint8_t id);
     49 static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result);
     50 static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
     51 static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
     52 static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed);
     53 static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result);
     54 static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg);
     55 static void hidd_l2cif_cong_ind(uint16_t cid, bool congested);
     56 
     57 static const tL2CAP_APPL_INFO dev_reg_info = {
     58     hidd_l2cif_connect_ind,
     59     hidd_l2cif_connect_cfm,
     60     NULL,
     61     hidd_l2cif_config_ind,
     62     hidd_l2cif_config_cfm,
     63     hidd_l2cif_disconnect_ind,
     64     hidd_l2cif_disconnect_cfm,
     65     NULL,
     66     hidd_l2cif_data_ind,
     67     hidd_l2cif_cong_ind,
     68     NULL,
     69     NULL /* tL2CA_CREDITS_RECEIVED_CB */};
     70 
     71 /*******************************************************************************
     72  *
     73  * Function         hidd_check_config_done
     74  *
     75  * Description      Checks if connection is configured and callback can be fired
     76  *
     77  * Returns          void
     78  *
     79  ******************************************************************************/
     80 static void hidd_check_config_done() {
     81   tHID_CONN* p_hcon;
     82 
     83   p_hcon = &hd_cb.device.conn;
     84 
     85   if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) ==
     86        HID_CONN_FLAGS_ALL_CONFIGURED) &&
     87       (p_hcon->conn_state == HID_CONN_STATE_CONFIG)) {
     88     p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
     89 
     90     hd_cb.device.state = HIDD_DEV_CONNECTED;
     91 
     92     hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_OPEN, 0, NULL);
     93 
     94     // send outstanding data on intr
     95     if (hd_cb.pending_data) {
     96       L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data);
     97       hd_cb.pending_data = NULL;
     98     }
     99   }
    100 }
    101 
    102 /*******************************************************************************
    103  *
    104  * Function         hidh_sec_check_complete_term
    105  *
    106  * Description      HID security check complete callback function.
    107  *
    108  * Returns          Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
    109  *                  send security block L2C connection response.
    110  *
    111  ******************************************************************************/
    112 static void hidd_sec_check_complete(UNUSED_ATTR const RawAddress* bd_addr,
    113                                     UNUSED_ATTR tBT_TRANSPORT transport,
    114                                     void* p_ref_data, uint8_t res) {
    115   tHID_DEV_DEV_CTB* p_dev = (tHID_DEV_DEV_CTB*)p_ref_data;
    116 
    117   if (res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) {
    118     p_dev->conn.disc_reason = HID_SUCCESS;
    119     p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
    120 
    121     L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid,
    122                     L2CAP_CONN_OK, L2CAP_CONN_OK);
    123     L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
    124   } else if (res != BTM_SUCCESS) {
    125     HIDD_TRACE_WARNING("%s: connection rejected by security", __func__);
    126 
    127     p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
    128     p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
    129     L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid,
    130                     L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
    131     return;
    132   }
    133 }
    134 
    135 /*******************************************************************************
    136  *
    137  * Function         hidd_sec_check_complete_orig
    138  *
    139  * Description      HID security check complete callback function (device
    140 *originated)
    141  *
    142  * Returns          void
    143  *
    144  ******************************************************************************/
    145 void hidd_sec_check_complete_orig(UNUSED_ATTR const RawAddress* bd_addr,
    146                                   UNUSED_ATTR tBT_TRANSPORT transport,
    147                                   void* p_ref_data, uint8_t res) {
    148   tHID_DEV_DEV_CTB* p_dev = (tHID_DEV_DEV_CTB*)p_ref_data;
    149 
    150   if (p_dev->conn.conn_state != HID_CONN_STATE_SECURITY) {
    151     HIDD_TRACE_WARNING("%s: invalid state (%02x)", __func__,
    152                        p_dev->conn.conn_state);
    153     return;
    154   }
    155 
    156   if (res == BTM_SUCCESS) {
    157     HIDD_TRACE_EVENT("%s: security ok", __func__);
    158     p_dev->conn.disc_reason = HID_SUCCESS;
    159 
    160     p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
    161     L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
    162   } else {
    163     HIDD_TRACE_WARNING("%s: security check failed (%02x)", __func__, res);
    164     p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
    165     hidd_conn_disconnect();
    166   }
    167 }
    168 
    169 /*******************************************************************************
    170  *
    171  * Function         hidd_l2cif_connect_ind
    172  *
    173  * Description      Handles incoming L2CAP connection (we act as server)
    174  *
    175  * Returns          void
    176  *
    177  ******************************************************************************/
    178 static void hidd_l2cif_connect_ind(const RawAddress& bd_addr, uint16_t cid,
    179                                    uint16_t psm, uint8_t id) {
    180   tHID_CONN* p_hcon;
    181   tHID_DEV_DEV_CTB* p_dev;
    182   bool accept = TRUE;  // accept by default
    183 
    184   HIDD_TRACE_EVENT("%s: psm=%04x cid=%04x id=%02x", __func__, psm, cid, id);
    185 
    186   p_dev = &hd_cb.device;
    187 
    188   if (!hd_cb.allow_incoming) {
    189     HIDD_TRACE_WARNING("%s: incoming connections not allowed, rejecting",
    190                        __func__);
    191     L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
    192     return;
    193   }
    194 
    195   p_hcon = &hd_cb.device.conn;
    196 
    197   switch (psm) {
    198     case HID_PSM_INTERRUPT:
    199       if (p_hcon->ctrl_cid == 0) {
    200         accept = FALSE;
    201         HIDD_TRACE_WARNING("%s: incoming INTR without CTRL, rejecting",
    202                            __func__);
    203       }
    204 
    205       if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) {
    206         accept = FALSE;
    207         HIDD_TRACE_WARNING("%s: incoming INTR in invalid state (%d), rejecting",
    208                            __func__, p_hcon->conn_state);
    209       }
    210 
    211       break;
    212 
    213     case HID_PSM_CONTROL:
    214       if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) {
    215         accept = FALSE;
    216         HIDD_TRACE_WARNING("%s: incoming CTRL in invalid state (%d), rejecting",
    217                            __func__, p_hcon->conn_state);
    218       }
    219 
    220       break;
    221 
    222     default:
    223       accept = FALSE;
    224       HIDD_TRACE_ERROR("%s: received invalid PSM, rejecting", __func__);
    225       break;
    226   }
    227 
    228   if (!accept) {
    229     L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
    230     return;
    231   }
    232 
    233   // for CTRL we need to go through security and we reply in callback from there
    234   if (psm == HID_PSM_CONTROL) {
    235     // We are ready to accept connection from this device, since we aren't
    236     // connected to anything and are in the correct state.
    237     p_dev->in_use = TRUE;
    238     p_dev->addr = bd_addr;
    239     p_dev->state = HIDD_DEV_NO_CONN;
    240 
    241     p_hcon->conn_flags = 0;
    242     p_hcon->ctrl_cid = cid;
    243     p_hcon->ctrl_id = id;
    244     p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
    245 
    246     p_hcon->conn_state = HID_CONN_STATE_SECURITY;
    247     if (btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, FALSE,
    248                                   BTM_SEC_PROTO_HID, HIDD_NOSEC_CHN,
    249                                   &hidd_sec_check_complete,
    250                                   p_dev) == BTM_CMD_STARTED) {
    251       L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
    252     }
    253 
    254     return;
    255   }
    256 
    257   // for INTR we go directly to config state
    258   p_hcon->conn_state = HID_CONN_STATE_CONFIG;
    259   p_hcon->intr_cid = cid;
    260 
    261   L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
    262   L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
    263 }
    264 
    265 /*******************************************************************************
    266  *
    267  * Function         hidd_l2cif_connect_cfm
    268  *
    269  * Description      Handles L2CAP connection response (we act as client)
    270  *
    271  * Returns          void
    272  *
    273  ******************************************************************************/
    274 static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result) {
    275   tHID_DEV_DEV_CTB* p_dev = &hd_cb.device;
    276   tHID_CONN* p_hcon = &hd_cb.device.conn;
    277 
    278   HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result);
    279 
    280   if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
    281     HIDD_TRACE_WARNING("%s: unknown cid", __func__);
    282     return;
    283   }
    284 
    285   if (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) ||
    286       ((cid == p_hcon->ctrl_cid) &&
    287        (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL)) ||
    288       ((cid == p_hcon->intr_cid) &&
    289        (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR))) {
    290     HIDD_TRACE_WARNING("%s: unexpected", __func__);
    291     return;
    292   }
    293 
    294   if (result != L2CAP_CONN_OK) {
    295     HIDD_TRACE_WARNING("%s: connection failed, now disconnect", __func__);
    296 
    297     if (cid == p_hcon->ctrl_cid)
    298       p_hcon->ctrl_cid = 0;
    299     else
    300       p_hcon->intr_cid = 0;
    301 
    302     hidd_conn_disconnect();
    303 
    304     hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
    305                    HID_L2CAP_CONN_FAIL | (uint32_t)result, NULL);
    306     return;
    307   }
    308 
    309   /* CTRL connect conf */
    310   if (cid == p_hcon->ctrl_cid) {
    311     p_hcon->conn_state = HID_CONN_STATE_SECURITY;
    312     p_hcon->disc_reason =
    313         HID_L2CAP_CONN_FAIL; /* in case disconnected before sec completed */
    314 
    315     btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, TRUE,
    316                               BTM_SEC_PROTO_HID, HIDD_SEC_CHN,
    317                               &hidd_sec_check_complete_orig, p_dev);
    318   } else {
    319     p_hcon->conn_state = HID_CONN_STATE_CONFIG;
    320     L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
    321   }
    322 
    323   return;
    324 }
    325 
    326 /*******************************************************************************
    327  *
    328  * Function         hidd_l2cif_config_ind
    329  *
    330  * Description      Handles incoming L2CAP configuration request
    331  *
    332  * Returns          void
    333  *
    334  ******************************************************************************/
    335 static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
    336   tHID_CONN* p_hcon;
    337 
    338   HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
    339 
    340   p_hcon = &hd_cb.device.conn;
    341 
    342   if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
    343     HIDD_TRACE_WARNING("%s: unknown cid", __func__);
    344     return;
    345   }
    346 
    347   if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_DEV_MTU_SIZE))
    348     p_hcon->rem_mtu_size = HID_DEV_MTU_SIZE;
    349   else
    350     p_hcon->rem_mtu_size = p_cfg->mtu;
    351 
    352   // accept without changes
    353   p_cfg->flush_to_present = FALSE;
    354   p_cfg->mtu_present = FALSE;
    355   p_cfg->result = L2CAP_CFG_OK;
    356 
    357   if (cid == p_hcon->intr_cid && hd_cb.use_in_qos && !p_cfg->qos_present) {
    358     p_cfg->qos_present = TRUE;
    359     memcpy(&p_cfg->qos, &hd_cb.in_qos, sizeof(FLOW_SPEC));
    360   }
    361 
    362   L2CA_ConfigRsp(cid, p_cfg);
    363 
    364   // update flags
    365   if (cid == p_hcon->ctrl_cid) {
    366     p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
    367 
    368     if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
    369         (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) {
    370       p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
    371       if ((p_hcon->intr_cid =
    372                L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
    373         hidd_conn_disconnect();
    374         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
    375 
    376         HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR",
    377                            __func__);
    378         hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
    379                        HID_ERR_L2CAP_FAILED, NULL);
    380         return;
    381       } else {
    382         p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
    383       }
    384     }
    385   } else {
    386     p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
    387   }
    388 
    389   hidd_check_config_done();
    390 }
    391 
    392 /*******************************************************************************
    393  *
    394  * Function         hidd_l2cif_config_cfm
    395  *
    396  * Description      Handles incoming L2CAP configuration response
    397  *
    398  * Returns          void
    399  *
    400  ******************************************************************************/
    401 static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
    402   tHID_CONN* p_hcon;
    403   uint32_t reason;
    404 
    405   HIDD_TRACE_EVENT("%s: cid=%04x pcfg->result=%d", __func__, cid,
    406                    p_cfg->result);
    407 
    408   p_hcon = &hd_cb.device.conn;
    409 
    410   if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
    411     HIDD_TRACE_WARNING("%s: unknown cid", __func__);
    412     return;
    413   }
    414 
    415   if (p_hcon->intr_cid == cid &&
    416       p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS && p_cfg->qos_present) {
    417     tL2CAP_CFG_INFO new_qos;
    418 
    419     // QoS parameters not accepted for intr, try again with host proposal
    420 
    421     memcpy(&new_qos, &hd_cb.l2cap_intr_cfg, sizeof(new_qos));
    422     memcpy(&new_qos.qos, &p_cfg->qos, sizeof(FLOW_SPEC));
    423     new_qos.qos_present = TRUE;
    424 
    425     HIDD_TRACE_WARNING("%s: config failed, retry", __func__);
    426 
    427     L2CA_ConfigReq(cid, &new_qos);
    428     return;
    429   } else if (p_hcon->intr_cid == cid &&
    430              p_cfg->result == L2CAP_CFG_UNKNOWN_OPTIONS) {
    431     // QoS not understood by remote device, try configuring without QoS
    432 
    433     HIDD_TRACE_WARNING("%s: config failed, retry without QoS", __func__);
    434 
    435     L2CA_ConfigReq(cid, &hd_cb.l2cap_cfg);
    436     return;
    437   } else if (p_cfg->result != L2CAP_CFG_OK) {
    438     HIDD_TRACE_WARNING("%s: config failed, disconnecting", __func__);
    439 
    440     hidd_conn_disconnect();
    441     reason = HID_L2CAP_CFG_FAIL | (uint32_t)p_cfg->result;
    442 
    443     hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, reason, NULL);
    444     return;
    445   }
    446 
    447   // update flags
    448   if (cid == p_hcon->ctrl_cid) {
    449     p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
    450 
    451     if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
    452         (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) {
    453       p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
    454       if ((p_hcon->intr_cid =
    455                L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
    456         hidd_conn_disconnect();
    457         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
    458 
    459         HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR",
    460                            __func__);
    461         hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
    462                        HID_ERR_L2CAP_FAILED, NULL);
    463         return;
    464       } else {
    465         p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
    466       }
    467     }
    468   } else {
    469     p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
    470   }
    471 
    472   hidd_check_config_done();
    473 }
    474 
    475 /*******************************************************************************
    476  *
    477  * Function         hidd_l2cif_disconnect_ind
    478  *
    479  * Description      Handler incoming L2CAP disconnection request
    480  *
    481  * Returns          void
    482  *
    483  ******************************************************************************/
    484 static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed) {
    485   tHID_CONN* p_hcon;
    486 
    487   HIDD_TRACE_EVENT("%s: cid=%04x ack_needed=%d", __func__, cid, ack_needed);
    488 
    489   p_hcon = &hd_cb.device.conn;
    490 
    491   if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
    492       (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
    493     HIDD_TRACE_WARNING("%s: unknown cid", __func__);
    494     return;
    495   }
    496 
    497   if (ack_needed) L2CA_DisconnectRsp(cid);
    498 
    499   p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
    500 
    501   if (cid == p_hcon->ctrl_cid)
    502     p_hcon->ctrl_cid = 0;
    503   else
    504     p_hcon->intr_cid = 0;
    505 
    506   if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
    507     HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
    508 
    509     // clean any outstanding data on intr
    510     if (hd_cb.pending_data) {
    511       osi_free(hd_cb.pending_data);
    512       hd_cb.pending_data = NULL;
    513     }
    514 
    515     hd_cb.device.state = HIDD_DEV_NO_CONN;
    516     p_hcon->conn_state = HID_CONN_STATE_UNUSED;
    517 
    518     hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, p_hcon->disc_reason,
    519                    NULL);
    520   }
    521 }
    522 
    523 /*******************************************************************************
    524  *
    525  * Function         hidd_l2cif_disconnect_cfm
    526  *
    527  * Description      Handles L2CAP disconection response
    528  *
    529  * Returns          void
    530  *
    531  ******************************************************************************/
    532 static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result) {
    533   tHID_CONN* p_hcon;
    534 
    535   HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result);
    536 
    537   p_hcon = &hd_cb.device.conn;
    538 
    539   if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
    540       (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
    541     HIDD_TRACE_WARNING("%s: unknown cid", __func__);
    542     return;
    543   }
    544 
    545   if (cid == p_hcon->ctrl_cid) {
    546     p_hcon->ctrl_cid = 0;
    547   } else {
    548     p_hcon->intr_cid = 0;
    549 
    550     // now disconnect CTRL
    551     L2CA_DisconnectReq(p_hcon->ctrl_cid);
    552   }
    553 
    554   if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
    555     HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
    556 
    557     hd_cb.device.state = HIDD_DEV_NO_CONN;
    558     p_hcon->conn_state = HID_CONN_STATE_UNUSED;
    559 
    560     if (hd_cb.pending_vc_unplug) {
    561       hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_VC_UNPLUG,
    562                      p_hcon->disc_reason, NULL);
    563       hd_cb.pending_vc_unplug = FALSE;
    564     } else {
    565       hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
    566                      p_hcon->disc_reason, NULL);
    567     }
    568   }
    569 }
    570 
    571 /*******************************************************************************
    572  *
    573  * Function         hidd_l2cif_cong_ind
    574  *
    575  * Description      Handles L2CAP congestion status event
    576  *
    577  * Returns          void
    578  *
    579  ******************************************************************************/
    580 static void hidd_l2cif_cong_ind(uint16_t cid, bool congested) {
    581   tHID_CONN* p_hcon;
    582 
    583   HIDD_TRACE_EVENT("%s: cid=%04x congested=%d", __func__, cid, congested);
    584 
    585   p_hcon = &hd_cb.device.conn;
    586 
    587   if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
    588       (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
    589     HIDD_TRACE_WARNING("%s: unknown cid", __func__);
    590     return;
    591   }
    592 
    593   if (congested) {
    594     p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
    595   } else {
    596     p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
    597   }
    598 }
    599 
    600 /*******************************************************************************
    601  *
    602  * Function         hidd_l2cif_data_ind
    603  *
    604  * Description      Handler incoming data on L2CAP channel
    605  *
    606  * Returns          void
    607  *
    608  ******************************************************************************/
    609 static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg) {
    610   tHID_CONN* p_hcon;
    611   uint8_t* p_data = (uint8_t*)(p_msg + 1) + p_msg->offset;
    612   uint8_t msg_type, param;
    613   bool err = FALSE;
    614 
    615   HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
    616 
    617   p_hcon = &hd_cb.device.conn;
    618 
    619   if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
    620       (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
    621     HIDD_TRACE_WARNING("%s: unknown cid", __func__);
    622     osi_free(p_msg);
    623     return;
    624   }
    625 
    626   msg_type = HID_GET_TRANS_FROM_HDR(*p_data);
    627   param = HID_GET_PARAM_FROM_HDR(*p_data);
    628 
    629   if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
    630     // skip HID header
    631     p_msg->offset++;
    632     p_msg->len--;
    633 
    634     hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_INTR_DATA, 0, p_msg);
    635     return;
    636   }
    637 
    638   switch (msg_type) {
    639     case HID_TRANS_GET_REPORT:
    640       // at this stage we don't know if Report Id shall be included in request
    641       // so we pass complete packet in callback and let other code analyze this
    642       hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_GET_REPORT,
    643                      !!(param & HID_PAR_GET_REP_BUFSIZE_FOLLOWS), p_msg);
    644       break;
    645 
    646     case HID_TRANS_SET_REPORT:
    647       // as above
    648       hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_REPORT, 0, p_msg);
    649       break;
    650 
    651     case HID_TRANS_GET_IDLE:
    652       hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA,
    653                           HID_PAR_REP_TYPE_OTHER, hd_cb.device.idle_time, 0,
    654                           NULL);
    655       osi_free(p_msg);
    656       break;
    657 
    658     case HID_TRANS_SET_IDLE:
    659       if (p_msg->len != 2) {
    660         HIDD_TRACE_ERROR("%s: invalid len (%d) set idle request received",
    661                          __func__, p_msg->len);
    662         err = TRUE;
    663       } else {
    664         hd_cb.device.idle_time = p_data[1];
    665         HIDD_TRACE_DEBUG("%s: idle_time = %d", __func__,
    666                          hd_cb.device.idle_time);
    667         if (hd_cb.device.idle_time) {
    668           HIDD_TRACE_WARNING(
    669               "%s: idle_time of %d ms not supported by HID Device", __func__,
    670               (hd_cb.device.idle_time * 4));
    671           err = TRUE;
    672         }
    673       }
    674       if (!err) {
    675         hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
    676                             HID_PAR_HANDSHAKE_RSP_SUCCESS, 0, 0, NULL);
    677       } else {
    678         hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
    679                             HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM, 0, 0,
    680                             NULL);
    681       }
    682       osi_free(p_msg);
    683       break;
    684 
    685     case HID_TRANS_GET_PROTOCOL:
    686       hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA,
    687                           HID_PAR_REP_TYPE_OTHER, !hd_cb.device.boot_mode, 0,
    688                           NULL);
    689       osi_free(p_msg);
    690       break;
    691 
    692     case HID_TRANS_SET_PROTOCOL:
    693       hd_cb.device.boot_mode = !(param & HID_PAR_PROTOCOL_MASK);
    694       hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_PROTOCOL,
    695                      param & HID_PAR_PROTOCOL_MASK, NULL);
    696       hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_SUCCESS,
    697                           0, 0, NULL);
    698       osi_free(p_msg);
    699       break;
    700 
    701     case HID_TRANS_CONTROL:
    702       switch (param) {
    703         case HID_PAR_CONTROL_SUSPEND:
    704           hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SUSPEND, 0, NULL);
    705           break;
    706 
    707         case HID_PAR_CONTROL_EXIT_SUSPEND:
    708           hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_EXIT_SUSPEND, 0,
    709                          NULL);
    710           break;
    711 
    712         case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
    713           hidd_conn_disconnect();
    714 
    715           // set flag so we can notify properly when disconnected
    716           hd_cb.pending_vc_unplug = TRUE;
    717           break;
    718       }
    719 
    720       osi_free(p_msg);
    721       break;
    722 
    723     case HID_TRANS_DATA:
    724     default:
    725       HIDD_TRACE_WARNING("%s: got unsupported msg (%d)", __func__, msg_type);
    726       hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
    727                           HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ, 0, 0,
    728                           NULL);
    729       osi_free(p_msg);
    730       break;
    731   }
    732 }
    733 
    734 /*******************************************************************************
    735  *
    736  * Function         hidd_conn_reg
    737  *
    738  * Description      Registers L2CAP channels
    739  *
    740  * Returns          void
    741  *
    742  ******************************************************************************/
    743 tHID_STATUS hidd_conn_reg(void) {
    744   HIDD_TRACE_API("%s", __func__);
    745 
    746   memset(&hd_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
    747 
    748   hd_cb.l2cap_cfg.mtu_present = TRUE;
    749   hd_cb.l2cap_cfg.mtu = HID_DEV_MTU_SIZE;
    750   hd_cb.l2cap_cfg.flush_to_present = TRUE;
    751   hd_cb.l2cap_cfg.flush_to = HID_DEV_FLUSH_TO;
    752 
    753   memset(&hd_cb.l2cap_intr_cfg, 0, sizeof(tL2CAP_CFG_INFO));
    754   hd_cb.l2cap_intr_cfg.mtu_present = TRUE;
    755   hd_cb.l2cap_intr_cfg.mtu = HID_DEV_MTU_SIZE;
    756   hd_cb.l2cap_intr_cfg.flush_to_present = TRUE;
    757   hd_cb.l2cap_intr_cfg.flush_to = HID_DEV_FLUSH_TO;
    758 
    759   if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&dev_reg_info)) {
    760     HIDD_TRACE_ERROR("HID Control (device) registration failed");
    761     return (HID_ERR_L2CAP_FAILED);
    762   }
    763 
    764   if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&dev_reg_info)) {
    765     L2CA_Deregister(HID_PSM_CONTROL);
    766     HIDD_TRACE_ERROR("HID Interrupt (device) registration failed");
    767     return (HID_ERR_L2CAP_FAILED);
    768   }
    769 
    770   return (HID_SUCCESS);
    771 }
    772 
    773 /*******************************************************************************
    774  *
    775  * Function         hidd_conn_dereg
    776  *
    777  * Description      Deregisters L2CAP channels
    778  *
    779  * Returns          void
    780  *
    781  ******************************************************************************/
    782 void hidd_conn_dereg(void) {
    783   HIDD_TRACE_API("%s", __func__);
    784 
    785   L2CA_Deregister(HID_PSM_CONTROL);
    786   L2CA_Deregister(HID_PSM_INTERRUPT);
    787 }
    788 
    789 /*******************************************************************************
    790  *
    791  * Function         hidd_conn_initiate
    792  *
    793  * Description      Initiates HID connection to plugged device
    794  *
    795  * Returns          HID_SUCCESS
    796  *
    797  ******************************************************************************/
    798 tHID_STATUS hidd_conn_initiate(void) {
    799   tHID_DEV_DEV_CTB* p_dev = &hd_cb.device;
    800 
    801   HIDD_TRACE_API("%s", __func__);
    802 
    803   if (!p_dev->in_use) {
    804     HIDD_TRACE_WARNING("%s: no virtual cable established", __func__);
    805     return (HID_ERR_NOT_REGISTERED);
    806   }
    807 
    808   if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) {
    809     HIDD_TRACE_WARNING("%s: connection already in progress", __func__);
    810     return (HID_ERR_CONN_IN_PROCESS);
    811   }
    812 
    813   p_dev->conn.ctrl_cid = 0;
    814   p_dev->conn.intr_cid = 0;
    815   p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL;
    816 
    817   p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
    818 
    819   BTM_SetOutService(p_dev->addr, BTM_SEC_SERVICE_HIDD_SEC_CTRL, HIDD_SEC_CHN);
    820 
    821   /* Check if L2CAP started the connection process */
    822   if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq(HID_PSM_CONTROL, p_dev->addr)) ==
    823       0) {
    824     HIDD_TRACE_WARNING("%s: could not start L2CAP connection", __func__);
    825     hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED,
    826                    NULL);
    827   } else {
    828     p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
    829   }
    830 
    831   return (HID_SUCCESS);
    832 }
    833 
    834 /*******************************************************************************
    835  *
    836  * Function         hidd_conn_disconnect
    837  *
    838  * Description      Disconnects existing HID connection
    839  *
    840  * Returns          HID_SUCCESS
    841  *
    842  ******************************************************************************/
    843 tHID_STATUS hidd_conn_disconnect(void) {
    844   tHID_CONN* p_hcon;
    845 
    846   HIDD_TRACE_API("%s", __func__);
    847 
    848   // clean any outstanding data on intr
    849   if (hd_cb.pending_data) {
    850     osi_free(hd_cb.pending_data);
    851     hd_cb.pending_data = NULL;
    852   }
    853 
    854   p_hcon = &hd_cb.device.conn;
    855 
    856   if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
    857     p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
    858 
    859     /* Set l2cap idle timeout to 0 (so ACL link is disconnected
    860      * immediately after last channel is closed) */
    861     L2CA_SetIdleTimeoutByBdAddr(hd_cb.device.addr, 0, BT_TRANSPORT_BR_EDR);
    862 
    863     if (p_hcon->intr_cid) {
    864       L2CA_DisconnectReq(p_hcon->intr_cid);
    865     } else if (p_hcon->ctrl_cid) {
    866       L2CA_DisconnectReq(p_hcon->ctrl_cid);
    867     }
    868   } else {
    869     HIDD_TRACE_WARNING("%s: already disconnected", __func__);
    870     p_hcon->conn_state = HID_CONN_STATE_UNUSED;
    871   }
    872 
    873   return (HID_SUCCESS);
    874 }
    875 
    876 /*******************************************************************************
    877  *
    878  * Function         hidd_conn_send_data
    879  *
    880  * Description      Sends data to host
    881  *
    882  * Returns          tHID_STATUS
    883  *
    884  ******************************************************************************/
    885 tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type,
    886                                 uint8_t param, uint8_t data, uint16_t len,
    887                                 uint8_t* p_data) {
    888   tHID_CONN* p_hcon;
    889   BT_HDR* p_buf;
    890   uint8_t* p_out;
    891   uint16_t cid;
    892   uint16_t buf_size;
    893 
    894   HIDD_TRACE_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__,
    895                      channel, msg_type, len);
    896 
    897   p_hcon = &hd_cb.device.conn;
    898 
    899   if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
    900     return HID_ERR_CONGESTED;
    901   }
    902 
    903   switch (msg_type) {
    904     case HID_TRANS_HANDSHAKE:
    905     case HID_TRANS_CONTROL:
    906       cid = p_hcon->ctrl_cid;
    907       buf_size = HID_CONTROL_BUF_SIZE;
    908       break;
    909     case HID_TRANS_DATA:
    910       if (channel == HID_CHANNEL_CTRL) {
    911         cid = p_hcon->ctrl_cid;
    912         buf_size = HID_CONTROL_BUF_SIZE;
    913       } else {
    914         cid = p_hcon->intr_cid;
    915         buf_size = HID_INTERRUPT_BUF_SIZE;
    916       }
    917       break;
    918     default:
    919       return (HID_ERR_INVALID_PARAM);
    920   }
    921 
    922   p_buf = (BT_HDR*)osi_malloc(buf_size);
    923   if (p_buf == NULL) return (HID_ERR_NO_RESOURCES);
    924 
    925   p_buf->offset = L2CAP_MIN_OFFSET;
    926 
    927   p_out = (uint8_t*)(p_buf + 1) + p_buf->offset;
    928 
    929   *p_out = HID_BUILD_HDR(msg_type, param);
    930   p_out++;
    931 
    932   p_buf->len = 1;  // start with header only
    933 
    934   // add report id prefix only if non-zero (which is reserved)
    935   if (msg_type == HID_TRANS_DATA && (data || param == HID_PAR_REP_TYPE_OTHER)) {
    936     *p_out = data;  // report_id
    937     p_out++;
    938     p_buf->len++;
    939   }
    940 
    941   if (len > 0 && p_data != NULL) {
    942     memcpy(p_out, p_data, len);
    943     p_buf->len += len;
    944   }
    945 
    946   // check if connected
    947   if (hd_cb.device.state != HIDD_DEV_CONNECTED) {
    948     // for DATA on intr we hold transfer and try to reconnect
    949     if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
    950       // drop previous data, we do not queue it for now
    951       if (hd_cb.pending_data) {
    952         osi_free(hd_cb.pending_data);
    953       }
    954 
    955       hd_cb.pending_data = p_buf;
    956 
    957       if (hd_cb.device.conn.conn_state == HID_CONN_STATE_UNUSED) {
    958         hidd_conn_initiate();
    959       }
    960 
    961       return HID_SUCCESS;
    962     }
    963 
    964     return HID_ERR_NO_CONNECTION;
    965   }
    966 
    967 #ifdef REPORT_TRANSFER_TIMESTAMP
    968   if (report_transfer) {
    969     HIDD_TRACE_ERROR("%s: report sent", __func__);
    970   }
    971 #endif
    972   HIDD_TRACE_VERBOSE("%s: report sent", __func__);
    973 
    974   if (!L2CA_DataWrite(cid, p_buf)) return (HID_ERR_CONGESTED);
    975 
    976   return (HID_SUCCESS);
    977 }
    978