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