1 /******************************************************************************
2 *
3 * Copyright (C) 2002-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /******************************************************************************
20 *
21 * this file contains the connection interface functions
22 *
23 ******************************************************************************/
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "bt_common.h"
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 "hidh_api.h"
43 #include "hidh_int.h"
44
45 #include "log/log.h"
46 #include "osi/include/osi.h"
47
48 static uint8_t find_conn_by_cid(uint16_t cid);
49 static void hidh_conn_retry(uint8_t dhandle);
50
51 /******************************************************************************/
52 /* L O C A L F U N C T I O N P R O T O T Y P E S */
53 /******************************************************************************/
54 static void hidh_l2cif_connect_ind(const RawAddress& bd_addr,
55 uint16_t l2cap_cid, uint16_t psm,
56 uint8_t l2cap_id);
57 static void hidh_l2cif_connect_cfm(uint16_t l2cap_cid, uint16_t result);
58 static void hidh_l2cif_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
59 static void hidh_l2cif_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg);
60 static void hidh_l2cif_disconnect_ind(uint16_t l2cap_cid, bool ack_needed);
61 static void hidh_l2cif_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg);
62 static void hidh_l2cif_disconnect_cfm(uint16_t l2cap_cid, uint16_t result);
63 static void hidh_l2cif_cong_ind(uint16_t l2cap_cid, bool congested);
64
65 static const tL2CAP_APPL_INFO hst_reg_info = {
66 hidh_l2cif_connect_ind,
67 hidh_l2cif_connect_cfm,
68 NULL,
69 hidh_l2cif_config_ind,
70 hidh_l2cif_config_cfm,
71 hidh_l2cif_disconnect_ind,
72 hidh_l2cif_disconnect_cfm,
73 NULL,
74 hidh_l2cif_data_ind,
75 hidh_l2cif_cong_ind,
76 NULL /* tL2CA_TX_COMPLETE_CB */
77 };
78
79 /*******************************************************************************
80 *
81 * Function hidh_l2cif_reg
82 *
83 * Description This function initializes the SDP unit.
84 *
85 * Returns void
86 *
87 ******************************************************************************/
hidh_conn_reg(void)88 tHID_STATUS hidh_conn_reg(void) {
89 int xx;
90
91 /* Initialize the L2CAP configuration. We only care about MTU and flush */
92 memset(&hh_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
93
94 hh_cb.l2cap_cfg.mtu_present = true;
95 hh_cb.l2cap_cfg.mtu = HID_HOST_MTU;
96 hh_cb.l2cap_cfg.flush_to_present = true;
97 hh_cb.l2cap_cfg.flush_to = HID_HOST_FLUSH_TO;
98
99 /* Now, register with L2CAP */
100 if (!L2CA_Register(HID_PSM_CONTROL, (tL2CAP_APPL_INFO*)&hst_reg_info)) {
101 HIDH_TRACE_ERROR("HID-Host Control Registration failed");
102 return (HID_ERR_L2CAP_FAILED);
103 }
104 if (!L2CA_Register(HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO*)&hst_reg_info)) {
105 L2CA_Deregister(HID_PSM_CONTROL);
106 HIDH_TRACE_ERROR("HID-Host Interrupt Registration failed");
107 return (HID_ERR_L2CAP_FAILED);
108 }
109
110 for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++) {
111 hh_cb.devices[xx].in_use = false;
112 hh_cb.devices[xx].conn.conn_state = HID_CONN_STATE_UNUSED;
113 }
114
115 return (HID_SUCCESS);
116 }
117
118 /*******************************************************************************
119 *
120 * Function hidh_conn_disconnect
121 *
122 * Description This function disconnects a connection.
123 *
124 * Returns true if disconnect started, false if already disconnected
125 *
126 ******************************************************************************/
hidh_conn_disconnect(uint8_t dhandle)127 tHID_STATUS hidh_conn_disconnect(uint8_t dhandle) {
128 tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn;
129
130 HIDH_TRACE_EVENT("HID-Host disconnect");
131
132 if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) {
133 p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
134
135 /* Set l2cap idle timeout to 0 (so ACL link is disconnected
136 * immediately after last channel is closed) */
137 L2CA_SetIdleTimeoutByBdAddr(hh_cb.devices[dhandle].addr, 0,
138 BT_TRANSPORT_BR_EDR);
139 /* Disconnect both interrupt and control channels */
140 if (p_hcon->intr_cid)
141 L2CA_DisconnectReq(p_hcon->intr_cid);
142 else if (p_hcon->ctrl_cid)
143 L2CA_DisconnectReq(p_hcon->ctrl_cid);
144 } else {
145 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
146 }
147
148 return (HID_SUCCESS);
149 }
150
151 /*******************************************************************************
152 *
153 * Function hidh_sec_check_complete_term
154 *
155 * Description HID security check complete callback function.
156 *
157 * Returns Send L2CA_ConnectRsp OK if secutiry check succeed; otherwise
158 * send security block L2C connection response.
159 *
160 ******************************************************************************/
hidh_sec_check_complete_term(UNUSED_ATTR const RawAddress * bd_addr,UNUSED_ATTR tBT_TRANSPORT transport,void * p_ref_data,uint8_t res)161 void hidh_sec_check_complete_term(UNUSED_ATTR const RawAddress* bd_addr,
162 UNUSED_ATTR tBT_TRANSPORT transport,
163 void* p_ref_data, uint8_t res) {
164 tHID_HOST_DEV_CTB* p_dev = (tHID_HOST_DEV_CTB*)p_ref_data;
165
166 if (res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) {
167 p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset
168 disc_reason (from
169 HID_ERR_AUTH_FAILED) */
170
171 p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
172
173 /* Send response to the L2CAP layer. */
174 L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid,
175 L2CAP_CONN_OK, L2CAP_CONN_OK);
176
177 /* Send a Configuration Request. */
178 L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
179
180 }
181 /* security check fail */
182 else if (res != BTM_SUCCESS) {
183 p_dev->conn.disc_reason =
184 HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */
185 p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
186 L2CA_ConnectRsp(p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid,
187 L2CAP_CONN_SECURITY_BLOCK, L2CAP_CONN_OK);
188 }
189 }
190
191 /*******************************************************************************
192 *
193 * Function hidh_l2cif_connect_ind
194 *
195 * Description This function handles an inbound connection indication
196 * from L2CAP. This is the case where we are acting as a
197 * server.
198 *
199 * Returns void
200 *
201 ******************************************************************************/
hidh_l2cif_connect_ind(const RawAddress & bd_addr,uint16_t l2cap_cid,uint16_t psm,uint8_t l2cap_id)202 static void hidh_l2cif_connect_ind(const RawAddress& bd_addr,
203 uint16_t l2cap_cid, uint16_t psm,
204 uint8_t l2cap_id) {
205 tHID_CONN* p_hcon;
206 bool bAccept = true;
207 uint8_t i = HID_HOST_MAX_DEVICES;
208 tHID_HOST_DEV_CTB* p_dev;
209
210 HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP conn ind, PSM: 0x%04x CID 0x%x", psm,
211 l2cap_cid);
212
213 /* always add incoming connection device into HID database by default */
214 if (HID_HostAddDev(bd_addr, HID_SEC_REQUIRED, &i) != HID_SUCCESS) {
215 L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_SECURITY_BLOCK, 0);
216 return;
217 }
218
219 p_hcon = &hh_cb.devices[i].conn;
220 p_dev = &hh_cb.devices[i];
221
222 /* Check we are in the correct state for this */
223 if (psm == HID_PSM_INTERRUPT) {
224 if (p_hcon->ctrl_cid == 0) {
225 HIDH_TRACE_WARNING(
226 "HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel");
227 bAccept = false;
228 }
229 if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) {
230 HIDH_TRACE_WARNING("HID-Host Rcvd INTR L2CAP conn ind, wrong state: %d",
231 p_hcon->conn_state);
232 bAccept = false;
233 }
234 } else /* CTRL channel */
235 {
236 #if (HID_HOST_ACPT_NEW_CONN == TRUE)
237 p_hcon->ctrl_cid = p_hcon->intr_cid = 0;
238 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
239 #else
240 if (p_hcon->conn_state != HID_CONN_STATE_UNUSED) {
241 HIDH_TRACE_WARNING("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: %d",
242 p_hcon->conn_state);
243 bAccept = false;
244 }
245 #endif
246 }
247
248 if (!bAccept) {
249 L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_RESOURCES, 0);
250 return;
251 }
252
253 if (psm == HID_PSM_CONTROL) {
254 p_hcon->conn_flags = 0;
255 p_hcon->ctrl_cid = l2cap_cid;
256 p_hcon->ctrl_id = l2cap_id;
257 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs
258 before security is completed,
259 then set CLOSE_EVT reason code
260 to 'connection failure' */
261
262 p_hcon->conn_state = HID_CONN_STATE_SECURITY;
263 if (btm_sec_mx_access_request(
264 p_dev->addr, HID_PSM_CONTROL, false, BTM_SEC_PROTO_HID,
265 (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
266 &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED) {
267 L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING,
268 L2CAP_CONN_OK);
269 }
270
271 return;
272 }
273
274 /* Transition to the next appropriate state, configuration */
275 p_hcon->conn_state = HID_CONN_STATE_CONFIG;
276 p_hcon->intr_cid = l2cap_cid;
277
278 /* Send response to the L2CAP layer. */
279 L2CA_ConnectRsp(bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
280
281 /* Send a Configuration Request. */
282 L2CA_ConfigReq(l2cap_cid, &hh_cb.l2cap_cfg);
283
284 HIDH_TRACE_EVENT(
285 "HID-Host Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x CID 0x%x",
286 psm, l2cap_cid);
287 }
288
hidh_process_repage_timer_timeout(void * data)289 void hidh_process_repage_timer_timeout(void* data) {
290 uint8_t dhandle = PTR_TO_UINT(data);
291 hidh_try_repage(dhandle);
292 }
293
294 /*******************************************************************************
295 *
296 * Function hidh_try_repage
297 *
298 * Description This function processes timeout (to page device).
299 *
300 * Returns void
301 *
302 ******************************************************************************/
hidh_try_repage(uint8_t dhandle)303 void hidh_try_repage(uint8_t dhandle) {
304 tHID_HOST_DEV_CTB* device;
305
306 hidh_conn_initiate(dhandle);
307
308 device = &hh_cb.devices[dhandle];
309 device->conn_tries++;
310
311 hh_cb.callback(dhandle, device->addr, HID_HDEV_EVT_RETRYING,
312 device->conn_tries, NULL);
313 }
314
315 /*******************************************************************************
316 *
317 * Function hidh_sec_check_complete_orig
318 *
319 * Description This function checks to see if security procedures are being
320 * carried out or not..
321 *
322 * Returns void
323 *
324 ******************************************************************************/
hidh_sec_check_complete_orig(UNUSED_ATTR const RawAddress * bd_addr,UNUSED_ATTR tBT_TRANSPORT transport,void * p_ref_data,uint8_t res)325 void hidh_sec_check_complete_orig(UNUSED_ATTR const RawAddress* bd_addr,
326 UNUSED_ATTR tBT_TRANSPORT transport,
327 void* p_ref_data, uint8_t res) {
328 tHID_HOST_DEV_CTB* p_dev = (tHID_HOST_DEV_CTB*)p_ref_data;
329 uint8_t dhandle;
330
331 // TODO(armansito): This kind of math to determine a device handle is way
332 // too dirty and unnecessary. Why can't |p_dev| store it's handle?
333 dhandle = (PTR_TO_UINT(p_dev) - PTR_TO_UINT(&(hh_cb.devices[0]))) /
334 sizeof(tHID_HOST_DEV_CTB);
335 if (res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) {
336 HIDH_TRACE_EVENT("HID-Host Originator security pass.");
337 p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset
338 disc_reason (from
339 HID_ERR_AUTH_FAILED) */
340
341 /* Transition to the next appropriate state, configuration */
342 p_dev->conn.conn_state = HID_CONN_STATE_CONFIG;
343 L2CA_ConfigReq(p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
344 HIDH_TRACE_EVENT("HID-Host Got Control conn cnf, sent cfg req, CID: 0x%x",
345 p_dev->conn.ctrl_cid);
346 }
347
348 if (res != BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY) {
349 #if (HID_HOST_MAX_CONN_RETRY > 0)
350 if (res == BTM_DEVICE_TIMEOUT) {
351 if (p_dev->conn_tries <= HID_HOST_MAX_CONN_RETRY) {
352 hidh_conn_retry(dhandle);
353 return;
354 }
355 }
356 #endif
357 p_dev->conn.disc_reason =
358 HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */
359 hidh_conn_disconnect(dhandle);
360 }
361 }
362
363 /*******************************************************************************
364 *
365 * Function hidh_l2cif_connect_cfm
366 *
367 * Description This function handles the connect confirm events
368 * from L2CAP. This is the case when we are acting as a
369 * client and have sent a connect request.
370 *
371 * Returns void
372 *
373 ******************************************************************************/
hidh_l2cif_connect_cfm(uint16_t l2cap_cid,uint16_t result)374 static void hidh_l2cif_connect_cfm(uint16_t l2cap_cid, uint16_t result) {
375 uint8_t dhandle;
376 tHID_CONN* p_hcon = NULL;
377 uint32_t reason;
378 tHID_HOST_DEV_CTB* p_dev = NULL;
379
380 /* Find CCB based on CID, and verify we are in a state to accept this message
381 */
382 dhandle = find_conn_by_cid(l2cap_cid);
383 if (dhandle < HID_HOST_MAX_DEVICES) {
384 p_dev = &hh_cb.devices[dhandle];
385 p_hcon = &hh_cb.devices[dhandle].conn;
386 }
387
388 if ((p_hcon == NULL) || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG)) ||
389 ((l2cap_cid == p_hcon->ctrl_cid) &&
390 (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL)) ||
391 ((l2cap_cid == p_hcon->intr_cid) &&
392 (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR) &&
393 (p_hcon->conn_state != HID_CONN_STATE_DISCONNECTING))) {
394 HIDH_TRACE_WARNING("HID-Host Rcvd unexpected conn cnf, CID 0x%x ",
395 l2cap_cid);
396 return;
397 }
398
399 if (result != L2CAP_CONN_OK) {
400 if (l2cap_cid == p_hcon->ctrl_cid)
401 p_hcon->ctrl_cid = 0;
402 else
403 p_hcon->intr_cid = 0;
404
405 hidh_conn_disconnect(dhandle);
406
407 #if (HID_HOST_MAX_CONN_RETRY > 0)
408 if ((hh_cb.devices[dhandle].conn_tries <= HID_HOST_MAX_CONN_RETRY) &&
409 (result == HCI_ERR_CONNECTION_TOUT || result == HCI_ERR_UNSPECIFIED ||
410 result == HCI_ERR_PAGE_TIMEOUT)) {
411 hidh_conn_retry(dhandle);
412 } else
413 #endif
414 {
415 reason = HID_L2CAP_CONN_FAIL | (uint32_t)result;
416 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
417 reason, NULL);
418 }
419 return;
420 }
421 /* receive Control Channel connect confirmation */
422 if (l2cap_cid == p_hcon->ctrl_cid) {
423 /* check security requirement */
424 p_hcon->conn_state = HID_CONN_STATE_SECURITY;
425 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* In case disconnection occurs
426 before security is completed,
427 then set CLOSE_EVT reason code
428 to "connection failure" */
429
430 btm_sec_mx_access_request(
431 p_dev->addr, HID_PSM_CONTROL, true, BTM_SEC_PROTO_HID,
432 (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
433 &hidh_sec_check_complete_orig, p_dev);
434 } else {
435 p_hcon->conn_state = HID_CONN_STATE_CONFIG;
436 /* Send a Configuration Request. */
437 L2CA_ConfigReq(l2cap_cid, &hh_cb.l2cap_cfg);
438 HIDH_TRACE_EVENT("HID-Host got Interrupt conn cnf, sent cfg req, CID: 0x%x",
439 l2cap_cid);
440 }
441
442 return;
443 }
444
445 /*******************************************************************************
446 *
447 * Function hidh_l2cif_config_ind
448 *
449 * Description This function processes the L2CAP configuration indication
450 * event.
451 *
452 * Returns void
453 *
454 ******************************************************************************/
hidh_l2cif_config_ind(uint16_t l2cap_cid,tL2CAP_CFG_INFO * p_cfg)455 static void hidh_l2cif_config_ind(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
456 uint8_t dhandle;
457 tHID_CONN* p_hcon = NULL;
458 uint32_t reason;
459
460 /* Find CCB based on CID */
461 dhandle = find_conn_by_cid(l2cap_cid);
462 if (dhandle < HID_HOST_MAX_DEVICES) {
463 p_hcon = &hh_cb.devices[dhandle].conn;
464 }
465
466 if (p_hcon == NULL) {
467 HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x",
468 l2cap_cid);
469 return;
470 }
471
472 HIDH_TRACE_EVENT("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
473
474 /* Remember the remote MTU size */
475 if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_HOST_MTU))
476 p_hcon->rem_mtu_size = HID_HOST_MTU;
477 else
478 p_hcon->rem_mtu_size = p_cfg->mtu;
479
480 /* For now, always accept configuration from the other side */
481 p_cfg->flush_to_present = false;
482 p_cfg->mtu_present = false;
483 p_cfg->result = L2CAP_CFG_OK;
484
485 L2CA_ConfigRsp(l2cap_cid, p_cfg);
486
487 if (l2cap_cid == p_hcon->ctrl_cid) {
488 p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
489 if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
490 (p_hcon->conn_flags & HID_CONN_FLAGS_MY_CTRL_CFG_DONE)) {
491 /* Connect interrupt channel */
492 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for
493 CLOSE_EVT: Connection
494 Attempt was made but failed
495 */
496 p_hcon->intr_cid =
497 L2CA_ConnectReq(HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr);
498 if (p_hcon->intr_cid == 0) {
499 HIDH_TRACE_WARNING("HID-Host INTR Originate failed");
500 reason = HID_L2CAP_REQ_FAIL;
501 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
502 hidh_conn_disconnect(dhandle);
503 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
504 reason, NULL);
505 return;
506 } else {
507 /* Transition to the next appropriate state, waiting for connection
508 * confirm on interrupt channel. */
509 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
510 }
511 }
512 } else
513 p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
514
515 /* If all configuration is complete, change state and tell management we are
516 * up */
517 if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) ==
518 HID_CONN_FLAGS_ALL_CONFIGURED) &&
519 (p_hcon->conn_state == HID_CONN_STATE_CONFIG)) {
520 p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
521 /* Reset disconnect reason to success, as connection successful */
522 p_hcon->disc_reason = HID_SUCCESS;
523
524 hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
525 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0,
526 NULL);
527 }
528 }
529
530 /*******************************************************************************
531 *
532 * Function hidh_l2cif_config_cfm
533 *
534 * Description This function processes the L2CAP configuration confirmation
535 * event.
536 *
537 * Returns void
538 *
539 ******************************************************************************/
hidh_l2cif_config_cfm(uint16_t l2cap_cid,tL2CAP_CFG_INFO * p_cfg)540 static void hidh_l2cif_config_cfm(uint16_t l2cap_cid, tL2CAP_CFG_INFO* p_cfg) {
541 uint8_t dhandle;
542 tHID_CONN* p_hcon = NULL;
543 uint32_t reason;
544
545 HIDH_TRACE_EVENT("HID-Host Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid,
546 p_cfg->result);
547
548 /* Find CCB based on CID */
549 dhandle = find_conn_by_cid(l2cap_cid);
550 if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
551
552 if (p_hcon == NULL) {
553 HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x",
554 l2cap_cid);
555 return;
556 }
557
558 /* If configuration failed, disconnect the channel(s) */
559 if (p_cfg->result != L2CAP_CFG_OK) {
560 hidh_conn_disconnect(dhandle);
561 reason = HID_L2CAP_CFG_FAIL | (uint32_t)p_cfg->result;
562 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
563 reason, NULL);
564 return;
565 }
566
567 if (l2cap_cid == p_hcon->ctrl_cid) {
568 p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
569 if ((p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG) &&
570 (p_hcon->conn_flags & HID_CONN_FLAGS_HIS_CTRL_CFG_DONE)) {
571 /* Connect interrupt channel */
572 p_hcon->disc_reason = HID_L2CAP_CONN_FAIL; /* Reset initial reason for
573 CLOSE_EVT: Connection
574 Attempt was made but failed
575 */
576 p_hcon->intr_cid =
577 L2CA_ConnectReq(HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr);
578 if (p_hcon->intr_cid == 0) {
579 HIDH_TRACE_WARNING("HID-Host INTR Originate failed");
580 reason = HID_L2CAP_REQ_FAIL;
581 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
582 hidh_conn_disconnect(dhandle);
583 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
584 reason, NULL);
585 return;
586 } else {
587 /* Transition to the next appropriate state, waiting for connection
588 * confirm on interrupt channel. */
589 p_hcon->conn_state = HID_CONN_STATE_CONNECTING_INTR;
590 }
591 }
592 } else
593 p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
594
595 /* If all configuration is complete, change state and tell management we are
596 * up */
597 if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) ==
598 HID_CONN_FLAGS_ALL_CONFIGURED) &&
599 (p_hcon->conn_state == HID_CONN_STATE_CONFIG)) {
600 p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
601 /* Reset disconnect reason to success, as connection successful */
602 p_hcon->disc_reason = HID_SUCCESS;
603
604 hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
605 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0,
606 NULL);
607 }
608 }
609
610 /*******************************************************************************
611 *
612 * Function hidh_l2cif_disconnect_ind
613 *
614 * Description This function handles a disconnect event from L2CAP. If
615 * requested to, we ack the disconnect before dropping the CCB
616 *
617 * Returns void
618 *
619 ******************************************************************************/
hidh_l2cif_disconnect_ind(uint16_t l2cap_cid,bool ack_needed)620 static void hidh_l2cif_disconnect_ind(uint16_t l2cap_cid, bool ack_needed) {
621 uint8_t dhandle;
622 tHID_CONN* p_hcon = NULL;
623 uint16_t disc_res = HCI_SUCCESS;
624 uint16_t hid_close_evt_reason;
625
626 /* Find CCB based on CID */
627 dhandle = find_conn_by_cid(l2cap_cid);
628 if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
629
630 if (p_hcon == NULL) {
631 HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP disc, unknown CID: 0x%x",
632 l2cap_cid);
633 return;
634 }
635
636 if (ack_needed) L2CA_DisconnectRsp(l2cap_cid);
637
638 HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP disc, CID: 0x%x", l2cap_cid);
639
640 p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
641
642 if (l2cap_cid == p_hcon->ctrl_cid)
643 p_hcon->ctrl_cid = 0;
644 else
645 p_hcon->intr_cid = 0;
646
647 if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
648 hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
649 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
650
651 if (!ack_needed) disc_res = btm_get_acl_disc_reason_code();
652
653 #if (HID_HOST_MAX_CONN_RETRY > 0)
654 if ((disc_res == HCI_ERR_CONNECTION_TOUT ||
655 disc_res == HCI_ERR_UNSPECIFIED) &&
656 (!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) &&
657 (hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE)) {
658 hh_cb.devices[dhandle].conn_tries = 0;
659 period_ms_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
660 alarm_set_on_mloop(hh_cb.devices[dhandle].conn.process_repage_timer,
661 interval_ms, hidh_process_repage_timer_timeout,
662 UINT_TO_PTR(dhandle));
663 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
664 disc_res, NULL);
665 } else
666 #endif
667 {
668 /* Set reason code for HID_HDEV_EVT_CLOSE */
669 hid_close_evt_reason = p_hcon->disc_reason;
670
671 /* If we got baseband sent HCI_DISCONNECT_COMPLETE_EVT due to security
672 * failure, then set reason to HID_ERR_AUTH_FAILED */
673 if ((disc_res == HCI_ERR_AUTH_FAILURE) ||
674 (disc_res == HCI_ERR_KEY_MISSING) ||
675 (disc_res == HCI_ERR_HOST_REJECT_SECURITY) ||
676 (disc_res == HCI_ERR_PAIRING_NOT_ALLOWED) ||
677 (disc_res == HCI_ERR_UNIT_KEY_USED) ||
678 (disc_res == HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED) ||
679 (disc_res == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE) ||
680 (disc_res == HCI_ERR_REPEATED_ATTEMPTS)) {
681 hid_close_evt_reason = HID_ERR_AUTH_FAILED;
682 }
683
684 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
685 hid_close_evt_reason, NULL);
686 }
687 }
688 }
689
690 /*******************************************************************************
691 *
692 * Function hidh_l2cif_disconnect_cfm
693 *
694 * Description This function handles a disconnect confirm event from L2CAP.
695 *
696 * Returns void
697 *
698 ******************************************************************************/
hidh_l2cif_disconnect_cfm(uint16_t l2cap_cid,UNUSED_ATTR uint16_t result)699 static void hidh_l2cif_disconnect_cfm(uint16_t l2cap_cid,
700 UNUSED_ATTR uint16_t result) {
701 uint8_t dhandle;
702 tHID_CONN* p_hcon = NULL;
703
704 /* Find CCB based on CID */
705 dhandle = find_conn_by_cid(l2cap_cid);
706 if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
707
708 if (p_hcon == NULL) {
709 HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x%x",
710 l2cap_cid);
711 return;
712 }
713
714 HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP disc cfm, CID: 0x%x", l2cap_cid);
715
716 if (l2cap_cid == p_hcon->ctrl_cid)
717 p_hcon->ctrl_cid = 0;
718 else {
719 p_hcon->intr_cid = 0;
720 if (p_hcon->ctrl_cid) {
721 HIDH_TRACE_EVENT("HID-Host Initiating L2CAP Ctrl disconnection");
722 L2CA_DisconnectReq(p_hcon->ctrl_cid);
723 }
724 }
725
726 if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) {
727 hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
728 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
729 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
730 p_hcon->disc_reason, NULL);
731 }
732 }
733
734 /*******************************************************************************
735 *
736 * Function hidh_l2cif_cong_ind
737 *
738 * Description This function handles a congestion status event from L2CAP.
739 *
740 * Returns void
741 *
742 ******************************************************************************/
hidh_l2cif_cong_ind(uint16_t l2cap_cid,bool congested)743 static void hidh_l2cif_cong_ind(uint16_t l2cap_cid, bool congested) {
744 uint8_t dhandle;
745 tHID_CONN* p_hcon = NULL;
746
747 /* Find CCB based on CID */
748 dhandle = find_conn_by_cid(l2cap_cid);
749 if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
750
751 if (p_hcon == NULL) {
752 HIDH_TRACE_WARNING(
753 "HID-Host Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid);
754 return;
755 }
756
757 HIDH_TRACE_EVENT("HID-Host Rcvd L2CAP congestion status, CID: 0x%x Cong: %d",
758 l2cap_cid, congested);
759
760 if (congested)
761 p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
762 else {
763 p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
764 }
765 }
766
767 /*******************************************************************************
768 *
769 * Function hidh_l2cif_data_ind
770 *
771 * Description This function is called when data is received from L2CAP.
772 * if we are the originator of the connection, we are the SDP
773 * client, and the received message is queued up for the
774 * client.
775 *
776 * If we are the destination of the connection, we are the SDP
777 * server, so the message is passed to the server processing
778 * function.
779 *
780 * Returns void
781 *
782 ******************************************************************************/
hidh_l2cif_data_ind(uint16_t l2cap_cid,BT_HDR * p_msg)783 static void hidh_l2cif_data_ind(uint16_t l2cap_cid, BT_HDR* p_msg) {
784 uint8_t* p_data = (uint8_t*)(p_msg + 1) + p_msg->offset;
785 uint8_t ttype, param, rep_type, evt;
786 uint8_t dhandle;
787 tHID_CONN* p_hcon = NULL;
788
789 HIDH_TRACE_DEBUG("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x%04x]",
790 l2cap_cid);
791
792 /* Find CCB based on CID */
793 dhandle = find_conn_by_cid(l2cap_cid);
794 if (dhandle < HID_HOST_MAX_DEVICES) p_hcon = &hh_cb.devices[dhandle].conn;
795
796 if (p_hcon == NULL) {
797 HIDH_TRACE_WARNING("HID-Host Rcvd L2CAP data, unknown CID: 0x%x",
798 l2cap_cid);
799 osi_free(p_msg);
800 return;
801 }
802
803 if (p_msg->len < 1) {
804 HIDH_TRACE_WARNING("Rcvd L2CAP data, invalid length %d, should be >= 1",
805 p_msg->len);
806 osi_free(p_msg);
807 android_errorWriteLog(0x534e4554, "80493272");
808 return;
809 }
810
811 ttype = HID_GET_TRANS_FROM_HDR(*p_data);
812 param = HID_GET_PARAM_FROM_HDR(*p_data);
813 rep_type = param & HID_PAR_REP_TYPE_MASK;
814 p_data++;
815
816 /* Get rid of the data type */
817 p_msg->len--;
818 p_msg->offset++;
819
820 switch (ttype) {
821 case HID_TRANS_HANDSHAKE:
822 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr,
823 HID_HDEV_EVT_HANDSHAKE, param, NULL);
824 osi_free(p_msg);
825 break;
826
827 case HID_TRANS_CONTROL:
828 switch (param) {
829 case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
830 hidh_conn_disconnect(dhandle);
831 /* Device is unplugging from us. Tell USB */
832 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr,
833 HID_HDEV_EVT_VC_UNPLUG, 0, NULL);
834 break;
835
836 default:
837 break;
838 }
839 osi_free(p_msg);
840 break;
841
842 case HID_TRANS_DATA:
843 evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid)
844 ? HID_HDEV_EVT_INTR_DATA
845 : HID_HDEV_EVT_CTRL_DATA;
846 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type,
847 p_msg);
848 break;
849
850 case HID_TRANS_DATAC:
851 evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid)
852 ? HID_HDEV_EVT_INTR_DATC
853 : HID_HDEV_EVT_CTRL_DATC;
854 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type,
855 p_msg);
856 break;
857
858 default:
859 osi_free(p_msg);
860 break;
861 }
862 }
863
864 /*******************************************************************************
865 *
866 * Function hidh_conn_snd_data
867 *
868 * Description This function is sends out data.
869 *
870 * Returns tHID_STATUS
871 *
872 ******************************************************************************/
hidh_conn_snd_data(uint8_t dhandle,uint8_t trans_type,uint8_t param,uint16_t data,uint8_t report_id,BT_HDR * buf)873 tHID_STATUS hidh_conn_snd_data(uint8_t dhandle, uint8_t trans_type,
874 uint8_t param, uint16_t data, uint8_t report_id,
875 BT_HDR* buf) {
876 tHID_CONN* p_hcon = &hh_cb.devices[dhandle].conn;
877 BT_HDR* p_buf;
878 uint8_t* p_out;
879 uint16_t bytes_copied;
880 bool seg_req = false;
881 uint16_t data_size;
882 uint16_t cid;
883 uint16_t buf_size;
884 uint8_t use_data = 0;
885 bool blank_datc = false;
886
887 if (!BTM_IsAclConnectionUp(hh_cb.devices[dhandle].addr,
888 BT_TRANSPORT_BR_EDR)) {
889 osi_free(buf);
890 return HID_ERR_NO_CONNECTION;
891 }
892
893 if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) {
894 osi_free(buf);
895 return HID_ERR_CONGESTED;
896 }
897
898 switch (trans_type) {
899 case HID_TRANS_CONTROL:
900 case HID_TRANS_GET_REPORT:
901 case HID_TRANS_SET_REPORT:
902 case HID_TRANS_GET_PROTOCOL:
903 case HID_TRANS_SET_PROTOCOL:
904 case HID_TRANS_GET_IDLE:
905 case HID_TRANS_SET_IDLE:
906 cid = p_hcon->ctrl_cid;
907 buf_size = HID_CONTROL_BUF_SIZE;
908 break;
909 case HID_TRANS_DATA:
910 cid = p_hcon->intr_cid;
911 buf_size = HID_INTERRUPT_BUF_SIZE;
912 break;
913 default:
914 return (HID_ERR_INVALID_PARAM);
915 }
916
917 if (trans_type == HID_TRANS_SET_IDLE)
918 use_data = 1;
919 else if ((trans_type == HID_TRANS_GET_REPORT) && (param & 0x08))
920 use_data = 2;
921
922 do {
923 if (buf == NULL || blank_datc) {
924 p_buf = (BT_HDR*)osi_malloc(buf_size);
925
926 p_buf->offset = L2CAP_MIN_OFFSET;
927 seg_req = false;
928 data_size = 0;
929 bytes_copied = 0;
930 blank_datc = false;
931 } else if ((buf->len > (p_hcon->rem_mtu_size - 1))) {
932 p_buf = (BT_HDR*)osi_malloc(buf_size);
933
934 p_buf->offset = L2CAP_MIN_OFFSET;
935 seg_req = true;
936 data_size = buf->len;
937 bytes_copied = p_hcon->rem_mtu_size - 1;
938 } else {
939 p_buf = buf;
940 p_buf->offset -= 1;
941 seg_req = false;
942 data_size = buf->len;
943 bytes_copied = buf->len;
944 }
945
946 p_out = (uint8_t*)(p_buf + 1) + p_buf->offset;
947 *p_out++ = HID_BUILD_HDR(trans_type, param);
948
949 /* If report ID required for this device */
950 if ((trans_type == HID_TRANS_GET_REPORT) && (report_id != 0)) {
951 *p_out = report_id;
952 data_size = bytes_copied = 1;
953 }
954
955 if (seg_req) {
956 memcpy(p_out, (((uint8_t*)(buf + 1)) + buf->offset), bytes_copied);
957 buf->offset += bytes_copied;
958 buf->len -= bytes_copied;
959 } else if (use_data == 1) {
960 *(p_out + bytes_copied) = data & 0xff;
961 } else if (use_data == 2) {
962 *(p_out + bytes_copied) = data & 0xff;
963 *(p_out + bytes_copied + 1) = (data >> 8) & 0xff;
964 }
965
966 p_buf->len = bytes_copied + 1 + use_data;
967 data_size -= bytes_copied;
968
969 /* Send the buffer through L2CAP */
970 if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) ||
971 (!L2CA_DataWrite(cid, p_buf)))
972 return (HID_ERR_CONGESTED);
973
974 if (data_size)
975 trans_type = HID_TRANS_DATAC;
976 else if (bytes_copied == (p_hcon->rem_mtu_size - 1)) {
977 trans_type = HID_TRANS_DATAC;
978 blank_datc = true;
979 }
980
981 } while ((data_size != 0) || blank_datc);
982
983 return (HID_SUCCESS);
984 }
985 /*******************************************************************************
986 *
987 * Function hidh_conn_initiate
988 *
989 * Description This function is called by the management to create a
990 * connection.
991 *
992 * Returns void
993 *
994 ******************************************************************************/
hidh_conn_initiate(uint8_t dhandle)995 tHID_STATUS hidh_conn_initiate(uint8_t dhandle) {
996 uint8_t service_id = BTM_SEC_SERVICE_HIDH_NOSEC_CTRL;
997 uint32_t mx_chan_id = HID_NOSEC_CHN;
998
999 tHID_HOST_DEV_CTB* p_dev = &hh_cb.devices[dhandle];
1000
1001 if (p_dev->conn.conn_state != HID_CONN_STATE_UNUSED)
1002 return (HID_ERR_CONN_IN_PROCESS);
1003
1004 p_dev->conn.ctrl_cid = 0;
1005 p_dev->conn.intr_cid = 0;
1006 p_dev->conn.disc_reason =
1007 HID_L2CAP_CONN_FAIL; /* Reset initial reason for CLOSE_EVT: Connection
1008 Attempt was made but failed */
1009
1010 /* We are the originator of this connection */
1011 p_dev->conn.conn_flags = HID_CONN_FLAGS_IS_ORIG;
1012
1013 if (p_dev->attr_mask & HID_SEC_REQUIRED) {
1014 service_id = BTM_SEC_SERVICE_HIDH_SEC_CTRL;
1015 mx_chan_id = HID_SEC_CHN;
1016 }
1017 BTM_SetOutService(p_dev->addr, service_id, mx_chan_id);
1018
1019 /* Check if L2CAP started the connection process */
1020 p_dev->conn.ctrl_cid = L2CA_ConnectReq(HID_PSM_CONTROL, p_dev->addr);
1021 if (p_dev->conn.ctrl_cid == 0) {
1022 HIDH_TRACE_WARNING("HID-Host Originate failed");
1023 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
1024 HID_ERR_L2CAP_FAILED, NULL);
1025 } else {
1026 /* Transition to the next appropriate state, waiting for connection confirm
1027 * on control channel. */
1028 p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
1029 }
1030
1031 return (HID_SUCCESS);
1032 }
1033
1034 /*******************************************************************************
1035 *
1036 * Function find_conn_by_cid
1037 *
1038 * Description This function finds a connection control block based on CID
1039 *
1040 * Returns address of control block, or NULL if not found
1041 *
1042 ******************************************************************************/
find_conn_by_cid(uint16_t cid)1043 static uint8_t find_conn_by_cid(uint16_t cid) {
1044 uint8_t xx;
1045
1046 for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++) {
1047 if ((hh_cb.devices[xx].in_use) &&
1048 (hh_cb.devices[xx].conn.conn_state != HID_CONN_STATE_UNUSED) &&
1049 ((hh_cb.devices[xx].conn.ctrl_cid == cid) ||
1050 (hh_cb.devices[xx].conn.intr_cid == cid)))
1051 break;
1052 }
1053
1054 return (xx);
1055 }
1056
hidh_conn_dereg(void)1057 void hidh_conn_dereg(void) {
1058 L2CA_Deregister(HID_PSM_CONTROL);
1059 L2CA_Deregister(HID_PSM_INTERRUPT);
1060 }
1061
1062 /*******************************************************************************
1063 *
1064 * Function hidh_conn_retry
1065 *
1066 * Description This function is called to retry a failed connection.
1067 *
1068 * Returns void
1069 *
1070 ******************************************************************************/
hidh_conn_retry(uint8_t dhandle)1071 static void hidh_conn_retry(uint8_t dhandle) {
1072 tHID_HOST_DEV_CTB* p_dev = &hh_cb.devices[dhandle];
1073
1074 p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
1075 #if (HID_HOST_REPAGE_WIN > 0)
1076 period_ms_t interval_ms = HID_HOST_REPAGE_WIN * 1000;
1077 alarm_set_on_mloop(p_dev->conn.process_repage_timer, interval_ms,
1078 hidh_process_repage_timer_timeout, UINT_TO_PTR(dhandle));
1079 #else
1080 hidh_try_repage(dhandle);
1081 #endif
1082 }
1083