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