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