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