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