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