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", __func__);
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         hidd_conn_disconnect();
251         hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_L2CAP_CONN_FAIL | (uint32_t)result, NULL);
252         return;
253     }
254     /* CTRL connect conf */
255     if (cid == p_hcon->ctrl_cid) {
256         p_hcon->conn_state = HID_CONN_STATE_SECURITY;
257         p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* in case disconnected before sec completed */
258         btm_sec_mx_access_request(p_dev->addr, HID_PSM_CONTROL, TRUE, BTM_SEC_PROTO_HID, HIDD_SEC_CHN,
259                                   &hidd_sec_check_complete_orig, p_dev);
260     } else {
261         p_hcon->conn_state = HID_CONN_STATE_CONFIG;
262         L2CA_ConfigReq(cid, &hd_cb.l2cap_intr_cfg);
263     }
264     return;
265 }
266 /*******************************************************************************
267  *
268  * Function         hidd_l2cif_config_ind
269  *
270  * Description      Handles incoming L2CAP configuration request
271  *
272  * Returns          void
273  *
274  ******************************************************************************/
hidd_l2cif_config_ind(uint16_t cid,tL2CAP_CFG_INFO * p_cfg)275 static void hidd_l2cif_config_ind(uint16_t cid, tL2CAP_CFG_INFO *p_cfg)
276 {
277     tHID_CONN *p_hcon;
278     HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
279     p_hcon = &hd_cb.device.conn;
280     if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
281         HIDD_TRACE_WARNING("%s: unknown cid", __func__);
282         return;
283     }
284     if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_DEV_MTU_SIZE))
285         p_hcon->rem_mtu_size = HID_DEV_MTU_SIZE;
286     else
287         p_hcon->rem_mtu_size = p_cfg->mtu;
288     // accept without changes
289     p_cfg->flush_to_present = FALSE;
290     p_cfg->mtu_present = FALSE;
291     p_cfg->result = L2CAP_CFG_OK;
292     if (cid == p_hcon->intr_cid && hd_cb.use_in_qos && !p_cfg->qos_present) {
293         p_cfg->qos_present = TRUE;
294         memcpy(&p_cfg->qos, &hd_cb.in_qos, sizeof(FLOW_SPEC));
295     }
296     L2CA_ConfigRsp(cid, p_cfg);
297     // update flags
298     if (cid == p_hcon->ctrl_cid) {
299         p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
300         if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) {
301             p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
302             if ((p_hcon->intr_cid = L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
303                 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
304                 hidd_conn_disconnect();
305                 HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR", __func__);
306                 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL);
307                 return;
308             } else {
309                 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
310             }
311         }
312     } else {
313         p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
314     }
315     hidd_check_config_done();
316 }
317 /*******************************************************************************
318  *
319  * Function         hidd_l2cif_config_cfm
320  *
321  * Description      Handles incoming L2CAP configuration response
322  *
323  * Returns          void
324  *
325  ******************************************************************************/
hidd_l2cif_config_cfm(uint16_t cid,tL2CAP_CFG_INFO * p_cfg)326 static void hidd_l2cif_config_cfm(uint16_t cid, tL2CAP_CFG_INFO *p_cfg)
327 {
328     tHID_CONN *p_hcon;
329     uint32_t reason;
330     HIDD_TRACE_EVENT("%s: cid=%04x pcfg->result=%d", __func__, cid, p_cfg->result);
331     p_hcon = &hd_cb.device.conn;
332     if (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid) {
333         HIDD_TRACE_WARNING("%s: unknown cid", __func__);
334         return;
335     }
336     if (p_hcon->intr_cid == cid && p_cfg->result == L2CAP_CFG_UNACCEPTABLE_PARAMS && p_cfg->qos_present) {
337         tL2CAP_CFG_INFO new_qos;
338         // QoS parameters not accepted for intr, try again with host proposal
339         memcpy(&new_qos, &hd_cb.l2cap_intr_cfg, sizeof(new_qos));
340         memcpy(&new_qos.qos, &p_cfg->qos, sizeof(FLOW_SPEC));
341         new_qos.qos_present = TRUE;
342         HIDD_TRACE_WARNING("%s: config failed, retry", __func__);
343         L2CA_ConfigReq(cid, &new_qos);
344         return;
345     } else if (p_hcon->intr_cid == cid && p_cfg->result == L2CAP_CFG_UNKNOWN_OPTIONS) {
346         // QoS not understood by remote device, try configuring without QoS
347         HIDD_TRACE_WARNING("%s: config failed, retry without QoS", __func__);
348         L2CA_ConfigReq(cid, &hd_cb.l2cap_cfg);
349         return;
350     } else if (p_cfg->result != L2CAP_CFG_OK) {
351         HIDD_TRACE_WARNING("%s: config failed, disconnecting", __func__);
352         hidd_conn_disconnect();
353         reason = HID_L2CAP_CFG_FAIL | (uint32_t)p_cfg->result;
354         hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, reason, NULL);
355         return;
356     }
357     // update flags
358     if (cid == p_hcon->ctrl_cid) {
359         p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
360         if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) && (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) {
361             p_hcon->disc_reason = HID_L2CAP_CONN_FAIL;
362             if ((p_hcon->intr_cid = L2CA_ConnectReq(HID_PSM_INTERRUPT, hd_cb.device.addr)) == 0) {
363                 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
364                 hidd_conn_disconnect();
365                 HIDD_TRACE_WARNING("%s: could not start L2CAP connection for INTR", __func__);
366                 hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL);
367                 return;
368             } else {
369                 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
370             }
371         }
372     } else {
373         p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
374     }
375     hidd_check_config_done();
376 }
377 /*******************************************************************************
378  *
379  * Function         hidd_l2cif_disconnect_ind
380  *
381  * Description      Handler incoming L2CAP disconnection request
382  *
383  * Returns          void
384  *
385  ******************************************************************************/
hidd_l2cif_disconnect_ind(uint16_t cid,bool ack_needed)386 static void hidd_l2cif_disconnect_ind(uint16_t cid, bool ack_needed)
387 {
388     tHID_CONN *p_hcon;
389     HIDD_TRACE_EVENT("%s: cid=%04x ack_needed=%d", __func__, cid, ack_needed);
390     p_hcon = &hd_cb.device.conn;
391     if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
392         HIDD_TRACE_WARNING("%s: unknown cid", __func__);
393         return;
394     }
395     if (ack_needed)
396         L2CA_DisconnectRsp(cid);
397     if (cid == p_hcon->ctrl_cid) {
398         p_hcon->ctrl_cid = 0;
399         p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_CTRL;
400     } else {
401         p_hcon->intr_cid = 0;
402         p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_INTR;
403     }
404     if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
405         HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
406         // clean any outstanding data on intr
407         if (hd_cb.pending_data) {
408             osi_free(hd_cb.pending_data);
409             hd_cb.pending_data = NULL;
410         }
411         hd_cb.device.state = HIDD_DEV_NO_CONN;
412         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
413         hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, p_hcon->disc_reason, NULL);
414     }
415 }
416 /*******************************************************************************
417  *
418  * Function         hidd_l2cif_disconnect_cfm
419  *
420  * Description      Handles L2CAP disconection response
421  *
422  * Returns          void
423  *
424  ******************************************************************************/
hidd_l2cif_disconnect_cfm(uint16_t cid,uint16_t result)425 static void hidd_l2cif_disconnect_cfm(uint16_t cid, uint16_t result)
426 {
427     tHID_CONN *p_hcon;
428     HIDD_TRACE_EVENT("%s: cid=%04x result=%d", __func__, cid, result);
429     p_hcon = &hd_cb.device.conn;
430     if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
431         HIDD_TRACE_WARNING("%s: unknown cid", __func__);
432         return;
433     }
434     if (cid == p_hcon->ctrl_cid) {
435         p_hcon->ctrl_cid = 0;
436     } else {
437         p_hcon->intr_cid = 0;
438         // now disconnect CTRL
439         L2CA_DisconnectReq(p_hcon->ctrl_cid);
440     }
441     if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
442         HIDD_TRACE_EVENT("%s: INTR and CTRL disconnected", __func__);
443         hd_cb.device.state = HIDD_DEV_NO_CONN;
444         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
445         if (hd_cb.pending_vc_unplug) {
446             hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_VC_UNPLUG, p_hcon->disc_reason, NULL);
447             hd_cb.pending_vc_unplug = FALSE;
448         } else {
449             hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, p_hcon->disc_reason, NULL);
450         }
451     }
452 }
453 /*******************************************************************************
454  *
455  * Function         hidd_l2cif_cong_ind
456  *
457  * Description      Handles L2CAP congestion status event
458  *
459  * Returns          void
460  *
461  ******************************************************************************/
hidd_l2cif_cong_ind(uint16_t cid,bool congested)462 static void hidd_l2cif_cong_ind(uint16_t cid, bool congested)
463 {
464     tHID_CONN *p_hcon;
465     HIDD_TRACE_EVENT("%s: cid=%04x congested=%d", __func__, cid, congested);
466     p_hcon = &hd_cb.device.conn;
467     if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
468         HIDD_TRACE_WARNING("%s: unknown cid", __func__);
469         return;
470     }
471     if (congested) {
472         p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
473     } else {
474         p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
475     }
476 }
477 /*******************************************************************************
478  *
479  * Function         hidd_l2cif_data_ind
480  *
481  * Description      Handler incoming data on L2CAP channel
482  *
483  * Returns          void
484  *
485  ******************************************************************************/
hidd_l2cif_data_ind(uint16_t cid,BT_HDR * p_msg)486 static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR *p_msg)
487 {
488     tHID_CONN *p_hcon;
489     uint8_t *p_data = (uint8_t *)(p_msg + 1) + p_msg->offset;
490     uint8_t msg_type, param;
491     bool err = FALSE;
492     HIDD_TRACE_EVENT("%s: cid=%04x", __func__, cid);
493     p_hcon = &hd_cb.device.conn;
494     if (p_hcon->conn_state == HID_CONN_STATE_UNUSED || (p_hcon->ctrl_cid != cid && p_hcon->intr_cid != cid)) {
495         HIDD_TRACE_WARNING("%s: unknown cid", __func__);
496         osi_free(p_msg);
497         return;
498     }
499     msg_type = HID_GET_TRANS_FROM_HDR(*p_data);
500     param = HID_GET_PARAM_FROM_HDR(*p_data);
501     if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
502         // skip HID header
503         p_msg->offset++;
504         p_msg->len--;
505         hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_INTR_DATA, 0, p_msg);
506         return;
507     }
508     switch (msg_type) {
509     case HID_TRANS_GET_REPORT:
510         // at this stage we don't know if Report Id shall be included in request
511         // so we pass complete packet in callback and let other code analyze this
512         hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_GET_REPORT, !!(param & HID_PAR_GET_REP_BUFSIZE_FOLLOWS), p_msg);
513         break;
514     case HID_TRANS_SET_REPORT:
515         // as above
516         hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_REPORT, 0, p_msg);
517         break;
518     case HID_TRANS_GET_IDLE:
519         hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, HID_PAR_REP_TYPE_OTHER, hd_cb.device.idle_time, 0, NULL);
520         osi_free(p_msg);
521         break;
522     case HID_TRANS_SET_IDLE:
523         if (p_msg->len != 2) {
524             HIDD_TRACE_ERROR("%s: invalid len (%d) set idle request received", __func__, p_msg->len);
525             err = TRUE;
526         } else {
527             hd_cb.device.idle_time = p_data[1];
528             HIDD_TRACE_DEBUG("%s: idle_time = %d", __func__, hd_cb.device.idle_time);
529             if (hd_cb.device.idle_time) {
530                 HIDD_TRACE_WARNING("%s: idle_time of %d ms not supported by HID Device", __func__,
531                                    (hd_cb.device.idle_time * 4));
532                 err = TRUE;
533             }
534         }
535         if (!err) {
536             hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_SUCCESS, 0, 0, NULL);
537         } else {
538             hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_ERR_INVALID_PARAM, 0, 0, NULL);
539         }
540         osi_free(p_msg);
541         break;
542     case HID_TRANS_GET_PROTOCOL:
543         hidd_conn_send_data(HID_CHANNEL_CTRL, HID_TRANS_DATA, HID_PAR_REP_TYPE_OTHER, !hd_cb.device.boot_mode, 0, NULL);
544         osi_free(p_msg);
545         break;
546     case HID_TRANS_SET_PROTOCOL:
547         hd_cb.device.boot_mode = !(param & HID_PAR_PROTOCOL_MASK);
548         hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SET_PROTOCOL, param & HID_PAR_PROTOCOL_MASK, NULL);
549         hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_SUCCESS, 0, 0, NULL);
550         osi_free(p_msg);
551         break;
552     case HID_TRANS_CONTROL:
553         switch (param) {
554         case HID_PAR_CONTROL_SUSPEND:
555             hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_SUSPEND, 0, NULL);
556             break;
557         case HID_PAR_CONTROL_EXIT_SUSPEND:
558             hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_EXIT_SUSPEND, 0, NULL);
559             break;
560         case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
561             hidd_conn_disconnect();
562             // set flag so we can notify properly when disconnected
563             hd_cb.pending_vc_unplug = TRUE;
564             break;
565         }
566         osi_free(p_msg);
567         break;
568     case HID_TRANS_DATA:
569     default:
570         HIDD_TRACE_WARNING("%s: got unsupported msg (%d)", __func__, msg_type);
571         hidd_conn_send_data(0, HID_TRANS_HANDSHAKE, HID_PAR_HANDSHAKE_RSP_ERR_UNSUPPORTED_REQ, 0, 0, NULL);
572         osi_free(p_msg);
573         break;
574     }
575 }
576 /*******************************************************************************
577  *
578  * Function         hidd_conn_reg
579  *
580  * Description      Registers L2CAP channels
581  *
582  * Returns          void
583  *
584  ******************************************************************************/
hidd_conn_reg(void)585 tHID_STATUS hidd_conn_reg(void)
586 {
587     HIDD_TRACE_API("%s", __func__);
588     memset(&hd_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
589     hd_cb.l2cap_cfg.mtu_present = TRUE;
590     hd_cb.l2cap_cfg.mtu = HID_DEV_MTU_SIZE;
591     hd_cb.l2cap_cfg.flush_to_present = TRUE;
592     hd_cb.l2cap_cfg.flush_to = HID_DEV_FLUSH_TO;
593     memset(&hd_cb.l2cap_intr_cfg, 0, sizeof(tL2CAP_CFG_INFO));
594     hd_cb.l2cap_intr_cfg.mtu_present = TRUE;
595     hd_cb.l2cap_intr_cfg.mtu = HID_DEV_MTU_SIZE;
596     hd_cb.l2cap_intr_cfg.flush_to_present = TRUE;
597     hd_cb.l2cap_intr_cfg.flush_to = HID_DEV_FLUSH_TO;
598     if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO *)&dev_reg_info)) {
599         HIDD_TRACE_ERROR("HID Control (device) registration failed");
600         return (HID_ERR_L2CAP_FAILED);
601     }
602     if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO *)&dev_reg_info)) {
603         L2CA_Deregister(HID_PSM_CONTROL);
604         HIDD_TRACE_ERROR("HID Interrupt (device) registration failed");
605         return (HID_ERR_L2CAP_FAILED);
606     }
607     return (HID_SUCCESS);
608 }
609 /*******************************************************************************
610  *
611  * Function         hidd_conn_dereg
612  *
613  * Description      Deregisters L2CAP channels
614  *
615  * Returns          void
616  *
617  ******************************************************************************/
hidd_conn_dereg(void)618 void hidd_conn_dereg(void)
619 {
620     HIDD_TRACE_API("%s", __func__);
621     L2CA_Deregister(HID_PSM_CONTROL);
622     L2CA_Deregister(HID_PSM_INTERRUPT);
623 }
624 /*******************************************************************************
625  *
626  * Function         hidd_conn_initiate
627  *
628  * Description      Initiates HID connection to plugged device
629  *
630  * Returns          HID_SUCCESS
631  *
632  ******************************************************************************/
hidd_conn_initiate(void)633 tHID_STATUS hidd_conn_initiate(void)
634 {
635     tHID_DEV_DEV_CTB *p_dev = &hd_cb.device;
636     HIDD_TRACE_API("%s", __func__);
637     if (!p_dev->in_use) {
638         HIDD_TRACE_WARNING("%s: no virtual cable established", __func__);
639         return (HID_ERR_NOT_REGISTERED);
640     }
641     if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED) {
642         HIDD_TRACE_WARNING("%s: connection already in progress", __func__);
643         return (HID_ERR_CONN_IN_PROCESS);
644     }
645     p_dev->conn.ctrl_cid = 0;
646     p_dev->conn.intr_cid = 0;
647     p_dev->conn.disc_reason = HID_L2CAP_CONN_FAIL;
648     p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
649     BTM_SetOutService(p_dev->addr, BTM_SEC_SERVICE_HIDD_SEC_CTRL, HIDD_SEC_CHN);
650     /* Check if L2CAP started the connection process */
651     if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq(HID_PSM_CONTROL, p_dev->addr)) == 0) {
652         HIDD_TRACE_WARNING("%s: could not start L2CAP connection", __func__);
653         hd_cb.callback(hd_cb.device.addr, HID_DHOST_EVT_CLOSE, HID_ERR_L2CAP_FAILED, NULL);
654     } else {
655         p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
656     }
657     return (HID_SUCCESS);
658 }
659 /*******************************************************************************
660  *
661  * Function         hidd_conn_disconnect
662  *
663  * Description      Disconnects existing HID connection
664  *
665  * Returns          HID_SUCCESS
666  *
667  ******************************************************************************/
hidd_conn_disconnect(void)668 tHID_STATUS hidd_conn_disconnect(void)
669 {
670     tHID_CONN *p_hcon;
671     HIDD_TRACE_API("%s", __func__);
672     // clean any outstanding data on intr
673     if (hd_cb.pending_data) {
674         osi_free(hd_cb.pending_data);
675         hd_cb.pending_data = NULL;
676     }
677     p_hcon = &hd_cb.device.conn;
678     if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
679         /* Set l2cap idle timeout to 0 (so ACL link is disconnected
680          * immediately after last channel is closed) */
681         L2CA_SetIdleTimeoutByBdAddr(hd_cb.device.addr, 0, BT_TRANSPORT_BR_EDR);
682         if (p_hcon->intr_cid) {
683             p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_INTR;
684             L2CA_DisconnectReq(p_hcon->intr_cid);
685         } else if (p_hcon->ctrl_cid) {
686             p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING_CTRL;
687             L2CA_DisconnectReq(p_hcon->ctrl_cid);
688         }
689     } else {
690         HIDD_TRACE_WARNING("%s: already disconnected", __func__);
691         p_hcon->conn_state = HID_CONN_STATE_UNUSED;
692     }
693     return (HID_SUCCESS);
694 }
695 /*******************************************************************************
696  *
697  * Function         hidd_conn_send_data
698  *
699  * Description      Sends data to host
700  *
701  * Returns          tHID_STATUS
702  *
703  ******************************************************************************/
hidd_conn_send_data(uint8_t channel,uint8_t msg_type,uint8_t param,uint8_t data,uint16_t len,uint8_t * p_data)704 tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param, uint8_t data, uint16_t len,
705                                 uint8_t *p_data)
706 {
707     tHID_CONN *p_hcon;
708     BT_HDR *p_buf;
709     uint8_t *p_out;
710     uint16_t cid;
711     uint16_t buf_size;
712     HIDD_TRACE_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__, channel, msg_type, len);
713     p_hcon = &hd_cb.device.conn;
714     if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
715         return HID_ERR_CONGESTED;
716     }
717     switch (msg_type) {
718     case HID_TRANS_HANDSHAKE:
719     case HID_TRANS_CONTROL:
720         cid = p_hcon->ctrl_cid;
721         buf_size = HID_CONTROL_BUF_SIZE;
722         break;
723     case HID_TRANS_DATA:
724         if (channel == HID_CHANNEL_CTRL) {
725             cid = p_hcon->ctrl_cid;
726             buf_size = HID_CONTROL_BUF_SIZE;
727         } else {
728             cid = p_hcon->intr_cid;
729             buf_size = HID_INTERRUPT_BUF_SIZE;
730         }
731         break;
732     default:
733         return (HID_ERR_INVALID_PARAM);
734     }
735     p_buf = (BT_HDR *)osi_malloc(buf_size);
736     if (p_buf == NULL)
737         return (HID_ERR_NO_RESOURCES);
738     p_buf->offset = L2CAP_MIN_OFFSET;
739     p_out = (uint8_t *)(p_buf + 1) + p_buf->offset;
740     *p_out = HID_BUILD_HDR(msg_type, param);
741     p_out++;
742     p_buf->len = 1; // start with header only
743     // add report id prefix only if non-zero (which is reserved)
744     if (msg_type == HID_TRANS_DATA && (data || param == HID_PAR_REP_TYPE_OTHER)) {
745         *p_out = data; // report_id
746         p_out++;
747         p_buf->len++;
748     }
749     if (len > 0 && p_data != NULL) {
750         memcpy(p_out, p_data, len);
751         p_buf->len += len;
752     }
753     // check if connected
754     if (hd_cb.device.state != HIDD_DEV_CONNECTED) {
755         // for DATA on intr we hold transfer and try to reconnect
756         if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) {
757             // drop previous data, we do not queue it for now
758             if (hd_cb.pending_data) {
759                 osi_free(hd_cb.pending_data);
760             }
761             hd_cb.pending_data = p_buf;
762             if (hd_cb.device.conn.conn_state == HID_CONN_STATE_UNUSED) {
763                 hidd_conn_initiate();
764             }
765             return HID_SUCCESS;
766         }
767         return HID_ERR_NO_CONNECTION;
768     }
769 #ifdef REPORT_TRANSFER_TIMESTAMP
770     if (report_transfer) {
771         HIDD_TRACE_ERROR("%s: report sent", __func__);
772     }
773 #endif
774     HIDD_TRACE_VERBOSE("%s: report sent", __func__);
775     if (!L2CA_DataWrite(cid, p_buf))
776         return (HID_ERR_CONGESTED);
777     return (HID_SUCCESS);
778 }
779 
780 #endif
781