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
46static UINT8 find_conn_by_cid (UINT16 cid);
47static 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/********************************************************************************/
52static void hidh_l2cif_connect_ind (BD_ADDR  bd_addr, UINT16 l2cap_cid,
53                                    UINT16 psm, UINT8 l2cap_id);
54static void hidh_l2cif_connect_cfm (UINT16 l2cap_cid, UINT16 result);
55static void hidh_l2cif_config_ind (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
56static void hidh_l2cif_config_cfm (UINT16 l2cap_cid, tL2CAP_CFG_INFO *p_cfg);
57static void hidh_l2cif_disconnect_ind (UINT16 l2cap_cid, BOOLEAN ack_needed);
58static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg);
59static void hidh_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result);
60static void hidh_l2cif_cong_ind (UINT16 l2cap_cid, BOOLEAN congested);
61
62static 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*******************************************************************************/
86tHID_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*******************************************************************************/
129tHID_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*******************************************************************************/
166void 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*******************************************************************************/
205static 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*******************************************************************************/
302void 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*******************************************************************************/
320void 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*******************************************************************************/
375static 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*******************************************************************************/
456static 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*******************************************************************************/
542static 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*******************************************************************************/
620static 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*******************************************************************************/
701static 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*******************************************************************************/
749static 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*******************************************************************************/
791static 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*******************************************************************************/
872tHID_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*******************************************************************************/
1012tHID_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*******************************************************************************/
1062static 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
1076void 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*******************************************************************************/
1091static 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