• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright 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 <base/functional/callback.h>
26 #include <base/logging.h>
27 #include <base/strings/stringprintf.h>
28 #include <frameworks/proto_logging/stats/enums/bluetooth/enums.pb.h>
29 #include <string.h>
30 
31 #include "bta/include/bta_api.h"
32 #include "hiddefs.h"
33 #include "hidh_api.h"
34 #include "hidh_int.h"
35 #include "l2c_api.h"
36 #include "l2cdefs.h"
37 #include "osi/include/allocator.h"
38 #include "osi/include/log.h"
39 #include "osi/include/osi.h"
40 #include "stack/btm/btm_sec.h"
41 #include "stack/include/acl_api.h"
42 #include "stack/include/bt_hdr.h"
43 #include "stack/include/btm_api.h"  // BTM_LogHistory
44 #include "stack/include/stack_metrics_logging.h"
45 #include "types/raw_address.h"
46 
47 namespace {
48 constexpr char kBtmLogTag[] = "HIDH";
49 constexpr uint8_t kHID_HOST_MAX_DEVICES = HID_HOST_MAX_DEVICES;
50 }
51 
52 static uint8_t find_conn_by_cid(uint16_t cid);
53 static void hidh_conn_retry(uint8_t dhandle);
54 
55 /******************************************************************************/
56 /*            L O C A L    F U N C T I O N     P R O T O T Y P E S            */
57 /******************************************************************************/
58 static void hidh_l2cif_connect_ind(const RawAddress& bd_addr,
59                                    uint16_t l2cap_cid, uint16_t psm,
60                                    uint8_t l2cap_id);
61 static void hidh_l2cif_connect_cfm(uint16_t l2cap_cid, uint16_t result);
62 static void hidh_l2cif_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
63 static void hidh_l2cif_config_cfm(uint16_t l2cap_cid, uint16_t result,
64                                   tL2CAP_CFG_INFO* p_cfg);
65 static void hidh_l2cif_disconnect_ind(uint16_t l2cap_cid, bool ack_needed);
66 static void hidh_l2cif_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg);
67 static void hidh_l2cif_disconnect(uint16_t l2cap_cid);
68 static void hidh_l2cif_cong_ind(uint16_t l2cap_cid, bool congested);
69 static void hidh_on_l2cap_error(uint16_t l2cap_cid, uint16_t result);
70 
71 static const tL2CAP_APPL_INFO hst_reg_info = {
72     .pL2CA_ConnectInd_Cb = hidh_l2cif_connect_ind,
73     .pL2CA_ConnectCfm_Cb = hidh_l2cif_connect_cfm,
74     .pL2CA_ConfigInd_Cb = hidh_l2cif_config_ind,
75     .pL2CA_ConfigCfm_Cb = hidh_l2cif_config_cfm,
76     .pL2CA_DisconnectInd_Cb = hidh_l2cif_disconnect_ind,
77     .pL2CA_DataInd_Cb = hidh_l2cif_data_ind,
78     .pL2CA_CongestionStatus_Cb = hidh_l2cif_cong_ind,
79     .pL2CA_TxComplete_Cb = nullptr,
80     .pL2CA_Error_Cb = hidh_on_l2cap_error,
81     .pL2CA_CreditBasedConnectInd_Cb = nullptr,
82     .pL2CA_CreditBasedConnectCfm_Cb = nullptr,
83     .pL2CA_CreditBasedReconfigCompleted_Cb = nullptr,
84     .pL2CA_CreditBasedCollisionInd_Cb = nullptr,
85 };
86 static void hidh_try_repage(uint8_t dhandle);
87 
88 /*******************************************************************************
89  *
90  * Function         hidh_l2cif_reg
91  *
92  * Description      This function initializes the SDP unit.
93  *
94  * Returns          void
95  *
96  ******************************************************************************/
hidh_conn_reg(void)97 tHID_STATUS hidh_conn_reg(void) {
98   int xx;
99 
100   /* Initialize the L2CAP configuration. We only care about MTU and flush */
101   memset(&hh_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
102 
103   hh_cb.l2cap_cfg.mtu_present = true;
104   hh_cb.l2cap_cfg.mtu = HID_HOST_MTU;
105 
106   /* Now, register with L2CAP */
107   if (!L2CA_Register2(HID_PSM_CONTROL, hst_reg_info, false /* enable_snoop */,
108                       nullptr, HID_HOST_MTU, 0,
109                       BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) {
110     HIDH_TRACE_ERROR("HID-Host Control Registration failed");
111     log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
112                             HIDH_ERR_L2CAP_FAILED_AT_REGISTER_CONTROL,
113                         1);
114     return (HID_ERR_L2CAP_FAILED);
115   }
116   if (!L2CA_Register2(HID_PSM_INTERRUPT, hst_reg_info, false /* enable_snoop */,
117                       nullptr, HID_HOST_MTU, 0,
118                       BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT)) {
119     L2CA_Deregister(HID_PSM_CONTROL);
120     HIDH_TRACE_ERROR("HID-Host Interrupt Registration failed");
121     log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
122                             HIDH_ERR_L2CAP_FAILED_AT_REGISTER_INTERRUPT,
123                         1);
124     return (HID_ERR_L2CAP_FAILED);
125   }
126 
127   for (xx = 0; xx < kHID_HOST_MAX_DEVICES; xx++) {
128     hh_cb.devices[xx].in_use = false;
129     hh_cb.devices[xx].conn.conn_state = HID_CONN_STATE_UNUSED;
130   }
131 
132   return (HID_SUCCESS);
133 }
134 
135 /*******************************************************************************
136  *
137  * Function         hidh_conn_disconnect
138  *
139  * Description      This function disconnects a connection.
140  *
141  * Returns          true if disconnect started, false if already disconnected
142  *
143  ******************************************************************************/
hidh_conn_disconnect(uint8_t dhandle)144 tHID_STATUS hidh_conn_disconnect(uint8_t dhandle) {
145   tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn;
146 
147   if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
148     p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
149 
150     /* Set l2cap idle timeout to 0 (so ACL link is disconnected
151      * immediately after last channel is closed) */
152     L2CA_SetIdleTimeoutByBdAddr(hh_cb.devices[dhandle].addr, 0,
153                                 BT_TRANSPORT_BR_EDR);
154     /* Disconnect both interrupt and control channels */
155     if (p_hcon->intr_cid)
156       hidh_l2cif_disconnect(p_hcon->intr_cid);
157     else if (p_hcon->ctrl_cid)
158       hidh_l2cif_disconnect(p_hcon->ctrl_cid);
159 
160     BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Disconnecting",
161                    "local initiated");
162   } else {
163     p_hcon->conn_state = HID_CONN_STATE_UNUSED;
164   }
165   return HID_SUCCESS;
166 }
167 
168 /*******************************************************************************
169  *
170  * Function         hidh_l2cif_connect_ind
171  *
172  * Description      This function handles an inbound connection indication
173  *                  from L2CAP. This is the case where we are acting as a
174  *                  server.
175  *
176  * Returns          void
177  *
178  ******************************************************************************/
hidh_l2cif_connect_ind(const RawAddress & bd_addr,uint16_t l2cap_cid,uint16_t psm,uint8_t l2cap_id)179 static void hidh_l2cif_connect_ind(const RawAddress& bd_addr,
180                                    uint16_t l2cap_cid, uint16_t psm,
181                                    uint8_t l2cap_id) {
182   bool bAccept = true;
183   uint8_t i = kHID_HOST_MAX_DEVICES;
184 
185   HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP conn ind, PSM: 0x%04x  CID 0x%x", psm,
186                    l2cap_cid);
187 
188   /* always add incoming connection device into HID database by default */
189   if (HID_HostAddDev(bd_addr, HID_SEC_REQUIRED, &i) != HID_SUCCESS) {
190     L2CA_DisconnectReq(l2cap_cid);
191     return;
192   }
193 
194   tHID_CONN* p_hcon = &hh_cb.devices[i].conn;
195 
196   BTM_LogHistory(
197       kBtmLogTag, hh_cb.devices[i].addr, "Connect request",
198       base::StringPrintf("%s state:%s",
199                          (psm == HID_PSM_CONTROL) ? "control" : "interrupt",
200                          hid_conn::state_text(p_hcon->conn_state).c_str()));
201 
202   /* Check we are in the correct state for this */
203   if (psm == HID_PSM_INTERRUPT) {
204     if (p_hcon->ctrl_cid == 0) {
205       HIDH_TRACE_WARNING(
206           "HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel");
207       bAccept = false;
208     }
209     if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) {
210       HIDH_TRACE_WARNING("HID-Host Rcvd INTR L2CAP conn ind, wrong state: %d",
211                          p_hcon->conn_state);
212       bAccept = false;
213     }
214   } else /* CTRL channel */
215   {
216 #if (HID_HOST_ACPT_NEW_CONN == TRUE)
217     p_hcon->ctrl_cid = p_hcon->intr_cid = 0;
218     p_hcon->conn_state = HID_CONN_STATE_UNUSED;
219 #else
220     if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) {
221       HIDH_TRACE_WARNING("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: %d",
222                          p_hcon->conn_state);
223       bAccept = false;
224     }
225 #endif
226   }
227 
228   if (!bAccept) {
229     L2CA_DisconnectReq(l2cap_cid);
230     return;
231   }
232 
233   if (psm == HID_PSM_CONTROL) {
234     p_hcon->conn_flags = 0;
235     p_hcon->ctrl_cid = l2cap_cid;
236     p_hcon->disc_reason = HID_SUCCESS; /* Authentication passed. Reset
237                                               disc_reason (from
238                                               HID_ERR_AUTH_FAILED) */
239     p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
240     BTM_LogHistory(kBtmLogTag, hh_cb.devices[i].addr, "Connecting",
241                    "waiting for interrupt channel");
242     return;
243   }
244 
245   /* Transition to the next appropriate state, configuration */
246   p_hcon->conn_state = HID_CONN_STATE_CONFIG;
247   p_hcon->intr_cid = l2cap_cid;
248 
249   HIDH_TRACE_EVENT(
250       "HID-Host Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x  CID 0x%x",
251       psm, l2cap_cid);
252 }
253 
hidh_process_repage_timer_timeout(void * data)254 static void hidh_process_repage_timer_timeout(void* data) {
255   uint8_t dhandle = PTR_TO_UINT(data);
256   hidh_try_repage(dhandle);
257 }
258 
259 /*******************************************************************************
260  *
261  * Function         hidh_try_repage
262  *
263  * Description      This function processes timeout (to page device).
264  *
265  * Returns          void
266  *
267  ******************************************************************************/
hidh_try_repage(uint8_t dhandle)268 static void hidh_try_repage(uint8_t dhandle) {
269   tHID_HOST_DEV_CTB* device;
270 
271   hidh_conn_initiate(dhandle);
272 
273   device = &hh_cb.devices[dhandle];
274   device->conn_tries++;
275 
276   hh_cb.callback(dhandle, device->addr, HID_HDEV_EVT_RETRYING,
277                  device->conn_tries, NULL);
278 }
279 
hidh_on_l2cap_error(uint16_t l2cap_cid,uint16_t result)280 static void hidh_on_l2cap_error(uint16_t l2cap_cid, uint16_t result) {
281   auto dhandle = find_conn_by_cid(l2cap_cid);
282   if (dhandle == kHID_HOST_MAX_DEVICES) {
283     LOG_WARN("Received error for unknown device cid:0x%04x reason:%s",
284              l2cap_cid,
285              hci_reason_code_text(to_hci_reason_code(result)).c_str());
286     return;
287   }
288 
289   hidh_conn_disconnect(dhandle);
290 
291   if (result != L2CAP_CFG_FAILED_NO_REASON) {
292 #if (HID_HOST_MAX_CONN_RETRY > 0)
293     if ((hh_cb.devices[dhandle].conn_tries <= HID_HOST_MAX_CONN_RETRY) &&
294         (result == HCI_ERR_CONNECTION_TOUT || result == HCI_ERR_UNSPECIFIED ||
295          result == HCI_ERR_PAGE_TIMEOUT)) {
296       hidh_conn_retry(dhandle);
297     } else
298 #endif
299     {
300       uint32_t reason = HID_L2CAP_CONN_FAIL | (uint32_t)result;
301       hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
302                      reason, NULL);
303     }
304   } else {
305     uint32_t reason = HID_L2CAP_CFG_FAIL | (uint32_t)result;
306     hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
307                    reason, NULL);
308   }
309 }
310 
311 /*******************************************************************************
312  *
313  * Function         hidh_l2cif_connect_cfm
314  *
315  * Description      This function handles the connect confirm events
316  *                  from L2CAP. This is the case when we are acting as a
317  *                  client and have sent a connect request.
318  *
319  * Returns          void
320  *
321  ******************************************************************************/
hidh_l2cif_connect_cfm(uint16_t l2cap_cid,uint16_t result)322 static void hidh_l2cif_connect_cfm(uint16_t l2cap_cid, uint16_t result) {
323   uint8_t dhandle;
324   tHID_CONN* p_hcon = NULL;
325 
326   /* Find CCB based on CID, and verify we are in a state to accept this message
327    */
328   dhandle = find_conn_by_cid(l2cap_cid);
329   if (dhandle < kHID_HOST_MAX_DEVICES) {
330     p_hcon = &hh_cb.devices[dhandle].conn;
331   }
332 
333   if ((p_hcon == NULL) || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG)) ||
334       ((l2cap_cid == p_hcon->ctrl_cid) &&
335        (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL)) ||
336       ((l2cap_cid == p_hcon->intr_cid) &&
337        (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) &&
338        (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING))) {
339     HIDH_TRACE_WARNING("HID-Host Rcvd unexpected conn cnf, CID 0x%x ",
340                        l2cap_cid);
341     return;
342   }
343 
344   if (result != L2CAP_CONN_OK) {
345     // TODO: We need to provide the real HCI status if we want to retry.
346     LOG(ERROR) << __func__ << ": invoked with non OK status";
347     return;
348   }
349   /* receive Control Channel connect confirmation */
350   if (l2cap_cid == p_hcon->ctrl_cid) {
351     /* check security requirement */
352     p_hcon->disc_reason = HID_SUCCESS; /* Authentication passed. Reset
353                                               disc_reason (from
354                                               HID_ERR_AUTH_FAILED) */
355 
356     /* Transition to the next appropriate state, configuration */
357     p_hcon->conn_state = HID_CONN_STATE_CONFIG;
358   } else {
359     p_hcon->conn_state = HID_CONN_STATE_CONFIG;
360   }
361   BTM_LogHistory(
362       kBtmLogTag, hh_cb.devices[dhandle].addr, "Configuring",
363       base::StringPrintf("control:0x%04x interrupt:0x%04x state:%s",
364                          p_hcon->ctrl_cid, p_hcon->intr_cid,
365                          hid_conn::state_text(p_hcon->conn_state).c_str()));
366   return;
367 }
368 
369 /*******************************************************************************
370  *
371  * Function         hidh_l2cif_config_ind
372  *
373  * Description      This function processes the L2CAP configuration indication
374  *                  event.
375  *
376  * Returns          void
377  *
378  ******************************************************************************/
hidh_l2cif_config_ind(uint16_t l2cap_cid,tL2CAP_CFG_INFO * p_cfg)379 static void hidh_l2cif_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
380   uint8_t dhandle;
381   tHID_CONN* p_hcon = NULL;
382 
383   /* Find CCB based on CID */
384   dhandle = find_conn_by_cid(l2cap_cid);
385   if (dhandle < kHID_HOST_MAX_DEVICES) {
386     p_hcon = &hh_cb.devices[dhandle].conn;
387   }
388 
389   if (p_hcon == NULL) {
390     HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x",
391                        l2cap_cid);
392     return;
393   }
394 
395   HIDH_TRACE_EVENT("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
396 
397   /* Remember the remote MTU size */
398   if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_HOST_MTU))
399     p_hcon->rem_mtu_size = HID_HOST_MTU;
400   else
401     p_hcon->rem_mtu_size = p_cfg->mtu;
402 }
403 
404 /*******************************************************************************
405  *
406  * Function         hidh_l2cif_config_cfm
407  *
408  * Description      This function processes the L2CAP configuration confirmation
409  *                  event.
410  *
411  * Returns          void
412  *
413  ******************************************************************************/
hidh_l2cif_config_cfm(uint16_t l2cap_cid,uint16_t initiator,tL2CAP_CFG_INFO * p_cfg)414 static void hidh_l2cif_config_cfm(uint16_t l2cap_cid, uint16_t initiator,
415                                   tL2CAP_CFG_INFO* p_cfg) {
416   hidh_l2cif_config_ind(l2cap_cid, p_cfg);
417 
418   uint8_t dhandle;
419   tHID_CONN* p_hcon = NULL;
420   uint32_t reason;
421 
422   HIDH_TRACE_EVENT("HID-Host Rcvd cfg cfm, CID: 0x%x", l2cap_cid);
423 
424   /* Find CCB based on CID */
425   dhandle = find_conn_by_cid(l2cap_cid);
426   if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
427 
428   if (p_hcon == NULL) {
429     HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x",
430                        l2cap_cid);
431     return;
432   }
433 
434   if (l2cap_cid == p_hcon->ctrl_cid) {
435     if (p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) {
436       /* Connect interrupt channel */
437       p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for
438                                                     CLOSE_EVT: Connection
439                                                     Attempt was made but failed
440                                                     */
441       p_hcon->intr_cid =
442           L2CA_ConnectReq2(HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr,
443                            BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
444       if (p_hcon->intr_cid == 0) {
445         HIDH_TRACE_WARNING("HID-Host INTR Originate failed");
446         reason = HID_L2CAP_REQ_FAIL;
447         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
448         BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Failed");
449         hidh_conn_disconnect(dhandle);
450         hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
451                        reason, NULL);
452         return;
453       } else {
454         /* Transition to the next appropriate state, waiting for connection
455          * confirm on interrupt channel. */
456         p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
457         BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Connecting",
458                        "interrupt channel");
459       }
460     }
461   }
462 
463   /* If all configuration is complete, change state and tell management we are
464    * up */
465   if (p_hcon->conn_state == HID_CONN_STATE_CONFIG) {
466     p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
467     /* Reset disconnect reason to success, as connection successful */
468     p_hcon->disc_reason = HID_SUCCESS;
469 
470     hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
471     hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0,
472                    NULL);
473     BTM_LogHistory(
474         kBtmLogTag, hh_cb.devices[dhandle].addr, "Connected",
475         base::StringPrintf("control:0x%04x interrupt:0x%04x state:%s",
476                            p_hcon->ctrl_cid, p_hcon->intr_cid,
477                            hid_conn::state_text(p_hcon->conn_state).c_str()));
478   }
479 }
480 
481 /*******************************************************************************
482  *
483  * Function         hidh_l2cif_disconnect_ind
484  *
485  * Description      This function handles a disconnect event from L2CAP. If
486  *                  requested to, we ack the disconnect before dropping the CCB
487  *
488  * Returns          void
489  *
490  ******************************************************************************/
hidh_l2cif_disconnect_ind(uint16_t l2cap_cid,bool ack_needed)491 static void hidh_l2cif_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) {
492   uint8_t dhandle;
493   tHID_CONN* p_hcon = NULL;
494   tHCI_REASON disc_res = HCI_SUCCESS;
495   uint16_t hid_close_evt_reason;
496 
497   /* Find CCB based on CID */
498   dhandle = find_conn_by_cid(l2cap_cid);
499   if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
500 
501   if (p_hcon == NULL) {
502     HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x",
503                        l2cap_cid);
504     return;
505   }
506 
507   HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
508 
509   p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
510   BTM_LogHistory(
511       kBtmLogTag, hh_cb.devices[dhandle].addr, "Disconnecting",
512       base::StringPrintf("%s channel", (l2cap_cid == p_hcon->ctrl_cid)
513                                            ? "control"
514                                            : "interrupt"));
515 
516   if (l2cap_cid == p_hcon->ctrl_cid)
517     p_hcon->ctrl_cid = 0;
518   else
519     p_hcon->intr_cid = 0;
520 
521   if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
522     hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
523     p_hcon->conn_state = HID_CONN_STATE_UNUSED;
524 
525     if (!ack_needed) disc_res = btm_get_acl_disc_reason_code();
526 
527 #if (HID_HOST_MAX_CONN_RETRY > 0)
528     if ((disc_res == HCI_ERR_CONNECTION_TOUT ||
529          disc_res == HCI_ERR_UNSPECIFIED) &&
530         (!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) &&
531         (hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE)) {
532       hh_cb.devices[dhandle].conn_tries = 0;
533       uint64_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
534       alarm_set_on_mloop(hh_cb.devices[dhandle].conn.process_repage_timer,
535                          interval_ms, hidh_process_repage_timer_timeout,
536                          UINT_TO_PTR(dhandle));
537       hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
538                      disc_res, NULL);
539     } else
540 #endif
541     {
542       /* Set reason code for HID_HDEV_EVT_CLOSE */
543       hid_close_evt_reason = p_hcon->disc_reason;
544 
545       /* If we got baseband sent HCI_DISCONNECT_COMPLETE_EVT due to security
546        * failure, then set reason to HID_ERR_AUTH_FAILED */
547       if ((disc_res == HCI_ERR_AUTH_FAILURE) ||
548           (disc_res == HCI_ERR_KEY_MISSING) ||
549           (disc_res == HCI_ERR_HOST_REJECT_SECURITY) ||
550           (disc_res == HCI_ERR_PAIRING_NOT_ALLOWED) ||
551           (disc_res == HCI_ERR_UNIT_KEY_USED) ||
552           (disc_res == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
553           (disc_res == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) ||
554           (disc_res == HCI_ERR_REPEATED_ATTEMPTS)) {
555         log_counter_metrics(
556             android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_AUTH_FAILED,
557             1);
558         hid_close_evt_reason = HID_ERR_AUTH_FAILED;
559       }
560 
561       hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
562                      hid_close_evt_reason, NULL);
563     }
564   }
565 }
566 
hidh_l2cif_disconnect(uint16_t l2cap_cid)567 static void hidh_l2cif_disconnect(uint16_t l2cap_cid) {
568   L2CA_DisconnectReq(l2cap_cid);
569 
570   /* Find CCB based on CID */
571   const uint8_t dhandle = find_conn_by_cid(l2cap_cid);
572   if (dhandle == kHID_HOST_MAX_DEVICES) {
573     LOG_WARN("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
574     return;
575   }
576 
577   tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn;
578   if (l2cap_cid == p_hcon->ctrl_cid) {
579     p_hcon->ctrl_cid = 0;
580   } else {
581     p_hcon->intr_cid = 0;
582     if (p_hcon->ctrl_cid) {
583       HIDH_TRACE_EVENT("HID-Host Initiating L2CAP Ctrl disconnection");
584       L2CA_DisconnectReq(p_hcon->ctrl_cid);
585       p_hcon->ctrl_cid = 0;
586     }
587   }
588 
589   if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
590     hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
591     p_hcon->conn_state = HID_CONN_STATE_UNUSED;
592     BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Disconnected");
593     hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
594                    p_hcon->disc_reason, NULL);
595   }
596 }
597 
598 /*******************************************************************************
599  *
600  * Function         hidh_l2cif_cong_ind
601  *
602  * Description      This function handles a congestion status event from L2CAP.
603  *
604  * Returns          void
605  *
606  ******************************************************************************/
hidh_l2cif_cong_ind(uint16_t l2cap_cid,bool congested)607 static void hidh_l2cif_cong_ind(uint16_t l2cap_cid, bool congested) {
608   uint8_t dhandle;
609   tHID_CONN* p_hcon = NULL;
610 
611   /* Find CCB based on CID */
612   dhandle = find_conn_by_cid(l2cap_cid);
613   if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
614 
615   if (p_hcon == NULL) {
616     HIDH_TRACE_WARNING(
617         "HID-Host Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid);
618     return;
619   }
620 
621   HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP congestion status, CID: 0x%x  Cong: %d",
622                    l2cap_cid, congested);
623 
624   if (congested)
625     p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
626   else {
627     p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
628   }
629 }
630 
631 /*******************************************************************************
632  *
633  * Function         hidh_l2cif_data_ind
634  *
635  * Description      This function is called when data is received from L2CAP.
636  *                  if we are the originator of the connection, we are the SDP
637  *                  client, and the received message is queued up for the
638  *                  client.
639  *
640  *                  If we are the destination of the connection, we are the SDP
641  *                  server, so the message is passed to the server processing
642  *                  function.
643  *
644  * Returns          void
645  *
646  ******************************************************************************/
hidh_l2cif_data_ind(uint16_t l2cap_cid,BT_HDR * p_msg)647 static void hidh_l2cif_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) {
648   uint8_t* p_data = (uint8_t*)(p_msg + 1) + p_msg->offset;
649   uint8_t ttype, param, rep_type, evt;
650   uint8_t dhandle;
651   tHID_CONN* p_hcon = NULL;
652 
653   HIDH_TRACE_DEBUG("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x%04x]",
654                    l2cap_cid);
655 
656   /* Find CCB based on CID */
657   dhandle = find_conn_by_cid(l2cap_cid);
658   if (dhandle < kHID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
659 
660   if (p_hcon == NULL) {
661     HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP data, unknown CID: 0x%x",
662                        l2cap_cid);
663     osi_free(p_msg);
664     return;
665   }
666 
667   if (p_msg->len < 1) {
668     HIDH_TRACE_WARNING("Rcvd L2CAP data, invalid length %d, should be >= 1",
669                        p_msg->len);
670     osi_free(p_msg);
671     return;
672   }
673 
674   ttype = HID_GET_TRANS_FROM_HDR(*p_data);
675   param = HID_GET_PARAM_FROM_HDR(*p_data);
676   rep_type = param & HID_PAR_REP_TYPE_MASK;
677   p_data++;
678 
679   /* Get rid of the data type */
680   p_msg->len--;
681   p_msg->offset++;
682 
683   switch (ttype) {
684     case HID_TRANS_HANDSHAKE:
685       hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr,
686                      HID_HDEV_EVT_HANDSHAKE, param, NULL);
687       osi_free(p_msg);
688       break;
689 
690     case HID_TRANS_CONTROL:
691       switch (param) {
692         case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
693           hidh_conn_disconnect(dhandle);
694           /* Device is unplugging from us. Tell USB */
695           hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr,
696                          HID_HDEV_EVT_VC_UNPLUG, 0, NULL);
697           break;
698 
699         default:
700           break;
701       }
702       osi_free(p_msg);
703       break;
704 
705     case HID_TRANS_DATA:
706       evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid)
707                 ? HID_HDEV_EVT_INTR_DATA
708                 : HID_HDEV_EVT_CTRL_DATA;
709       hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type,
710                      p_msg);
711       break;
712 
713     case HID_TRANS_DATAC:
714       evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid)
715                 ? HID_HDEV_EVT_INTR_DATC
716                 : HID_HDEV_EVT_CTRL_DATC;
717       hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type,
718                      p_msg);
719       break;
720 
721     default:
722       osi_free(p_msg);
723       break;
724   }
725 }
726 
727 /*******************************************************************************
728  *
729  * Function         hidh_conn_snd_data
730  *
731  * Description      This function is sends out data.
732  *
733  * Returns          tHID_STATUS
734  *
735  ******************************************************************************/
hidh_conn_snd_data(uint8_t dhandle,uint8_t trans_type,uint8_t param,uint16_t data,uint8_t report_id,BT_HDR * buf)736 tHID_STATUS hidh_conn_snd_data(uint8_t dhandle, uint8_t trans_type,
737                                uint8_t param, uint16_t data, uint8_t report_id,
738                                BT_HDR* buf) {
739   tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn;
740   BT_HDR* p_buf;
741   uint8_t* p_out;
742   uint16_t bytes_copied;
743   bool seg_req = false;
744   uint16_t data_size;
745   uint16_t cid;
746   uint16_t buf_size;
747   uint8_t use_data = 0;
748   bool blank_datc = false;
749 
750   if (!BTM_IsAclConnectionUp(hh_cb.devices[dhandle].addr,
751                              BT_TRANSPORT_BR_EDR)) {
752     osi_free(buf);
753     log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
754                             HIDH_ERR_NO_CONNECTION_AT_SEND_DATA,
755                         1);
756     return HID_ERR_NO_CONNECTION;
757   }
758 
759   if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
760     osi_free(buf);
761     log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
762                             HIDH_ERR_CONGESTED_AT_FLAG_CHECK,
763                         1);
764     return HID_ERR_CONGESTED;
765   }
766 
767   switch (trans_type) {
768     case HID_TRANS_CONTROL:
769     case HID_TRANS_GET_REPORT:
770     case HID_TRANS_SET_REPORT:
771     case HID_TRANS_GET_PROTOCOL:
772     case HID_TRANS_SET_PROTOCOL:
773     case HID_TRANS_GET_IDLE:
774     case HID_TRANS_SET_IDLE:
775       cid = p_hcon->ctrl_cid;
776       buf_size = HID_CONTROL_BUF_SIZE;
777       break;
778     case HID_TRANS_DATA:
779       cid = p_hcon->intr_cid;
780       buf_size = HID_INTERRUPT_BUF_SIZE;
781       break;
782     default:
783       log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
784                               HIDH_ERR_INVALID_PARAM_AT_SEND_DATA,
785                           1);
786       return (HID_ERR_INVALID_PARAM);
787   }
788 
789   if (trans_type == HID_TRANS_SET_IDLE)
790     use_data = 1;
791   else if ((trans_type == HID_TRANS_GET_REPORT) && (param & 0x08))
792     use_data = 2;
793 
794   do {
795     if (buf == NULL || blank_datc) {
796       p_buf = (BT_HDR*)osi_malloc(buf_size);
797 
798       p_buf->offset = L2CAP_MIN_OFFSET;
799       seg_req = false;
800       data_size = 0;
801       bytes_copied = 0;
802       blank_datc = false;
803     } else if ((buf->len > (p_hcon->rem_mtu_size - 1))) {
804       p_buf = (BT_HDR*)osi_malloc(buf_size);
805 
806       p_buf->offset = L2CAP_MIN_OFFSET;
807       seg_req = true;
808       data_size = buf->len;
809       bytes_copied = p_hcon->rem_mtu_size - 1;
810     } else {
811       p_buf = buf;
812       p_buf->offset -= 1;
813       seg_req = false;
814       data_size = buf->len;
815       bytes_copied = buf->len;
816     }
817 
818     p_out = (uint8_t*)(p_buf + 1) + p_buf->offset;
819     *p_out++ = HID_BUILD_HDR(trans_type, param);
820 
821     /* If report ID required for this device */
822     if ((trans_type == HID_TRANS_GET_REPORT) && (report_id != 0)) {
823       *p_out = report_id;
824       data_size = bytes_copied = 1;
825     }
826 
827     if (seg_req) {
828       memcpy(p_out, (((uint8_t*)(buf + 1)) + buf->offset), bytes_copied);
829       buf->offset += bytes_copied;
830       buf->len -= bytes_copied;
831     } else if (use_data == 1) {
832       *(p_out + bytes_copied) = data & 0xff;
833     } else if (use_data == 2) {
834       *(p_out + bytes_copied) = data & 0xff;
835       *(p_out + bytes_copied + 1) = (data >> 8) & 0xff;
836     }
837 
838     p_buf->len = bytes_copied + 1 + use_data;
839     data_size -= bytes_copied;
840 
841     /* Send the buffer through L2CAP */
842     if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) ||
843         (!L2CA_DataWrite(cid, p_buf))) {
844       log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
845                               HIDH_ERR_CONGESTED_AT_SEND_DATA,
846                           1);
847       return (HID_ERR_CONGESTED);
848     }
849 
850     if (data_size)
851       trans_type = HID_TRANS_DATAC;
852     else if (bytes_copied == (p_hcon->rem_mtu_size - 1)) {
853       trans_type = HID_TRANS_DATAC;
854       blank_datc = true;
855     }
856 
857   } while ((data_size != 0) || blank_datc);
858 
859   return (HID_SUCCESS);
860 }
861 /*******************************************************************************
862  *
863  * Function         hidh_conn_initiate
864  *
865  * Description      This function is called by the management to create a
866  *                  connection.
867  *
868  * Returns          void
869  *
870  ******************************************************************************/
hidh_conn_initiate(uint8_t dhandle)871 tHID_STATUS hidh_conn_initiate(uint8_t dhandle) {
872   tHID_HOST_DEV_CTB* p_dev = &hh_cb.devices[dhandle];
873 
874   if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) {
875     log_counter_metrics(
876         android::bluetooth::CodePathCounterKeyEnum::HIDH_ERR_CONN_IN_PROCESS,
877         1);
878     return (HID_ERR_CONN_IN_PROCESS);
879   }
880 
881   p_dev->conn.ctrl_cid = 0;
882   p_dev->conn.intr_cid = 0;
883   p_dev->conn.disc_reason =
884       HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection
885                               Attempt was made but failed */
886 
887   /* We are the originator of this connection */
888   p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
889 
890   /* Check if L2CAP started the connection process */
891   p_dev->conn.ctrl_cid = L2CA_ConnectReq2(
892       HID_PSM_CONTROL, p_dev->addr, BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT);
893   if (p_dev->conn.ctrl_cid == 0) {
894     HIDH_TRACE_WARNING("HID-Host Originate failed");
895     hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
896                    HID_ERR_L2CAP_FAILED, NULL);
897     log_counter_metrics(android::bluetooth::CodePathCounterKeyEnum::
898                             HIDH_ERR_L2CAP_FAILED_AT_INITIATE,
899                         1);
900   } else {
901     /* Transition to the next appropriate state, waiting for connection confirm
902      * on control channel. */
903     p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
904     BTM_LogHistory(kBtmLogTag, hh_cb.devices[dhandle].addr, "Connecting",
905                    "control channel");
906   }
907 
908   return (HID_SUCCESS);
909 }
910 
911 /*******************************************************************************
912  *
913  * Function         find_conn_by_cid
914  *
915  * Description      This function finds a connection control block based on CID.
916  *
917  * Returns          index of control block, or kHID_HOST_MAX_DEVICES if not
918  *                  found.
919  *
920  ******************************************************************************/
find_conn_by_cid(uint16_t cid)921 static uint8_t find_conn_by_cid(uint16_t cid) {
922   uint8_t xx;
923 
924   for (xx = 0; xx < kHID_HOST_MAX_DEVICES; xx++) {
925     if ((hh_cb.devices[xx].in_use) &&
926         (hh_cb.devices[xx].conn.conn_state != HID_CONN_STATE_UNUSED) &&
927         ((hh_cb.devices[xx].conn.ctrl_cid == cid) ||
928          (hh_cb.devices[xx].conn.intr_cid == cid)))
929       break;
930   }
931 
932   return (xx);
933 }
934 
hidh_conn_dereg(void)935 void hidh_conn_dereg(void) {
936   L2CA_Deregister(HID_PSM_CONTROL);
937   L2CA_Deregister(HID_PSM_INTERRUPT);
938 }
939 
940 /*******************************************************************************
941  *
942  * Function         hidh_conn_retry
943  *
944  * Description      This function is called to retry a failed connection.
945  *
946  * Returns          void
947  *
948  ******************************************************************************/
hidh_conn_retry(uint8_t dhandle)949 static void hidh_conn_retry(uint8_t dhandle) {
950   tHID_HOST_DEV_CTB* p_dev = &hh_cb.devices[dhandle];
951 
952   p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
953 #if (HID_HOST_REPAGE_WIN > 0)
954   uint64_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
955   alarm_set_on_mloop(p_dev->conn.process_repage_timer, interval_ms,
956                      hidh_process_repage_timer_timeout, UINT_TO_PTR(dhandle));
957 #else
958   hidh_try_repage(dhandle);
959 #endif
960 }
961