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