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