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