OSDN Git Service

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