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