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