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
45 static UINT8 find_conn_by_cid (UINT16 cid);
46 static void hidh_conn_retry (UINT8 dhandle);
47
48 /********************************************************************************/
49 /* L O C A L F U N C T I O N P R O T O T Y P E S */
50 /********************************************************************************/
51 static void hidh_l2cif_connect_ind (BD_ADDR bd_addr, UINT16 l2cap_cid,
52 UINT16 psm, UINT8 l2cap_id);
53 static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result);
54 static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
55 static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
56 static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
57 static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
58 static void hidh_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result);
59 static void hidh_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested);
60
61 static const tL2CAP_APPL_INFO hst_reg_info =
62 {
63 hidh_l2cif_connect_ind,
64 hidh_l2cif_connect_cfm,
65 NULL,
66 hidh_l2cif_config_ind,
67 hidh_l2cif_config_cfm,
68 hidh_l2cif_disconnect_ind,
69 hidh_l2cif_disconnect_cfm,
70 NULL,
71 hidh_l2cif_data_ind,
72 hidh_l2cif_cong_ind,
73 NULL /* tL2CA_TX_COMPLETE_CB */
74 };
75
76 /*******************************************************************************
77 **
78 ** Function hidh_l2cif_reg
79 **
80 ** Description This function initializes the SDP unit.
81 **
82 ** Returns void
83 **
84 *******************************************************************************/
hidh_conn_reg(void)85 tHID_STATUS hidh_conn_reg (void)
86 {
87 int xx;
88
89 /* Initialize the L2CAP configuration. We only care about MTU and flush */
90 memset(&hh_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO));
91
92 hh_cb.l2cap_cfg.mtu_present = TRUE;
93 hh_cb.l2cap_cfg.mtu = HID_HOST_MTU;
94 hh_cb.l2cap_cfg.flush_to_present = TRUE;
95 hh_cb.l2cap_cfg.flush_to = HID_HOST_FLUSH_TO;
96
97 /* Now, register with L2CAP */
98 if (!L2CA_Register (HID_PSM_CONTROL, (tL2CAP_APPL_INFO *) &hst_reg_info))
99 {
100 HIDH_TRACE_ERROR0 ("HID Control Registration failed");
101 return (HID_ERR_L2CAP_FAILED) ;
102 }
103 if (!L2CA_Register (HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO *) &hst_reg_info))
104 {
105 L2CA_Deregister( HID_PSM_CONTROL ) ;
106 HIDH_TRACE_ERROR0 ("HID Interrupt Registration failed");
107 return (HID_ERR_L2CAP_FAILED) ;
108 }
109
110 for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
111 {
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_EVENT0 ("HID-Host disconnect");
133
134 if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0))
135 {
136 p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING;
137
138 /* Disconnect both interrupt and control channels */
139 if (p_hcon->intr_cid)
140 L2CA_DisconnectReq (p_hcon->intr_cid);
141
142 if (p_hcon->ctrl_cid)
143 L2CA_DisconnectReq (p_hcon->ctrl_cid);
144 }
145 else
146 {
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,void * p_ref_data,UINT8 res)163 void hidh_sec_check_complete_term (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
164 {
165 tHID_HOST_DEV_CTB *p_dev= (tHID_HOST_DEV_CTB *) p_ref_data;
166
167 if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
168 {
169 p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
170
171 p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
172
173 /* Send response to the L2CAP layer. */
174 L2CA_ConnectRsp (p_dev->addr, p_dev->conn.ctrl_id, p_dev->conn.ctrl_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
175
176 /* Send a Configuration Request. */
177 L2CA_ConfigReq (p_dev->conn.ctrl_cid, &hh_cb.l2cap_cfg);
178
179 }
180 /* security check fail */
181 else if (res != BTM_SUCCESS)
182 {
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_EVENT2 ("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 {
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 {
222 if (p_hcon->ctrl_cid == 0)
223 {
224 HIDH_TRACE_WARNING0 ("HID-Host Rcvd INTR L2CAP conn ind, but no CTL channel");
225 bAccept = FALSE;
226 }
227 if (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)
228 {
229 HIDH_TRACE_WARNING1 ("HID-Host Rcvd INTR L2CAP conn ind, wrong state: %d",
230 p_hcon->conn_state);
231 bAccept = FALSE;
232 }
233 }
234 else /* CTRL channel */
235 {
236 #if defined(HID_HOST_ACPT_NEW_CONN) && (HID_HOST_ACPT_NEW_CONN == TRUE)
237 p_hcon->ctrl_cid = p_hcon->intr_cid = 0;
238 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
239 #else
240 if (p_hcon->conn_state != HID_CONN_STATE_UNUSED)
241 {
242 HIDH_TRACE_WARNING1 ("HID-Host - Rcvd CTL L2CAP conn ind, wrong state: %d",
243 p_hcon->conn_state);
244 bAccept = FALSE;
245 }
246 #endif
247 }
248
249 if (!bAccept)
250 {
251 L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_NO_RESOURCES, 0);
252 return;
253 }
254
255 if (psm == HID_PSM_CONTROL)
256 {
257 p_hcon->conn_flags = 0;
258 p_hcon->ctrl_cid = l2cap_cid;
259 p_hcon->ctrl_id = l2cap_id;
260 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' */
261
262 p_hcon->conn_state = HID_CONN_STATE_SECURITY;
263 if(btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
264 FALSE, BTM_SEC_PROTO_HID,
265 (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
266 &hidh_sec_check_complete_term, p_dev) == BTM_CMD_STARTED)
267 {
268 L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_PENDING, L2CAP_CONN_OK);
269 }
270
271 return;
272 }
273
274 /* Transition to the next appropriate state, configuration */
275 p_hcon->conn_state = HID_CONN_STATE_CONFIG;
276 p_hcon->intr_cid = l2cap_cid;
277
278 /* Send response to the L2CAP layer. */
279 L2CA_ConnectRsp (bd_addr, l2cap_id, l2cap_cid, L2CAP_CONN_OK, L2CAP_CONN_OK);
280
281 /* Send a Configuration Request. */
282 L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
283
284 HIDH_TRACE_EVENT2 ("HID-Host Rcvd L2CAP conn ind, sent config req, PSM: 0x%04x CID 0x%x",
285 psm, l2cap_cid);
286 }
287
288 /*******************************************************************************
289 **
290 ** Function hidh_proc_repage_timeout
291 **
292 ** Description This function handles timeout (to page device).
293 **
294 ** Returns void
295 **
296 *******************************************************************************/
hidh_proc_repage_timeout(TIMER_LIST_ENT * p_tle)297 void hidh_proc_repage_timeout (TIMER_LIST_ENT *p_tle)
298 {
299 hidh_conn_initiate( (UINT8) p_tle->param ) ;
300 hh_cb.devices[p_tle->param].conn_tries++;
301 hh_cb.callback( (UINT8) p_tle->param, hh_cb.devices[p_tle->param].addr,
302 HID_HDEV_EVT_RETRYING, hh_cb.devices[p_tle->param].conn_tries, NULL ) ;
303 }
304
305 /*******************************************************************************
306 **
307 ** Function hidh_sec_check_complete_orig
308 **
309 ** Description This function checks to see if security procedures are being
310 ** carried out or not..
311 **
312 ** Returns void
313 **
314 *******************************************************************************/
hidh_sec_check_complete_orig(BD_ADDR bd_addr,void * p_ref_data,UINT8 res)315 void hidh_sec_check_complete_orig (BD_ADDR bd_addr, void *p_ref_data, UINT8 res)
316 {
317 tHID_HOST_DEV_CTB *p_dev = (tHID_HOST_DEV_CTB *) p_ref_data;
318 UINT8 dhandle;
319 #if (HID_HOST_MAX_CONN_RETRY > 0)
320 UINT32 cb_res = HID_ERR_AUTH_FAILED;
321 #endif
322 UINT32 reason;
323
324 dhandle = ((UINT32)p_dev - (UINT32)&(hh_cb.devices[0]))/ sizeof(tHID_HOST_DEV_CTB);
325 if( res == BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
326 {
327 HIDH_TRACE_EVENT0 ("HID-Host Originator security pass.");
328 p_dev->conn.disc_reason = HID_SUCCESS; /* Authentication passed. Reset disc_reason (from HID_ERR_AUTH_FAILED) */
329
330 /* Check if L2CAP started the connection process for interrupt channel */
331 if ((p_dev->conn.intr_cid = L2CA_ConnectReq (HID_PSM_INTERRUPT, hh_cb.devices[dhandle].addr)) == 0)
332 {
333 HIDH_TRACE_WARNING0 ("HID-Host INTR Originate failed");
334 reason = HID_L2CAP_REQ_FAIL ;
335 hidh_conn_disconnect (dhandle);
336 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
337 return;
338 }
339 else
340 {
341 /* Transition to the next appropriate state, waiting for connection confirm on control channel. */
342 p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_INTR;
343 }
344 }
345
346 if( res != BTM_SUCCESS && p_dev->conn.conn_state == HID_CONN_STATE_SECURITY )
347 {
348 #if (HID_HOST_MAX_CONN_RETRY > 0)
349 if( res == BTM_DEVICE_TIMEOUT )
350 {
351 if( p_dev->conn_tries <= HID_HOST_MAX_CONN_RETRY )
352 {
353 hidh_conn_retry (dhandle);
354 return;
355 }
356 else
357 cb_res = HID_L2CAP_CONN_FAIL | HCI_ERR_PAGE_TIMEOUT ;
358 }
359 #endif
360 p_dev->conn.disc_reason = HID_ERR_AUTH_FAILED; /* Save reason for disconnecting */
361 hidh_conn_disconnect(dhandle);
362 }
363
364 }
365
366 /*******************************************************************************
367 **
368 ** Function hidh_l2cif_connect_cfm
369 **
370 ** Description This function handles the connect confirm events
371 ** from L2CAP. This is the case when we are acting as a
372 ** client and have sent a connect request.
373 **
374 ** Returns void
375 **
376 *******************************************************************************/
hidh_l2cif_connect_cfm(UINT16 l2cap_cid,UINT16 result)377 static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result)
378 {
379 UINT8 dhandle;
380 tHID_CONN *p_hcon = NULL;
381 UINT32 reason;
382 tHID_HOST_DEV_CTB *p_dev = NULL;
383
384 /* Find CCB based on CID, and verify we are in a state to accept this message */
385 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
386 {
387 p_dev = &hh_cb.devices[dhandle];
388 p_hcon = &hh_cb.devices[dhandle].conn;
389 }
390
391 if ((p_hcon == NULL)
392 || (!(p_hcon->conn_flags & HID_CONN_FLAGS_IS_ORIG))
393 || ((l2cap_cid == p_hcon->ctrl_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_CTRL))
394 || ((l2cap_cid == p_hcon->intr_cid) && (p_hcon->conn_state != HID_CONN_STATE_CONNECTING_INTR)))
395 {
396 HIDH_TRACE_WARNING1 ("HID-Host Rcvd unexpected conn cnf, CID 0x%x ", l2cap_cid);
397 return;
398 }
399
400 if (result != L2CAP_CONN_OK)
401 {
402 if (l2cap_cid == p_hcon->ctrl_cid)
403 p_hcon->ctrl_cid = 0;
404 else
405 p_hcon->intr_cid = 0;
406
407 hidh_conn_disconnect(dhandle);
408
409 #if (HID_HOST_MAX_CONN_RETRY > 0)
410 if( (hh_cb.devices[dhandle].conn_tries <= HID_HOST_MAX_CONN_RETRY) &&
411 (result == HCI_ERR_CONNECTION_TOUT || result == HCI_ERR_UNSPECIFIED ||
412 result == HCI_ERR_PAGE_TIMEOUT) )
413 {
414 hidh_conn_retry(dhandle);
415 }
416 else
417 #endif
418 {
419 reason = HID_L2CAP_CONN_FAIL | (UINT32) result ;
420 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
421 }
422 return;
423 }
424 /* receive Control Channel connect confirmation */
425 if (l2cap_cid == p_hcon->ctrl_cid)
426 {
427 /* check security requirement */
428 p_hcon->conn_state = HID_CONN_STATE_SECURITY;
429 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" */
430
431 btm_sec_mx_access_request (p_dev->addr, HID_PSM_CONTROL,
432 TRUE, BTM_SEC_PROTO_HID,
433 (p_dev->attr_mask & HID_SEC_REQUIRED) ? HID_SEC_CHN : HID_NOSEC_CHN,
434 &hidh_sec_check_complete_orig, p_dev);
435 }
436 else
437 {
438 p_hcon->conn_state = HID_CONN_STATE_CONFIG;
439 }
440
441 /* Send a Configuration Request. */
442 L2CA_ConfigReq (l2cap_cid, &hh_cb.l2cap_cfg);
443
444 HIDH_TRACE_EVENT1 ("HID-Host got CTRL conn cnf, sent cfg req, CID: 0x%x", l2cap_cid);
445 return;
446 }
447
448 /*******************************************************************************
449 **
450 ** Function hidh_l2cif_config_ind
451 **
452 ** Description This function processes the L2CAP configuration indication
453 ** event.
454 **
455 ** Returns void
456 **
457 *******************************************************************************/
hidh_l2cif_config_ind(UINT16 l2cap_cid,tL2CAP_CFG_INFO * p_cfg)458 static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
459 {
460 UINT8 dhandle;
461 tHID_CONN *p_hcon = NULL;
462 tHID_HOST_DEV_CTB *p_dev;
463
464 /* Find CCB based on CID */
465 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
466 {
467 p_dev = &hh_cb.devices[dhandle];
468 p_hcon = &hh_cb.devices[dhandle].conn;
469 }
470
471 if (p_hcon == NULL)
472 {
473 HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
474 return;
475 }
476
477 HIDH_TRACE_EVENT1 ("HID-Host Rcvd cfg ind, sent cfg cfm, CID: 0x%x", l2cap_cid);
478
479 /* Remember the remote MTU size */
480 if ((!p_cfg->mtu_present) || (p_cfg->mtu > HID_HOST_MTU))
481 p_hcon->rem_mtu_size = HID_HOST_MTU;
482 else
483 p_hcon->rem_mtu_size = p_cfg->mtu;
484
485 /* For now, always accept configuration from the other side */
486 p_cfg->flush_to_present = FALSE;
487 p_cfg->mtu_present = FALSE;
488 p_cfg->result = L2CAP_CFG_OK;
489
490 L2CA_ConfigRsp (l2cap_cid, p_cfg);
491
492 if (l2cap_cid == p_hcon->ctrl_cid)
493 p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_CTRL_CFG_DONE;
494 else
495 p_hcon->conn_flags |= HID_CONN_FLAGS_HIS_INTR_CFG_DONE;
496
497 /* If all configuration is complete, change state and tell management we are up */
498 if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
499 && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
500 {
501 p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
502
503 hh_cb.devices[dhandle].state = HID_DEV_CONNECTED;
504 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_OPEN, 0, NULL ) ;
505 }
506 }
507
508
509 /*******************************************************************************
510 **
511 ** Function hidh_l2cif_config_cfm
512 **
513 ** Description This function processes the L2CAP configuration confirmation
514 ** event.
515 **
516 ** Returns void
517 **
518 *******************************************************************************/
hidh_l2cif_config_cfm(UINT16 l2cap_cid,tL2CAP_CFG_INFO * p_cfg)519 static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg)
520 {
521 UINT8 dhandle;
522 tHID_CONN *p_hcon = NULL;
523 UINT32 reason;
524
525 HIDH_TRACE_EVENT2 ("HID-Host Rcvd cfg cfm, CID: 0x%x Result: %d", l2cap_cid, p_cfg->result);
526
527 /* Find CCB based on CID */
528 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
529 p_hcon = &hh_cb.devices[dhandle].conn;
530
531 if (p_hcon == NULL)
532 {
533 HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP cfg ind, unknown CID: 0x%x", l2cap_cid);
534 return;
535 }
536
537 /* If configuration failed, disconnect the channel(s) */
538 if (p_cfg->result != L2CAP_CFG_OK)
539 {
540 hidh_conn_disconnect (dhandle);
541 reason = HID_L2CAP_CFG_FAIL | (UINT32) p_cfg->result ;
542 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, reason, NULL ) ;
543 return;
544 }
545
546 if (l2cap_cid == p_hcon->ctrl_cid)
547 p_hcon->conn_flags |= HID_CONN_FLAGS_MY_CTRL_CFG_DONE;
548 else
549 p_hcon->conn_flags |= HID_CONN_FLAGS_MY_INTR_CFG_DONE;
550
551 /* If all configuration is complete, change state and tell management we are up */
552 if (((p_hcon->conn_flags & HID_CONN_FLAGS_ALL_CONFIGURED) == HID_CONN_FLAGS_ALL_CONFIGURED)
553 && (p_hcon->conn_state == HID_CONN_STATE_CONFIG))
554 {
555 p_hcon->conn_state = HID_CONN_STATE_CONNECTED;
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 if (p_hcon == NULL)
585 {
586 HIDH_TRACE_WARNING1 ("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 HIDH_TRACE_EVENT1 ("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 if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
603 {
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 #if (HID_HOST_MAX_CONN_RETRY > 0)
611 if( (disc_res == HCI_ERR_CONNECTION_TOUT || disc_res == HCI_ERR_UNSPECIFIED) &&
612 (!(hh_cb.devices[dhandle].attr_mask & HID_RECONN_INIT)) &&
613 (hh_cb.devices[dhandle].attr_mask & HID_NORMALLY_CONNECTABLE))
614 {
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 }
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 {
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
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 if (p_hcon == NULL)
663 {
664 HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid);
665 return;
666 }
667
668 HIDH_TRACE_EVENT1 ("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
675 if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0))
676 {
677 hh_cb.devices[dhandle].state = HID_DEV_NO_CONN;
678 p_hcon->conn_state = HID_CONN_STATE_UNUSED;
679 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, p_hcon->disc_reason, NULL ) ;
680 }
681 }
682
683
684 /*******************************************************************************
685 **
686 ** Function hidh_l2cif_cong_ind
687 **
688 ** Description This function handles a congestion status event from L2CAP.
689 **
690 ** Returns void
691 **
692 *******************************************************************************/
hidh_l2cif_cong_ind(UINT16 l2cap_cid,BOOLEAN congested)693 static void hidh_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested)
694 {
695 UINT8 dhandle;
696 tHID_CONN *p_hcon = NULL;
697
698 /* Find CCB based on CID */
699 if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES )
700 p_hcon = &hh_cb.devices[dhandle].conn;
701
702 if (p_hcon == NULL)
703 {
704 HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP congestion status, unknown CID: 0x%x", l2cap_cid);
705 return;
706 }
707
708 HIDH_TRACE_EVENT2 ("HID-Host Rcvd L2CAP congestion status, CID: 0x%x Cong: %d", l2cap_cid, congested);
709
710 if (congested)
711 p_hcon->conn_flags |= HID_CONN_FLAGS_CONGESTED;
712 else
713 {
714 p_hcon->conn_flags &= ~HID_CONN_FLAGS_CONGESTED;
715
716 }
717 }
718
719
720 /*******************************************************************************
721 **
722 ** Function hidh_l2cif_data_ind
723 **
724 ** Description This function is called when data is received from L2CAP.
725 ** if we are the originator of the connection, we are the SDP
726 ** client, and the received message is queued up for the client.
727 **
728 ** If we are the destination of the connection, we are the SDP
729 ** server, so the message is passed to the server processing
730 ** function.
731 **
732 ** Returns void
733 **
734 *******************************************************************************/
hidh_l2cif_data_ind(UINT16 l2cap_cid,BT_HDR * p_msg)735 static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg)
736 {
737 UINT8 *p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
738 UINT8 ttype, param, rep_type, evt;
739 UINT8 dhandle;
740 tHID_CONN *p_hcon = NULL;
741
742 HIDH_TRACE_DEBUG1 ("HID-Host hidh_l2cif_data_ind [l2cap_cid=0x%04x]", l2cap_cid);
743
744 /* Find CCB based on CID */
745 if ((dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES)
746 p_hcon = &hh_cb.devices[dhandle].conn;
747
748 if (p_hcon == NULL)
749 {
750 HIDH_TRACE_WARNING1 ("HID-Host Rcvd L2CAP data, unknown CID: 0x%x", l2cap_cid);
751 GKI_freebuf (p_msg);
752 return;
753 }
754
755
756 ttype = HID_GET_TRANS_FROM_HDR(*p_data);
757 param = HID_GET_PARAM_FROM_HDR(*p_data);
758 rep_type = param & HID_PAR_REP_TYPE_MASK;
759 p_data++;
760
761 /* Get rid of the data type */
762 p_msg->len--;
763 p_msg->offset++;
764
765 switch (ttype)
766 {
767 case HID_TRANS_HANDSHAKE:
768 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_HANDSHAKE, param, NULL);
769 GKI_freebuf (p_msg);
770 break;
771
772 case HID_TRANS_CONTROL:
773 switch (param)
774 {
775 case HID_PAR_CONTROL_VIRTUAL_CABLE_UNPLUG:
776 hidh_conn_disconnect( dhandle ) ;
777 /* Device is unplugging from us. Tell USB */
778 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_VC_UNPLUG, 0, NULL);
779 break;
780
781 default:
782 break;
783 }
784 GKI_freebuf (p_msg);
785 break;
786
787
788 case HID_TRANS_DATA:
789 evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
790 HID_HDEV_EVT_INTR_DATA : HID_HDEV_EVT_CTRL_DATA;
791 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
792 break;
793
794 case HID_TRANS_DATAC:
795 evt = (hh_cb.devices[dhandle].conn.intr_cid == l2cap_cid) ?
796 HID_HDEV_EVT_INTR_DATC : HID_HDEV_EVT_CTRL_DATC;
797 hh_cb.callback(dhandle, hh_cb.devices[dhandle].addr, evt, rep_type, p_msg);
798 break;
799
800 default:
801 GKI_freebuf (p_msg);
802 break;
803 }
804
805 }
806
807 /*******************************************************************************
808 **
809 ** Function hidh_conn_snd_data
810 **
811 ** Description This function is sends out data.
812 **
813 ** Returns tHID_STATUS
814 **
815 *******************************************************************************/
hidh_conn_snd_data(UINT8 dhandle,UINT8 trans_type,UINT8 param,UINT16 data,UINT8 report_id,BT_HDR * buf)816 tHID_STATUS hidh_conn_snd_data (UINT8 dhandle, UINT8 trans_type, UINT8 param,
817 UINT16 data, UINT8 report_id, BT_HDR *buf)
818 {
819 tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn;
820 BT_HDR *p_buf;
821 UINT8 *p_out;
822 UINT16 bytes_copied;
823 BOOLEAN seg_req = FALSE;
824 UINT16 data_size;
825 UINT16 cid;
826 UINT8 pool_id;
827 UINT8 use_data = 0 ;
828 BOOLEAN blank_datc = FALSE;
829
830 if (p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED)
831 {
832 if (buf)
833 GKI_freebuf ((void *)buf);
834 return( HID_ERR_CONGESTED );
835 }
836
837 switch( trans_type )
838 {
839 case HID_TRANS_CONTROL:
840 case HID_TRANS_GET_REPORT:
841 case HID_TRANS_SET_REPORT:
842 case HID_TRANS_GET_PROTOCOL:
843 case HID_TRANS_SET_PROTOCOL:
844 case HID_TRANS_GET_IDLE:
845 case HID_TRANS_SET_IDLE:
846 cid = p_hcon->ctrl_cid;
847 pool_id = HID_CONTROL_POOL_ID;
848 break;
849 case HID_TRANS_DATA:
850 cid = p_hcon->intr_cid;
851 pool_id = HID_INTERRUPT_POOL_ID;
852 break;
853 default:
854 return (HID_ERR_INVALID_PARAM) ;
855 }
856
857 if( trans_type == HID_TRANS_SET_IDLE )
858 use_data = 1;
859 else if( (trans_type == HID_TRANS_GET_REPORT) && (param & 0x08) )
860 use_data = 2;
861
862 do
863 {
864 if ( buf == NULL || blank_datc )
865 {
866 if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
867 return (HID_ERR_NO_RESOURCES);
868
869 p_buf->offset = L2CAP_MIN_OFFSET;
870 seg_req = FALSE;
871 data_size = 0;
872 bytes_copied = 0;
873 blank_datc = FALSE;
874 }
875 else if ( (buf->len > (p_hcon->rem_mtu_size - 1)))
876 {
877 if((p_buf = (BT_HDR *)GKI_getpoolbuf (pool_id)) == NULL)
878 return (HID_ERR_NO_RESOURCES);
879
880 p_buf->offset = L2CAP_MIN_OFFSET;
881 seg_req = TRUE;
882 data_size = buf->len;
883 bytes_copied = p_hcon->rem_mtu_size - 1;
884 }
885 else
886 {
887 p_buf = buf ;
888 p_buf->offset -= 1;
889 seg_req = FALSE;
890 data_size = buf->len;
891 bytes_copied = buf->len;
892 }
893
894 p_out = (UINT8 *)(p_buf + 1) + p_buf->offset;
895 *p_out++ = HID_BUILD_HDR(trans_type, param);
896
897 /* If report ID required for this device */
898 if( (trans_type == HID_TRANS_GET_REPORT) && (report_id != 0) )
899 {
900 *p_out = report_id;
901 data_size = bytes_copied = 1;
902 }
903
904
905 if (seg_req)
906 {
907 memcpy (p_out, (((UINT8 *)(buf+1)) + buf->offset), bytes_copied);
908 buf->offset += bytes_copied;
909 buf->len -= bytes_copied;
910 }
911 else if( use_data == 1)
912 {
913 *(p_out+bytes_copied) = data & 0xff;
914 }
915 else if( use_data == 2 )
916 {
917 *(p_out+bytes_copied) = data & 0xff;
918 *(p_out+bytes_copied+1) = (data >> 8) & 0xff ;
919 }
920
921 p_buf->len = bytes_copied + 1 + use_data;
922 data_size -= bytes_copied;
923
924 /* Send the buffer through L2CAP */
925 if ((p_hcon->conn_flags & HID_CONN_FLAGS_CONGESTED) || (!L2CA_DataWrite (cid, p_buf)))
926 return (HID_ERR_CONGESTED);
927
928 if (data_size)
929 trans_type = HID_TRANS_DATAC;
930 else if( bytes_copied == (p_hcon->rem_mtu_size - 1) )
931 {
932 trans_type = HID_TRANS_DATAC;
933 blank_datc = TRUE;
934 }
935
936 } while ((data_size != 0) || blank_datc ) ;
937
938 return (HID_SUCCESS);
939 }
940 /*******************************************************************************
941 **
942 ** Function hidh_conn_initiate
943 **
944 ** Description This function is called by the management to create a connection.
945 **
946 ** Returns void
947 **
948 *******************************************************************************/
hidh_conn_initiate(UINT8 dhandle)949 tHID_STATUS hidh_conn_initiate (UINT8 dhandle)
950 {
951 UINT8 service_id = BTM_SEC_SERVICE_HIDH_NOSEC_CTRL;
952 UINT32 mx_chan_id = HID_NOSEC_CHN;
953
954 tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
955
956 if( p_dev->conn.conn_state != HID_CONN_STATE_UNUSED )
957 return( HID_ERR_CONN_IN_PROCESS );
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 {
968 service_id = BTM_SEC_SERVICE_HIDH_SEC_CTRL;
969 mx_chan_id = HID_SEC_CHN;
970 }
971 BTM_SetOutService (p_dev->addr, service_id, mx_chan_id);
972
973 /* Check if L2CAP started the connection process */
974 if ((p_dev->conn.ctrl_cid = L2CA_ConnectReq (HID_PSM_CONTROL, p_dev->addr)) == 0)
975 {
976 HIDH_TRACE_WARNING0 ("HID-Host Originate failed");
977 hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE,
978 HID_ERR_L2CAP_FAILED, NULL ) ;
979 }
980 else
981 {
982 /* Transition to the next appropriate state, waiting for connection confirm on control channel. */
983 p_dev->conn.conn_state = HID_CONN_STATE_CONNECTING_CTRL;
984 }
985
986 return( HID_SUCCESS );
987 }
988
989
990 /*******************************************************************************
991 **
992 ** Function find_conn_by_cid
993 **
994 ** Description This function finds a connection control block based on CID
995 **
996 ** Returns address of control block, or NULL if not found
997 **
998 *******************************************************************************/
find_conn_by_cid(UINT16 cid)999 static UINT8 find_conn_by_cid (UINT16 cid)
1000 {
1001 UINT8 xx;
1002
1003 for (xx = 0; xx < HID_HOST_MAX_DEVICES; xx++)
1004 {
1005 if ((hh_cb.devices[xx].in_use) && (hh_cb.devices[xx].conn.conn_state != HID_CONN_STATE_UNUSED)
1006 && ((hh_cb.devices[xx].conn.ctrl_cid == cid) || (hh_cb.devices[xx].conn.intr_cid == cid)))
1007 break;
1008 }
1009
1010 return (xx);
1011 }
1012
hidh_conn_dereg(void)1013 void hidh_conn_dereg( void )
1014 {
1015 L2CA_Deregister (HID_PSM_CONTROL);
1016 L2CA_Deregister (HID_PSM_INTERRUPT);
1017 }
1018
1019 /*******************************************************************************
1020 **
1021 ** Function hidh_conn_retry
1022 **
1023 ** Description This function is called to retry a failed connection.
1024 **
1025 ** Returns void
1026 **
1027 *******************************************************************************/
hidh_conn_retry(UINT8 dhandle)1028 static void hidh_conn_retry( UINT8 dhandle )
1029 {
1030 tHID_HOST_DEV_CTB *p_dev = &hh_cb.devices[dhandle];
1031
1032 p_dev->conn.conn_state = HID_CONN_STATE_UNUSED;
1033 p_dev->conn.timer_entry.param = (UINT32) dhandle;
1034 #if (HID_HOST_REPAGE_WIN > 0)
1035 btu_start_timer (&(p_dev->conn.timer_entry), BTU_TTYPE_HID_HOST_REPAGE_TO, HID_HOST_REPAGE_WIN);
1036 #else
1037 hidh_proc_repage_timeout( &(p_dev->conn.timer_entry) );
1038 #endif
1039 }
1040