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