• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright (C) 2016 The Android Open Source Project
4  *  Copyright (C) 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 <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "bt_types.h"
31 
32 #include "l2c_api.h"
33 #include "l2cdefs.h"
34 
35 #include "btm_api.h"
36 #include "btm_int.h"
37 #include "btu.h"
38 
39 #include "hiddefs.h"
40 
41 #include "bt_utils.h"
42 #include "hidd_api.h"
43 #include "hidd_int.h"
44 
45 #include "osi/include/osi.h"
46 
47 static void hidd_l2cif_connect_ind(const RawAddress& bd_addr, uint16_t cid,
48                                    uint16_t psm, uint8_t id);
49 static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result);
50 static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
51 static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
52 static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed);
53 static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result);
54 static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg);
55 static void hidd_l2cif_cong_ind(uint16_t cid, bool congested);
56 
57 static const tL2CAP_APPL_INFO dev_reg_info = {hidd_l2cif_connect_ind,
58                                               hidd_l2cif_connect_cfm,
59                                               NULL,
60                                               hidd_l2cif_config_ind,
61                                               hidd_l2cif_config_cfm,
62                                               hidd_l2cif_disconnect_ind,
63                                               hidd_l2cif_disconnect_cfm,
64                                               NULL,
65                                               hidd_l2cif_data_ind,
66                                               hidd_l2cif_cong_ind,
67                                               NULL};
68 
69 /*******************************************************************************
70  *
71  * Function         hidd_check_config_done
72  *
73  * Description      Checks if connection is configured and callback can be fired
74  *
75  * Returns          void
76  *
77  ******************************************************************************/
hidd_check_config_done()78 static void hidd_check_config_done() {
79   tHID_CONN* p_hcon;
80 
81   p_hcon = &hd_cb.device.conn;
82 
83   if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) ==
84        HID_CONN_FLAGS_ALL_CONFIGURED) &&
85       (p_hcon->conn_state == HID_CONN_STATE_CONFIG)) {
86     p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
87 
88     hd_cb.device.state = HIDD_DEV_CONNECTED;
89 
90     hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_OPEN, 0, NULL);
91 
92     // send outstanding data on intr
93     if (hd_cb.pending_data) {
94       L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data);
95       hd_cb.pending_data = NULL;
96     }
97   }
98 }
99 
100 /*******************************************************************************
101  *
102  * Function         hidh_sec_check_complete_term
103  *
104  * Description      HID security check complete callback function.
105  *
106  * Returns          Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
107  *                  send security block L2C connection response.
108  *
109  ******************************************************************************/
hidd_sec_check_complete(UNUSED_ATTR const RawAddress * bd_addr,UNUSED_ATTR tBT_TRANSPORT transport,void * p_ref_data,uint8_t res)110 static void hidd_sec_check_complete(UNUSED_ATTR const RawAddress* bd_addr,
111                                     UNUSED_ATTR tBT_TRANSPORT transport,
112                                     void* p_ref_data, uint8_t res) {
113   tHID_DEV_DEV_CTB* p_dev = (tHID_DEV_DEV_CTB*)p_ref_data;
114 
115   if (res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) {
116     p_dev->conn.disc_reason = HID_SUCCESS;
117     p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
118 
119     L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid,
120                     L2CAP_CONN_OK, L2CAP_CONN_OK);
121     L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
122   } else if (res != BTM_SUCCESS) {
123     HIDD_TRACE_WARNING("%s: connection rejected by security", __func__);
124 
125     p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
126     p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
127     L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid,
128                     L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
129     return;
130   }
131 }
132 
133 /*******************************************************************************
134  *
135  * Function         hidd_sec_check_complete_orig
136  *
137  * Description      HID security check complete callback function (device
138 *originated)
139  *
140  * Returns          void
141  *
142  ******************************************************************************/
hidd_sec_check_complete_orig(UNUSED_ATTR const RawAddress * bd_addr,UNUSED_ATTR tBT_TRANSPORT transport,void * p_ref_data,uint8_t res)143 void hidd_sec_check_complete_orig(UNUSED_ATTR const RawAddress* bd_addr,
144                                   UNUSED_ATTR tBT_TRANSPORT transport,
145                                   void* p_ref_data, uint8_t res) {
146   tHID_DEV_DEV_CTB* p_dev = (tHID_DEV_DEV_CTB*)p_ref_data;
147 
148   if (p_dev->conn.conn_state != HID_CONN_STATE_SECURITY) {
149     HIDD_TRACE_WARNING("%s: invalid state (%02x)", __func__,
150                        p_dev->conn.conn_state);
151     return;
152   }
153 
154   if (res == BTM_SUCCESS) {
155     HIDD_TRACE_EVENT("%s: security ok", __func__);
156     p_dev->conn.disc_reason = HID_SUCCESS;
157 
158     p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
159     L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hd_cb.l2cap_cfg);
160   } else {
161     HIDD_TRACE_WARNING("%s: security check failed (%02x)", __func__, res);
162     p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED;
163     hidd_conn_disconnect();
164   }
165 }
166 
167 /*******************************************************************************
168  *
169  * Function         hidd_l2cif_connect_ind
170  *
171  * Description      Handles incoming L2CAP connection (we act as server)
172  *
173  * Returns          void
174  *
175  ******************************************************************************/
hidd_l2cif_connect_ind(const RawAddress & bd_addr,uint16_t cid,uint16_t psm,uint8_t id)176 static void hidd_l2cif_connect_ind(const RawAddress& bd_addr, uint16_t cid,
177                                    uint16_t psm, uint8_t id) {
178   tHID_CONN* p_hcon;
179   tHID_DEV_DEV_CTB* p_dev;
180   bool accept = TRUE;  // accept by default
181 
182   HIDD_TRACE_EVENT("%s: psm=%04x cid=%04x id=%02x", __func__, psm, cid, id);
183 
184   p_dev = &hd_cb.device;
185 
186   if (!hd_cb.allow_incoming) {
187     HIDD_TRACE_WARNING("%s: incoming connections not allowed, rejecting",
188                        __func__);
189     L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
190     return;
191   }
192 
193   if (p_dev->in_use && bd_addr != p_dev->addr) {
194     HIDD_TRACE_WARNING(
195         "%s: incoming connections from different device, rejecting", __func__);
196     L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
197     return;
198   } else if (!p_dev->in_use) {
199     p_dev->in_use = TRUE;
200     p_dev->addr = bd_addr;
201     p_dev->state = HIDD_DEV_NO_CONN;
202   }
203 
204   p_hcon = &hd_cb.device.conn;
205 
206   switch (psm) {
207     case HID_PSM_INTERRUPT:
208       if (p_hcon->ctrl_cid == 0) {
209         accept = FALSE;
210         HIDD_TRACE_WARNING("%s: incoming INTR without CTRL, rejecting",
211                            __func__);
212       }
213 
214       if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) {
215         accept = FALSE;
216         HIDD_TRACE_WARNING("%s: incoming INTR in invalid state (%d), rejecting",
217                            __func__, p_hcon->conn_state);
218       }
219 
220       break;
221 
222     case HID_PSM_CONTROL:
223       if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) {
224         accept = FALSE;
225         HIDD_TRACE_WARNING("%s: incoming CTRL in invalid state (%d), rejecting",
226                            __func__, p_hcon->conn_state);
227       }
228 
229       break;
230 
231     default:
232       accept = FALSE;
233       HIDD_TRACE_ERROR("%s: received invalid PSM, rejecting", __func__);
234       break;
235   }
236 
237   if (!accept) {
238     L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_NO_RESOURCES, 0);
239     return;
240   }
241 
242   // for CTRL we need to go through security and we reply in callback from there
243   if (psm == HID_PSM_CONTROL) {
244     p_hcon->conn_flags = 0;
245     p_hcon->ctrl_cid = cid;
246     p_hcon->ctrl_id = id;
247     p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
248 
249     p_hcon->conn_state = HID_CONN_STATE_SECURITY;
250     if (btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, FALSE,
251                                   BTM_SEC_PROTO_HID, HIDD_NOSEC_CHN,
252                                   &hidd_sec_check_complete,
253                                   p_dev) == BTM_CMD_STARTED) {
254       L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
255     }
256 
257     return;
258   }
259 
260   // for INTR we go directly to config state
261   p_hcon->conn_state = HID_CONN_STATE_CONFIG;
262   p_hcon->intr_cid = cid;
263 
264   L2CA_ConnectRsp(bd_addr, id, cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
265   L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
266 }
267 
268 /*******************************************************************************
269  *
270  * Function         hidd_l2cif_connect_cfm
271  *
272  * Description      Handles L2CAP connection response (we act as client)
273  *
274  * Returns          void
275  *
276  ******************************************************************************/
hidd_l2cif_connect_cfm(uint16_t cid,uint16_t result)277 static void hidd_l2cif_connect_cfm(uint16_t cid, uint16_t result) {
278   tHID_DEV_DEV_CTB* p_dev = &hd_cb.device;
279   tHID_CONN* p_hcon = &hd_cb.device.conn;
280 
281   HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result);
282 
283   if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
284     HIDD_TRACE_WARNING("%s: unknown cid", __func__);
285     return;
286   }
287 
288   if (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) ||
289       ((cid == p_hcon->ctrl_cid) &&
290        (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL)) ||
291       ((cid == p_hcon->intr_cid) &&
292        (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR))) {
293     HIDD_TRACE_WARNING("%s: unexpected", __func__);
294     return;
295   }
296 
297   if (result != L2CAP_CONN_OK) {
298     HIDD_TRACE_WARNING("%s: connection failed, now disconnect", __func__);
299 
300     if (cid == p_hcon->ctrl_cid)
301       p_hcon->ctrl_cid = 0;
302     else
303       p_hcon->intr_cid = 0;
304 
305     hidd_conn_disconnect();
306 
307     hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
308                    HID_L2CAP_CONN_FAIL | (uint32_t)result, NULL);
309     return;
310   }
311 
312   /* CTRL connect conf */
313   if (cid == p_hcon->ctrl_cid) {
314     p_hcon->conn_state = HID_CONN_STATE_SECURITY;
315     p_hcon->disc_reason =
316         HID_L2CAP_CONN_FAIL; /* in case disconnected before sec completed */
317 
318     btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, TRUE,
319                               BTM_SEC_PROTO_HID, HIDD_SEC_CHN,
320                               &hidd_sec_check_complete_orig, p_dev);
321   } else {
322     p_hcon->conn_state = HID_CONN_STATE_CONFIG;
323     L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
324   }
325 
326   return;
327 }
328 
329 /*******************************************************************************
330  *
331  * Function         hidd_l2cif_config_ind
332  *
333  * Description      Handles incoming L2CAP configuration request
334  *
335  * Returns          void
336  *
337  ******************************************************************************/
hidd_l2cif_config_ind(uint16_t cid,tL2CAP_CFG_INFO * p_cfg)338 static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
339   tHID_CONN* p_hcon;
340 
341   HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
342 
343   p_hcon = &hd_cb.device.conn;
344 
345   if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
346     HIDD_TRACE_WARNING("%s: unknown cid", __func__);
347     return;
348   }
349 
350   if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_DEV_MTU_SIZE))
351     p_hcon->rem_mtu_size = HID_DEV_MTU_SIZE;
352   else
353     p_hcon->rem_mtu_size = p_cfg->mtu;
354 
355   // accept without changes
356   p_cfg->flush_to_present = FALSE;
357   p_cfg->mtu_present = FALSE;
358   p_cfg->result = L2CAP_CFG_OK;
359 
360   if (cid == p_hcon->intr_cid && hd_cb.use_in_qos && !p_cfg->qos_present) {
361     p_cfg->qos_present = TRUE;
362     memcpy(&p_cfg->qos, &hd_cb.in_qos, sizeof(FLOW_SPEC));
363   }
364 
365   L2CA_ConfigRsp(cid, p_cfg);
366 
367   // update flags
368   if (cid == p_hcon->ctrl_cid) {
369     p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
370 
371     if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
372         (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) {
373       p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
374       if ((p_hcon->intr_cid =
375                L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
376         hidd_conn_disconnect();
377         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
378 
379         HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR",
380                            __func__);
381         hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
382                        HID_ERR_L2CAP_FAILED, NULL);
383         return;
384       } else {
385         p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
386       }
387     }
388   } else {
389     p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
390   }
391 
392   hidd_check_config_done();
393 }
394 
395 /*******************************************************************************
396  *
397  * Function         hidd_l2cif_config_cfm
398  *
399  * Description      Handles incoming L2CAP configuration response
400  *
401  * Returns          void
402  *
403  ******************************************************************************/
hidd_l2cif_config_cfm(uint16_t cid,tL2CAP_CFG_INFO * p_cfg)404 static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
405   tHID_CONN* p_hcon;
406   uint32_t reason;
407 
408   HIDD_TRACE_EVENT("%s: cid=%04x pcfg->result=%d", __func__, cid,
409                    p_cfg->result);
410 
411   p_hcon = &hd_cb.device.conn;
412 
413   if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
414     HIDD_TRACE_WARNING("%s: unknown cid", __func__);
415     return;
416   }
417 
418   if (p_hcon->intr_cid == cid &&
419       p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS && p_cfg->qos_present) {
420     tL2CAP_CFG_INFO new_qos;
421 
422     // QoS parameters not accepted for intr, try again with host proposal
423 
424     memcpy(&new_qos, &hd_cb.l2cap_intr_cfg, sizeof(new_qos));
425     memcpy(&new_qos.qos, &p_cfg->qos, sizeof(FLOW_SPEC));
426     new_qos.qos_present = TRUE;
427 
428     HIDD_TRACE_WARNING("%s: config failed, retry", __func__);
429 
430     L2CA_ConfigReq(cid, &new_qos);
431     return;
432   } else if (p_hcon->intr_cid == cid &&
433              p_cfg->result == L2CAP_CFG_UNKNOWN_OPTIONS) {
434     // QoS not understood by remote device, try configuring without QoS
435 
436     HIDD_TRACE_WARNING("%s: config failed, retry without QoS", __func__);
437 
438     L2CA_ConfigReq(cid, &hd_cb.l2cap_cfg);
439     return;
440   } else if (p_cfg->result != L2CAP_CFG_OK) {
441     HIDD_TRACE_WARNING("%s: config failed, disconnecting", __func__);
442 
443     hidd_conn_disconnect();
444     reason = HID_L2CAP_CFG_FAIL | (uint32_t)p_cfg->result;
445 
446     hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, reason, NULL);
447     return;
448   }
449 
450   // update flags
451   if (cid == p_hcon->ctrl_cid) {
452     p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
453 
454     if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
455         (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) {
456       p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
457       if ((p_hcon->intr_cid =
458                L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
459         hidd_conn_disconnect();
460         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
461 
462         HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR",
463                            __func__);
464         hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
465                        HID_ERR_L2CAP_FAILED, NULL);
466         return;
467       } else {
468         p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
469       }
470     }
471   } else {
472     p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
473   }
474 
475   hidd_check_config_done();
476 }
477 
478 /*******************************************************************************
479  *
480  * Function         hidd_l2cif_disconnect_ind
481  *
482  * Description      Handler incoming L2CAP disconnection request
483  *
484  * Returns          void
485  *
486  ******************************************************************************/
hidd_l2cif_disconnect_ind(uint16_t cid,bool ack_needed)487 static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed) {
488   tHID_CONN* p_hcon;
489 
490   HIDD_TRACE_EVENT("%s: cid=%04x ack_needed=%d", __func__, cid, ack_needed);
491 
492   p_hcon = &hd_cb.device.conn;
493 
494   if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
495       (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
496     HIDD_TRACE_WARNING("%s: unknown cid", __func__);
497     return;
498   }
499 
500   if (ack_needed) L2CA_DisconnectRsp(cid);
501 
502   p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
503 
504   if (cid == p_hcon->ctrl_cid)
505     p_hcon->ctrl_cid = 0;
506   else
507     p_hcon->intr_cid = 0;
508 
509   if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
510     HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
511 
512     // clean any outstanding data on intr
513     if (hd_cb.pending_data) {
514       osi_free(hd_cb.pending_data);
515       hd_cb.pending_data = NULL;
516     }
517 
518     hd_cb.device.state = HIDD_DEV_NO_CONN;
519     p_hcon->conn_state = HID_CONN_STATE_UNUSED;
520 
521     hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, p_hcon->disc_reason,
522                    NULL);
523   }
524 }
525 
526 /*******************************************************************************
527  *
528  * Function         hidd_l2cif_disconnect_cfm
529  *
530  * Description      Handles L2CAP disconection response
531  *
532  * Returns          void
533  *
534  ******************************************************************************/
hidd_l2cif_disconnect_cfm(uint16_t cid,uint16_t result)535 static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result) {
536   tHID_CONN* p_hcon;
537 
538   HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result);
539 
540   p_hcon = &hd_cb.device.conn;
541 
542   if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
543       (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
544     HIDD_TRACE_WARNING("%s: unknown cid", __func__);
545     return;
546   }
547 
548   if (cid == p_hcon->ctrl_cid) {
549     p_hcon->ctrl_cid = 0;
550   } else {
551     p_hcon->intr_cid = 0;
552 
553     // now disconnect CTRL
554     L2CA_DisconnectReq(p_hcon->ctrl_cid);
555   }
556 
557   if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
558     HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
559 
560     hd_cb.device.state = HIDD_DEV_NO_CONN;
561     p_hcon->conn_state = HID_CONN_STATE_UNUSED;
562 
563     if (hd_cb.pending_vc_unplug) {
564       hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_VC_UNPLUG,
565                      p_hcon->disc_reason, NULL);
566       hd_cb.pending_vc_unplug = FALSE;
567     } else {
568       hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE,
569                      p_hcon->disc_reason, NULL);
570     }
571   }
572 }
573 
574 /*******************************************************************************
575  *
576  * Function         hidd_l2cif_cong_ind
577  *
578  * Description      Handles L2CAP congestion status event
579  *
580  * Returns          void
581  *
582  ******************************************************************************/
hidd_l2cif_cong_ind(uint16_t cid,bool congested)583 static void hidd_l2cif_cong_ind(uint16_t cid, bool congested) {
584   tHID_CONN* p_hcon;
585 
586   HIDD_TRACE_EVENT("%s: cid=%04x congested=%d", __func__, cid, congested);
587 
588   p_hcon = &hd_cb.device.conn;
589 
590   if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
591       (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
592     HIDD_TRACE_WARNING("%s: unknown cid", __func__);
593     return;
594   }
595 
596   if (congested) {
597     p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
598   } else {
599     p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
600   }
601 }
602 
603 /*******************************************************************************
604  *
605  * Function         hidd_l2cif_data_ind
606  *
607  * Description      Handler incoming data on L2CAP channel
608  *
609  * Returns          void
610  *
611  ******************************************************************************/
hidd_l2cif_data_ind(uint16_t cid,BT_HDR * p_msg)612 static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR* p_msg) {
613   tHID_CONN* p_hcon;
614   uint8_t* p_data = (uint8_t*)(p_msg + 1) + p_msg->offset;
615   uint8_t msg_type, param;
616   bool err = FALSE;
617 
618   HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
619 
620   p_hcon = &hd_cb.device.conn;
621 
622   if (p_hcon->conn_state == HID_CONN_STATE_UNUSED ||
623       (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
624     HIDD_TRACE_WARNING("%s: unknown cid", __func__);
625     osi_free(p_msg);
626     return;
627   }
628 
629   msg_type = HID_GET_TRANS_FROM_HDR(*p_data);
630   param = HID_GET_PARAM_FROM_HDR(*p_data);
631 
632   if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
633     // skip HID header
634     p_msg->offset++;
635     p_msg->len--;
636 
637     hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_INTR_DATA, 0, p_msg);
638     return;
639   }
640 
641   switch (msg_type) {
642     case HID_TRANS_GET_REPORT:
643       // at this stage we don't know if Report Id shall be included in request
644       // so we pass complete packet in callback and let other code analyze this
645       hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_GET_REPORT,
646                      !!(param & HID_PAR_GET_REP_BUFSIZE_FOLLOWS), p_msg);
647       break;
648 
649     case HID_TRANS_SET_REPORT:
650       // as above
651       hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_REPORT, 0, p_msg);
652       break;
653 
654     case HID_TRANS_GET_IDLE:
655       hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA,
656                           HID_PAR_REP_TYPE_OTHER, hd_cb.device.idle_time, 0,
657                           NULL);
658       osi_free(p_msg);
659       break;
660 
661     case HID_TRANS_SET_IDLE:
662       if (p_msg->len != 2) {
663         HIDD_TRACE_ERROR("%s: invalid len (%d) set idle request received",
664                          __func__, p_msg->len);
665         err = TRUE;
666       } else {
667         hd_cb.device.idle_time = p_data[1];
668         HIDD_TRACE_DEBUG("%s: idle_time = %d", __func__,
669                          hd_cb.device.idle_time);
670         if (hd_cb.device.idle_time) {
671           HIDD_TRACE_WARNING(
672               "%s: idle_time of %d ms not supported by HID Device", __func__,
673               (hd_cb.device.idle_time * 4));
674           err = TRUE;
675         }
676       }
677       if (!err) {
678         hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
679                             HID_PAR_HANDSHAKE_RSP_SUCCESS, 0, 0, NULL);
680       } else {
681         hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
682                             HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM, 0, 0,
683                             NULL);
684       }
685       osi_free(p_msg);
686       break;
687 
688     case HID_TRANS_GET_PROTOCOL:
689       hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA,
690                           HID_PAR_REP_TYPE_OTHER, !hd_cb.device.boot_mode, 0,
691                           NULL);
692       osi_free(p_msg);
693       break;
694 
695     case HID_TRANS_SET_PROTOCOL:
696       hd_cb.device.boot_mode = !(param & HID_PAR_PROTOCOL_MASK);
697       hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_PROTOCOL,
698                      param & HID_PAR_PROTOCOL_MASK, NULL);
699       hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_SUCCESS,
700                           0, 0, NULL);
701       osi_free(p_msg);
702       break;
703 
704     case HID_TRANS_CONTROL:
705       switch (param) {
706         case HID_PAR_CONTROL_SUSPEND:
707           hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SUSPEND, 0, NULL);
708           break;
709 
710         case HID_PAR_CONTROL_EXIT_SUSPEND:
711           hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_EXIT_SUSPEND, 0,
712                          NULL);
713           break;
714 
715         case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
716           hidd_conn_disconnect();
717 
718           // set flag so we can notify properly when disconnected
719           hd_cb.pending_vc_unplug = TRUE;
720           break;
721       }
722 
723       osi_free(p_msg);
724       break;
725 
726     case HID_TRANS_DATA:
727     default:
728       HIDD_TRACE_WARNING("%s: got unsupported msg (%d)", __func__, msg_type);
729       hidd_conn_send_data(0, HID_TRANS_HANDSHAKE,
730                           HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ, 0, 0,
731                           NULL);
732       osi_free(p_msg);
733       break;
734   }
735 }
736 
737 /*******************************************************************************
738  *
739  * Function         hidd_conn_reg
740  *
741  * Description      Registers L2CAP channels
742  *
743  * Returns          void
744  *
745  ******************************************************************************/
hidd_conn_reg(void)746 tHID_STATUS hidd_conn_reg(void) {
747   HIDD_TRACE_API("%s", __func__);
748 
749   memset(&hd_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
750 
751   hd_cb.l2cap_cfg.mtu_present = TRUE;
752   hd_cb.l2cap_cfg.mtu = HID_DEV_MTU_SIZE;
753   hd_cb.l2cap_cfg.flush_to_present = TRUE;
754   hd_cb.l2cap_cfg.flush_to = HID_DEV_FLUSH_TO;
755 
756   memset(&hd_cb.l2cap_intr_cfg, 0, sizeof(tL2CAP_CFG_INFO));
757   hd_cb.l2cap_intr_cfg.mtu_present = TRUE;
758   hd_cb.l2cap_intr_cfg.mtu = HID_DEV_MTU_SIZE;
759   hd_cb.l2cap_intr_cfg.flush_to_present = TRUE;
760   hd_cb.l2cap_intr_cfg.flush_to = HID_DEV_FLUSH_TO;
761 
762   if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&dev_reg_info)) {
763     HIDD_TRACE_ERROR("HID Control (device) registration failed");
764     return (HID_ERR_L2CAP_FAILED);
765   }
766 
767   if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&dev_reg_info)) {
768     L2CA_Deregister(HID_PSM_CONTROL);
769     HIDD_TRACE_ERROR("HID Interrupt (device) registration failed");
770     return (HID_ERR_L2CAP_FAILED);
771   }
772 
773   return (HID_SUCCESS);
774 }
775 
776 /*******************************************************************************
777  *
778  * Function         hidd_conn_dereg
779  *
780  * Description      Deregisters L2CAP channels
781  *
782  * Returns          void
783  *
784  ******************************************************************************/
hidd_conn_dereg(void)785 void hidd_conn_dereg(void) {
786   HIDD_TRACE_API("%s", __func__);
787 
788   L2CA_Deregister(HID_PSM_CONTROL);
789   L2CA_Deregister(HID_PSM_INTERRUPT);
790 }
791 
792 /*******************************************************************************
793  *
794  * Function         hidd_conn_initiate
795  *
796  * Description      Initiates HID connection to plugged device
797  *
798  * Returns          HID_SUCCESS
799  *
800  ******************************************************************************/
hidd_conn_initiate(void)801 tHID_STATUS hidd_conn_initiate(void) {
802   tHID_DEV_DEV_CTB* p_dev = &hd_cb.device;
803 
804   HIDD_TRACE_API("%s", __func__);
805 
806   if (!p_dev->in_use) {
807     HIDD_TRACE_WARNING("%s: no virtual cable established", __func__);
808     return (HID_ERR_NOT_REGISTERED);
809   }
810 
811   if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) {
812     HIDD_TRACE_WARNING("%s: connection already in progress", __func__);
813     return (HID_ERR_CONN_IN_PROCESS);
814   }
815 
816   p_dev->conn.ctrl_cid = 0;
817   p_dev->conn.intr_cid = 0;
818   p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL;
819 
820   p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
821 
822   BTM_SetOutService(p_dev->addr, BTM_SEC_SERVICE_HIDD_SEC_CTRL, HIDD_SEC_CHN);
823 
824   /* Check if L2CAP started the connection process */
825   if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq(HID_PSM_CONTROL, p_dev->addr)) ==
826       0) {
827     HIDD_TRACE_WARNING("%s: could not start L2CAP connection", __func__);
828     hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED,
829                    NULL);
830   } else {
831     p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
832   }
833 
834   return (HID_SUCCESS);
835 }
836 
837 /*******************************************************************************
838  *
839  * Function         hidd_conn_disconnect
840  *
841  * Description      Disconnects existing HID connection
842  *
843  * Returns          HID_SUCCESS
844  *
845  ******************************************************************************/
hidd_conn_disconnect(void)846 tHID_STATUS hidd_conn_disconnect(void) {
847   tHID_CONN* p_hcon;
848 
849   HIDD_TRACE_API("%s", __func__);
850 
851   // clean any outstanding data on intr
852   if (hd_cb.pending_data) {
853     osi_free(hd_cb.pending_data);
854     hd_cb.pending_data = NULL;
855   }
856 
857   p_hcon = &hd_cb.device.conn;
858 
859   if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
860     p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
861 
862     /* Set l2cap idle timeout to 0 (so ACL link is disconnected
863      * immediately after last channel is closed) */
864     L2CA_SetIdleTimeoutByBdAddr(hd_cb.device.addr, 0, BT_TRANSPORT_BR_EDR);
865 
866     if (p_hcon->intr_cid) {
867       L2CA_DisconnectReq(p_hcon->intr_cid);
868     } else if (p_hcon->ctrl_cid) {
869       L2CA_DisconnectReq(p_hcon->ctrl_cid);
870     }
871   } else {
872     HIDD_TRACE_WARNING("%s: already disconnected", __func__);
873     p_hcon->conn_state = HID_CONN_STATE_UNUSED;
874   }
875 
876   return (HID_SUCCESS);
877 }
878 
879 /*******************************************************************************
880  *
881  * Function         hidd_conn_send_data
882  *
883  * Description      Sends data to host
884  *
885  * Returns          tHID_STATUS
886  *
887  ******************************************************************************/
hidd_conn_send_data(uint8_t channel,uint8_t msg_type,uint8_t param,uint8_t data,uint16_t len,uint8_t * p_data)888 tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type,
889                                 uint8_t param, uint8_t data, uint16_t len,
890                                 uint8_t* p_data) {
891   tHID_CONN* p_hcon;
892   BT_HDR* p_buf;
893   uint8_t* p_out;
894   uint16_t cid;
895   uint16_t buf_size;
896 
897   HIDD_TRACE_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__,
898                      channel, msg_type, len);
899 
900   p_hcon = &hd_cb.device.conn;
901 
902   if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
903     return HID_ERR_CONGESTED;
904   }
905 
906   switch (msg_type) {
907     case HID_TRANS_HANDSHAKE:
908     case HID_TRANS_CONTROL:
909       cid = p_hcon->ctrl_cid;
910       buf_size = HID_CONTROL_BUF_SIZE;
911       break;
912     case HID_TRANS_DATA:
913       if (channel == HID_CHANNEL_CTRL) {
914         cid = p_hcon->ctrl_cid;
915         buf_size = HID_CONTROL_BUF_SIZE;
916       } else {
917         cid = p_hcon->intr_cid;
918         buf_size = HID_INTERRUPT_BUF_SIZE;
919       }
920       break;
921     default:
922       return (HID_ERR_INVALID_PARAM);
923   }
924 
925   p_buf = (BT_HDR*)osi_malloc(buf_size);
926   if (p_buf == NULL) return (HID_ERR_NO_RESOURCES);
927 
928   p_buf->offset = L2CAP_MIN_OFFSET;
929 
930   p_out = (uint8_t*)(p_buf + 1) + p_buf->offset;
931 
932   *p_out = HID_BUILD_HDR(msg_type, param);
933   p_out++;
934 
935   p_buf->len = 1;  // start with header only
936 
937   // add report id prefix only if non-zero (which is reserved)
938   if (msg_type == HID_TRANS_DATA && (data || param == HID_PAR_REP_TYPE_OTHER)) {
939     *p_out = data;  // report_id
940     p_out++;
941     p_buf->len++;
942   }
943 
944   if (len > 0 && p_data != NULL) {
945     memcpy(p_out, p_data, len);
946     p_buf->len += len;
947   }
948 
949   // check if connected
950   if (hd_cb.device.state != HIDD_DEV_CONNECTED) {
951     // for DATA on intr we hold transfer and try to reconnect
952     if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
953       // drop previous data, we do not queue it for now
954       if (hd_cb.pending_data) {
955         osi_free(hd_cb.pending_data);
956       }
957 
958       hd_cb.pending_data = p_buf;
959 
960       if (hd_cb.device.conn.conn_state == HID_CONN_STATE_UNUSED) {
961         hidd_conn_initiate();
962       }
963 
964       return HID_SUCCESS;
965     }
966 
967     return HID_ERR_NO_CONNECTION;
968   }
969 
970 #ifdef REPORT_TRANSFER_TIMESTAMP
971   if (report_transfer) {
972     HIDD_TRACE_ERROR("%s: report sent", __func__);
973   }
974 #endif
975   HIDD_TRACE_VERBOSE("%s: report sent", __func__);
976 
977   if (!L2CA_DataWrite(cid, p_buf)) return (HID_ERR_CONGESTED);
978 
979   return (HID_SUCCESS);
980 }
981