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