2007-02-09 17:24:33 +03:00
/*
2005-04-17 02:20:36 +04:00
BlueZ - Bluetooth protocol stack for Linux
Copyright ( C ) 2000 - 2001 Qualcomm Incorporated
Written 2000 , 2001 by Maxim Krasnyansky < maxk @ qualcomm . com >
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation ;
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS
OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS .
IN NO EVENT SHALL THE COPYRIGHT HOLDER ( S ) AND AUTHOR ( S ) BE LIABLE FOR ANY
2007-02-09 17:24:33 +03:00
CLAIM , OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES , OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
2005-04-17 02:20:36 +04:00
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
2007-02-09 17:24:33 +03:00
ALL LIABILITY , INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS ,
COPYRIGHTS , TRADEMARKS OR OTHER RIGHTS , RELATING TO USE OF THIS
2005-04-17 02:20:36 +04:00
SOFTWARE IS DISCLAIMED .
*/
/* Bluetooth HCI event handling. */
# include <linux/module.h>
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/poll.h>
# include <linux/fcntl.h>
# include <linux/init.h>
# include <linux/skbuff.h>
# include <linux/interrupt.h>
# include <linux/notifier.h>
# include <net/sock.h>
# include <asm/system.h>
# include <asm/uaccess.h>
# include <asm/unaligned.h>
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
# ifndef CONFIG_BT_HCI_CORE_DEBUG
# undef BT_DBG
# define BT_DBG(D...)
# endif
/* Handle HCI Event packets */
2007-10-20 15:33:56 +04:00
static void hci_cc_inquiry_cancel ( struct hci_dev * hdev , struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
2007-10-20 15:33:56 +04:00
__u8 status = * ( ( __u8 * ) skb - > data ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( status )
return ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
clear_bit ( HCI_INQUIRY , & hdev - > flags ) ;
2006-11-19 00:14:22 +03:00
2007-10-20 15:33:56 +04:00
hci_req_complete ( hdev , status ) ;
hci_conn_check_pending ( hdev ) ;
}
2006-11-19 00:14:22 +03:00
2007-10-20 15:33:56 +04:00
static void hci_cc_exit_periodic_inq ( struct hci_dev * hdev , struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
2006-11-19 00:14:22 +03:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
2006-11-19 00:14:22 +03:00
2007-10-20 15:33:56 +04:00
if ( status )
return ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
clear_bit ( HCI_INQUIRY , & hdev - > flags ) ;
hci_conn_check_pending ( hdev ) ;
}
static void hci_cc_remote_name_req_cancel ( struct hci_dev * hdev , struct sk_buff * skb )
{
BT_DBG ( " %s " , hdev - > name ) ;
}
static void hci_cc_role_discovery ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_rp_role_discovery * rp = ( void * ) skb - > data ;
struct hci_conn * conn ;
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
if ( rp - > status )
return ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( rp - > handle ) ) ;
if ( conn ) {
if ( rp - > role )
conn - > link_mode & = ~ HCI_LM_MASTER ;
else
conn - > link_mode | = HCI_LM_MASTER ;
2005-04-17 02:20:36 +04:00
}
2007-10-20 15:33:56 +04:00
hci_dev_unlock ( hdev ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-14 22:13:47 +04:00
static void hci_cc_read_link_policy ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_rp_read_link_policy * rp = ( void * ) skb - > data ;
struct hci_conn * conn ;
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
if ( rp - > status )
return ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( rp - > handle ) ) ;
if ( conn )
conn - > link_policy = __le16_to_cpu ( rp - > policy ) ;
hci_dev_unlock ( hdev ) ;
}
2007-10-20 15:33:56 +04:00
static void hci_cc_write_link_policy ( struct hci_dev * hdev , struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
2007-10-20 15:33:56 +04:00
struct hci_rp_write_link_policy * rp = ( void * ) skb - > data ;
2005-04-17 02:20:36 +04:00
struct hci_conn * conn ;
2006-07-03 12:02:33 +04:00
void * sent ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( rp - > status )
return ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
sent = hci_sent_cmd_data ( hdev , HCI_OP_WRITE_LINK_POLICY ) ;
if ( ! sent )
return ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
hci_dev_lock ( hdev ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( rp - > handle ) ) ;
2008-07-14 22:13:47 +04:00
if ( conn )
2008-05-03 03:25:46 +04:00
conn - > link_policy = get_unaligned_le16 ( sent + 2 ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
hci_dev_unlock ( hdev ) ;
}
2005-04-17 02:20:36 +04:00
2008-07-14 22:13:47 +04:00
static void hci_cc_read_def_link_policy ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_rp_read_def_link_policy * rp = ( void * ) skb - > data ;
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
if ( rp - > status )
return ;
hdev - > link_policy = __le16_to_cpu ( rp - > policy ) ;
}
static void hci_cc_write_def_link_policy ( struct hci_dev * hdev , struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
void * sent ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
sent = hci_sent_cmd_data ( hdev , HCI_OP_WRITE_DEF_LINK_POLICY ) ;
if ( ! sent )
return ;
if ( ! status )
hdev - > link_policy = get_unaligned_le16 ( sent ) ;
hci_req_complete ( hdev , status ) ;
}
2007-10-20 15:33:56 +04:00
static void hci_cc_reset ( struct hci_dev * hdev , struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
2006-07-03 12:02:33 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
2006-07-03 12:02:33 +04:00
2007-10-20 15:33:56 +04:00
hci_req_complete ( hdev , status ) ;
}
2006-07-03 12:02:33 +04:00
2007-10-20 15:33:56 +04:00
static void hci_cc_write_local_name ( struct hci_dev * hdev , struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
void * sent ;
2006-07-03 12:02:33 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
2006-07-03 12:02:33 +04:00
2008-07-14 22:13:47 +04:00
if ( status )
return ;
2007-10-20 15:33:56 +04:00
sent = hci_sent_cmd_data ( hdev , HCI_OP_WRITE_LOCAL_NAME ) ;
if ( ! sent )
return ;
2006-07-03 12:02:33 +04:00
2008-07-14 22:13:47 +04:00
memcpy ( hdev - > dev_name , sent , 248 ) ;
2007-10-20 15:33:56 +04:00
}
static void hci_cc_read_local_name ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_rp_read_local_name * rp = ( void * ) skb - > data ;
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
if ( rp - > status )
return ;
memcpy ( hdev - > dev_name , rp - > name , 248 ) ;
}
static void hci_cc_write_auth_enable ( struct hci_dev * hdev , struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
void * sent ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
sent = hci_sent_cmd_data ( hdev , HCI_OP_WRITE_AUTH_ENABLE ) ;
if ( ! sent )
return ;
if ( ! status ) {
__u8 param = * ( ( __u8 * ) sent ) ;
if ( param = = AUTH_ENABLED )
set_bit ( HCI_AUTH , & hdev - > flags ) ;
else
clear_bit ( HCI_AUTH , & hdev - > flags ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-20 15:33:56 +04:00
hci_req_complete ( hdev , status ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-20 15:33:56 +04:00
static void hci_cc_write_encrypt_mode ( struct hci_dev * hdev , struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
2007-10-20 15:33:56 +04:00
__u8 status = * ( ( __u8 * ) skb - > data ) ;
2005-04-17 02:20:36 +04:00
void * sent ;
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
sent = hci_sent_cmd_data ( hdev , HCI_OP_WRITE_ENCRYPT_MODE ) ;
if ( ! sent )
return ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( ! status ) {
__u8 param = * ( ( __u8 * ) sent ) ;
if ( param )
set_bit ( HCI_ENCRYPT , & hdev - > flags ) ;
else
clear_bit ( HCI_ENCRYPT , & hdev - > flags ) ;
}
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
hci_req_complete ( hdev , status ) ;
}
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
static void hci_cc_write_scan_enable ( struct hci_dev * hdev , struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
void * sent ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
sent = hci_sent_cmd_data ( hdev , HCI_OP_WRITE_SCAN_ENABLE ) ;
if ( ! sent )
return ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( ! status ) {
__u8 param = * ( ( __u8 * ) sent ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
clear_bit ( HCI_PSCAN , & hdev - > flags ) ;
clear_bit ( HCI_ISCAN , & hdev - > flags ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( param & SCAN_INQUIRY )
set_bit ( HCI_ISCAN , & hdev - > flags ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( param & SCAN_PAGE )
set_bit ( HCI_PSCAN , & hdev - > flags ) ;
}
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
hci_req_complete ( hdev , status ) ;
}
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
static void hci_cc_read_class_of_dev ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_rp_read_class_of_dev * rp = ( void * ) skb - > data ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( rp - > status )
return ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
memcpy ( hdev - > dev_class , rp - > dev_class , 3 ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s class 0x%.2x%.2x%.2x " , hdev - > name ,
hdev - > dev_class [ 2 ] , hdev - > dev_class [ 1 ] , hdev - > dev_class [ 0 ] ) ;
}
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
static void hci_cc_write_class_of_dev ( struct hci_dev * hdev , struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
void * sent ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
2005-04-17 02:20:36 +04:00
2008-07-14 22:13:47 +04:00
if ( status )
return ;
2007-10-20 15:33:56 +04:00
sent = hci_sent_cmd_data ( hdev , HCI_OP_WRITE_CLASS_OF_DEV ) ;
if ( ! sent )
return ;
2005-04-17 02:20:36 +04:00
2008-07-14 22:13:47 +04:00
memcpy ( hdev - > dev_class , sent , 3 ) ;
2007-10-20 15:33:56 +04:00
}
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
static void hci_cc_read_voice_setting ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_rp_read_voice_setting * rp = ( void * ) skb - > data ;
__u16 setting ;
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
if ( rp - > status )
return ;
setting = __le16_to_cpu ( rp - > voice_setting ) ;
2008-07-14 22:13:47 +04:00
if ( hdev - > voice_setting = = setting )
2007-10-20 15:33:56 +04:00
return ;
hdev - > voice_setting = setting ;
BT_DBG ( " %s voice setting 0x%04x " , hdev - > name , setting ) ;
if ( hdev - > notify ) {
tasklet_disable ( & hdev - > tx_task ) ;
hdev - > notify ( hdev , HCI_NOTIFY_VOICE_SETTING ) ;
tasklet_enable ( & hdev - > tx_task ) ;
}
}
static void hci_cc_write_voice_setting ( struct hci_dev * hdev , struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
2008-07-14 22:13:47 +04:00
__u16 setting ;
2007-10-20 15:33:56 +04:00
void * sent ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
2005-04-17 02:20:36 +04:00
2008-07-14 22:13:47 +04:00
if ( status )
return ;
2007-10-20 15:33:56 +04:00
sent = hci_sent_cmd_data ( hdev , HCI_OP_WRITE_VOICE_SETTING ) ;
if ( ! sent )
return ;
2005-04-17 02:20:36 +04:00
2008-07-14 22:13:47 +04:00
setting = get_unaligned_le16 ( sent ) ;
2005-04-17 02:20:36 +04:00
2008-07-14 22:13:47 +04:00
if ( hdev - > voice_setting = = setting )
return ;
hdev - > voice_setting = setting ;
2005-04-17 02:20:36 +04:00
2008-07-14 22:13:47 +04:00
BT_DBG ( " %s voice setting 0x%04x " , hdev - > name , setting ) ;
2005-04-17 02:20:36 +04:00
2008-07-14 22:13:47 +04:00
if ( hdev - > notify ) {
tasklet_disable ( & hdev - > tx_task ) ;
hdev - > notify ( hdev , HCI_NOTIFY_VOICE_SETTING ) ;
tasklet_enable ( & hdev - > tx_task ) ;
2005-04-17 02:20:36 +04:00
}
}
2007-10-20 15:33:56 +04:00
static void hci_cc_host_buffer_size ( struct hci_dev * hdev , struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
2007-10-20 15:33:56 +04:00
__u8 status = * ( ( __u8 * ) skb - > data ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
hci_req_complete ( hdev , status ) ;
}
2006-09-23 11:57:20 +04:00
2008-07-14 22:13:48 +04:00
static void hci_cc_read_ssp_mode ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_rp_read_ssp_mode * rp = ( void * ) skb - > data ;
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
if ( rp - > status )
return ;
hdev - > ssp_mode = rp - > mode ;
}
static void hci_cc_write_ssp_mode ( struct hci_dev * hdev , struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
void * sent ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
if ( status )
return ;
sent = hci_sent_cmd_data ( hdev , HCI_OP_WRITE_SSP_MODE ) ;
if ( ! sent )
return ;
hdev - > ssp_mode = * ( ( __u8 * ) sent ) ;
}
2007-10-20 15:33:56 +04:00
static void hci_cc_read_local_version ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_rp_read_local_version * rp = ( void * ) skb - > data ;
2006-09-23 11:57:20 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
2006-09-23 11:57:20 +04:00
2007-10-20 15:33:56 +04:00
if ( rp - > status )
return ;
2006-09-23 11:57:20 +04:00
2007-10-20 15:33:56 +04:00
hdev - > hci_ver = rp - > hci_ver ;
2008-07-14 22:13:47 +04:00
hdev - > hci_rev = __le16_to_cpu ( rp - > hci_rev ) ;
hdev - > manufacturer = __le16_to_cpu ( rp - > manufacturer ) ;
2006-09-23 11:57:20 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s manufacturer %d hci ver %d:%d " , hdev - > name ,
hdev - > manufacturer ,
hdev - > hci_ver , hdev - > hci_rev ) ;
}
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
static void hci_cc_read_local_commands ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_rp_read_local_commands * rp = ( void * ) skb - > data ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( rp - > status )
return ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
memcpy ( hdev - > commands , rp - > commands , sizeof ( hdev - > commands ) ) ;
}
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
static void hci_cc_read_local_features ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_rp_read_local_features * rp = ( void * ) skb - > data ;
2007-07-11 11:51:55 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( rp - > status )
return ;
2007-07-11 11:51:55 +04:00
2007-10-20 15:33:56 +04:00
memcpy ( hdev - > features , rp - > features , 8 ) ;
2007-07-11 11:51:55 +04:00
2007-10-20 15:33:56 +04:00
/* Adjust default settings according to features
* supported by device . */
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( hdev - > features [ 0 ] & LMP_3SLOT )
hdev - > pkt_type | = ( HCI_DM3 | HCI_DH3 ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( hdev - > features [ 0 ] & LMP_5SLOT )
hdev - > pkt_type | = ( HCI_DM5 | HCI_DH5 ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( hdev - > features [ 1 ] & LMP_HV2 ) {
hdev - > pkt_type | = ( HCI_HV2 ) ;
hdev - > esco_type | = ( ESCO_HV2 ) ;
}
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( hdev - > features [ 1 ] & LMP_HV3 ) {
hdev - > pkt_type | = ( HCI_HV3 ) ;
hdev - > esco_type | = ( ESCO_HV3 ) ;
}
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( hdev - > features [ 3 ] & LMP_ESCO )
hdev - > esco_type | = ( ESCO_EV3 ) ;
2006-07-03 12:02:29 +04:00
2007-10-20 15:33:56 +04:00
if ( hdev - > features [ 4 ] & LMP_EV4 )
hdev - > esco_type | = ( ESCO_EV4 ) ;
2006-07-03 12:02:29 +04:00
2007-10-20 15:33:56 +04:00
if ( hdev - > features [ 4 ] & LMP_EV5 )
hdev - > esco_type | = ( ESCO_EV5 ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x " , hdev - > name ,
hdev - > features [ 0 ] , hdev - > features [ 1 ] ,
hdev - > features [ 2 ] , hdev - > features [ 3 ] ,
hdev - > features [ 4 ] , hdev - > features [ 5 ] ,
hdev - > features [ 6 ] , hdev - > features [ 7 ] ) ;
}
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
static void hci_cc_read_buffer_size ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_rp_read_buffer_size * rp = ( void * ) skb - > data ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( rp - > status )
return ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
hdev - > acl_mtu = __le16_to_cpu ( rp - > acl_mtu ) ;
hdev - > sco_mtu = rp - > sco_mtu ;
hdev - > acl_pkts = __le16_to_cpu ( rp - > acl_max_pkt ) ;
hdev - > sco_pkts = __le16_to_cpu ( rp - > sco_max_pkt ) ;
if ( test_bit ( HCI_QUIRK_FIXUP_BUFFER_SIZE , & hdev - > quirks ) ) {
hdev - > sco_mtu = 64 ;
hdev - > sco_pkts = 8 ;
2005-04-17 02:20:36 +04:00
}
2007-10-20 15:33:56 +04:00
hdev - > acl_cnt = hdev - > acl_pkts ;
hdev - > sco_cnt = hdev - > sco_pkts ;
BT_DBG ( " %s acl mtu %d:%d sco mtu %d:%d " , hdev - > name ,
hdev - > acl_mtu , hdev - > acl_pkts ,
hdev - > sco_mtu , hdev - > sco_pkts ) ;
}
static void hci_cc_read_bd_addr ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_rp_read_bd_addr * rp = ( void * ) skb - > data ;
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
if ( ! rp - > status )
bacpy ( & hdev - > bdaddr , & rp - > bdaddr ) ;
hci_req_complete ( hdev , rp - > status ) ;
}
static inline void hci_cs_inquiry ( struct hci_dev * hdev , __u8 status )
{
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
if ( status ) {
hci_req_complete ( hdev , status ) ;
hci_conn_check_pending ( hdev ) ;
} else
set_bit ( HCI_INQUIRY , & hdev - > flags ) ;
2005-04-17 02:20:36 +04:00
}
static inline void hci_cs_create_conn ( struct hci_dev * hdev , __u8 status )
{
2007-10-20 15:33:56 +04:00
struct hci_cp_create_conn * cp ;
2005-04-17 02:20:36 +04:00
struct hci_conn * conn ;
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
cp = hci_sent_cmd_data ( hdev , HCI_OP_CREATE_CONN ) ;
2005-04-17 02:20:36 +04:00
if ( ! cp )
return ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_ba ( hdev , ACL_LINK , & cp - > bdaddr ) ;
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s bdaddr %s conn %p " , hdev - > name , batostr ( & cp - > bdaddr ) , conn ) ;
2005-04-17 02:20:36 +04:00
if ( status ) {
if ( conn & & conn - > state = = BT_CONNECT ) {
2006-10-15 19:30:56 +04:00
if ( status ! = 0x0c | | conn - > attempt > 2 ) {
conn - > state = BT_CLOSED ;
hci_proto_connect_cfm ( conn , status ) ;
hci_conn_del ( conn ) ;
} else
conn - > state = BT_CONNECT2 ;
2005-04-17 02:20:36 +04:00
}
} else {
if ( ! conn ) {
conn = hci_conn_add ( hdev , ACL_LINK , & cp - > bdaddr ) ;
if ( conn ) {
conn - > out = 1 ;
conn - > link_mode | = HCI_LM_MASTER ;
} else
BT_ERR ( " No memmory for new connection " ) ;
}
}
hci_dev_unlock ( hdev ) ;
}
2007-10-20 15:33:56 +04:00
static void hci_cs_add_sco ( struct hci_dev * hdev , __u8 status )
2005-04-17 02:20:36 +04:00
{
2007-10-20 15:33:56 +04:00
struct hci_cp_add_sco * cp ;
struct hci_conn * acl , * sco ;
__u16 handle ;
2005-04-17 02:20:36 +04:00
2007-10-20 16:55:10 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
2007-10-20 15:33:56 +04:00
if ( ! status )
return ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
cp = hci_sent_cmd_data ( hdev , HCI_OP_ADD_SCO ) ;
if ( ! cp )
return ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
handle = __le16_to_cpu ( cp - > handle ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s handle %d " , hdev - > name , handle ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
hci_dev_lock ( hdev ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
acl = hci_conn_hash_lookup_handle ( hdev , handle ) ;
if ( acl & & ( sco = acl - > link ) ) {
sco - > state = BT_CLOSED ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
hci_proto_connect_cfm ( sco , status ) ;
hci_conn_del ( sco ) ;
}
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
hci_dev_unlock ( hdev ) ;
}
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
static void hci_cs_remote_name_req ( struct hci_dev * hdev , __u8 status )
{
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
}
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
static void hci_cs_setup_sync_conn ( struct hci_dev * hdev , __u8 status )
{
2007-10-20 16:55:10 +04:00
struct hci_cp_setup_sync_conn * cp ;
struct hci_conn * acl , * sco ;
__u16 handle ;
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
2007-10-20 16:55:10 +04:00
if ( ! status )
return ;
cp = hci_sent_cmd_data ( hdev , HCI_OP_SETUP_SYNC_CONN ) ;
if ( ! cp )
return ;
handle = __le16_to_cpu ( cp - > handle ) ;
BT_DBG ( " %s handle %d " , hdev - > name , handle ) ;
hci_dev_lock ( hdev ) ;
acl = hci_conn_hash_lookup_handle ( hdev , handle ) ;
if ( acl & & ( sco = acl - > link ) ) {
sco - > state = BT_CLOSED ;
hci_proto_connect_cfm ( sco , status ) ;
hci_conn_del ( sco ) ;
}
hci_dev_unlock ( hdev ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-20 15:33:56 +04:00
static void hci_cs_sniff_mode ( struct hci_dev * hdev , __u8 status )
2005-04-17 02:20:36 +04:00
{
2007-10-20 15:33:56 +04:00
struct hci_cp_sniff_mode * cp ;
struct hci_conn * conn ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
2006-07-03 12:02:33 +04:00
2007-10-20 15:33:56 +04:00
if ( ! status )
return ;
2006-07-03 12:02:33 +04:00
2007-10-20 15:33:56 +04:00
cp = hci_sent_cmd_data ( hdev , HCI_OP_SNIFF_MODE ) ;
if ( ! cp )
return ;
2006-07-03 12:02:33 +04:00
2007-10-20 15:33:56 +04:00
hci_dev_lock ( hdev ) ;
2006-07-03 12:02:33 +04:00
2007-10-20 15:33:56 +04:00
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( cp - > handle ) ) ;
if ( conn )
clear_bit ( HCI_CONN_MODE_CHANGE_PEND , & conn - > pend ) ;
2006-07-03 12:02:33 +04:00
2007-10-20 15:33:56 +04:00
hci_dev_unlock ( hdev ) ;
}
2006-07-03 12:02:33 +04:00
2007-10-20 15:33:56 +04:00
static void hci_cs_exit_sniff_mode ( struct hci_dev * hdev , __u8 status )
{
struct hci_cp_exit_sniff_mode * cp ;
struct hci_conn * conn ;
2006-07-03 12:02:33 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
2006-07-03 12:02:33 +04:00
2007-10-20 15:33:56 +04:00
if ( ! status )
return ;
2006-07-03 12:02:33 +04:00
2007-10-20 15:33:56 +04:00
cp = hci_sent_cmd_data ( hdev , HCI_OP_EXIT_SNIFF_MODE ) ;
if ( ! cp )
return ;
2006-07-03 12:02:33 +04:00
2007-10-20 15:33:56 +04:00
hci_dev_lock ( hdev ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( cp - > handle ) ) ;
if ( conn )
clear_bit ( HCI_CONN_MODE_CHANGE_PEND , & conn - > pend ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
hci_dev_unlock ( hdev ) ;
2005-04-17 02:20:36 +04:00
}
static inline void hci_inquiry_complete_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
BT_DBG ( " %s status %d " , hdev - > name , status ) ;
clear_bit ( HCI_INQUIRY , & hdev - > flags ) ;
2006-11-19 00:14:22 +03:00
2007-10-20 15:33:56 +04:00
hci_req_complete ( hdev , status ) ;
2006-11-19 00:14:22 +03:00
2007-10-20 15:33:56 +04:00
hci_conn_check_pending ( hdev ) ;
2005-04-17 02:20:36 +04:00
}
static inline void hci_inquiry_result_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
2005-08-10 07:27:49 +04:00
struct inquiry_data data ;
2007-10-20 15:33:56 +04:00
struct inquiry_info * info = ( void * ) ( skb - > data + 1 ) ;
2005-04-17 02:20:36 +04:00
int num_rsp = * ( ( __u8 * ) skb - > data ) ;
BT_DBG ( " %s num_rsp %d " , hdev - > name , num_rsp ) ;
2005-08-10 07:27:49 +04:00
if ( ! num_rsp )
return ;
2005-04-17 02:20:36 +04:00
hci_dev_lock ( hdev ) ;
2005-08-10 07:27:49 +04:00
2005-04-17 02:20:36 +04:00
for ( ; num_rsp ; num_rsp - - ) {
bacpy ( & data . bdaddr , & info - > bdaddr ) ;
data . pscan_rep_mode = info - > pscan_rep_mode ;
data . pscan_period_mode = info - > pscan_period_mode ;
data . pscan_mode = info - > pscan_mode ;
memcpy ( data . dev_class , info - > dev_class , 3 ) ;
data . clock_offset = info - > clock_offset ;
data . rssi = 0x00 ;
2008-07-14 22:13:48 +04:00
data . ssp_mode = 0x00 ;
2005-04-17 02:20:36 +04:00
info + + ;
hci_inquiry_cache_update ( hdev , & data ) ;
}
2005-08-10 07:27:49 +04:00
2005-04-17 02:20:36 +04:00
hci_dev_unlock ( hdev ) ;
}
static inline void hci_conn_complete_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
2007-10-20 15:33:56 +04:00
struct hci_ev_conn_complete * ev = ( void * ) skb - > data ;
struct hci_conn * conn ;
2005-04-17 02:20:36 +04:00
BT_DBG ( " %s " , hdev - > name ) ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_ba ( hdev , ev - > link_type , & ev - > bdaddr ) ;
2007-10-20 15:33:56 +04:00
if ( ! conn )
goto unlock ;
2005-04-17 02:20:36 +04:00
if ( ! ev - > status ) {
conn - > handle = __le16_to_cpu ( ev - > handle ) ;
conn - > state = BT_CONNECTED ;
if ( test_bit ( HCI_AUTH , & hdev - > flags ) )
conn - > link_mode | = HCI_LM_AUTH ;
if ( test_bit ( HCI_ENCRYPT , & hdev - > flags ) )
conn - > link_mode | = HCI_LM_ENCRYPT ;
2006-07-03 12:02:33 +04:00
/* Get remote features */
if ( conn - > type = = ACL_LINK ) {
struct hci_cp_read_remote_features cp ;
cp . handle = ev - > handle ;
2007-10-20 15:33:56 +04:00
hci_send_cmd ( hdev , HCI_OP_READ_REMOTE_FEATURES , sizeof ( cp ) , & cp ) ;
2006-07-03 12:02:33 +04:00
}
2005-04-17 02:20:36 +04:00
/* Set packet type for incoming connection */
2008-07-14 22:13:46 +04:00
if ( ! conn - > out & & hdev - > hci_ver < 3 ) {
2005-04-17 02:20:36 +04:00
struct hci_cp_change_conn_ptype cp ;
cp . handle = ev - > handle ;
2008-07-14 22:13:46 +04:00
cp . pkt_type = cpu_to_le16 ( conn - > pkt_type ) ;
hci_send_cmd ( hdev , HCI_OP_CHANGE_CONN_PTYPE ,
sizeof ( cp ) , & cp ) ;
2006-09-29 02:29:09 +04:00
} else {
/* Update disconnect timer */
hci_conn_hold ( conn ) ;
hci_conn_put ( conn ) ;
2005-04-17 02:20:36 +04:00
}
} else
conn - > state = BT_CLOSED ;
if ( conn - > type = = ACL_LINK ) {
struct hci_conn * sco = conn - > link ;
if ( sco ) {
2007-10-20 16:55:10 +04:00
if ( ! ev - > status ) {
if ( lmp_esco_capable ( hdev ) )
hci_setup_sync ( sco , conn - > handle ) ;
else
hci_add_sco ( sco , conn - > handle ) ;
} else {
2005-04-17 02:20:36 +04:00
hci_proto_connect_cfm ( sco , ev - > status ) ;
hci_conn_del ( sco ) ;
}
}
}
hci_proto_connect_cfm ( conn , ev - > status ) ;
if ( ev - > status )
hci_conn_del ( conn ) ;
2007-10-20 15:33:56 +04:00
unlock :
2005-04-17 02:20:36 +04:00
hci_dev_unlock ( hdev ) ;
2007-10-20 15:33:56 +04:00
hci_conn_check_pending ( hdev ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-20 15:33:56 +04:00
static inline void hci_conn_request_evt ( struct hci_dev * hdev , struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
2007-10-20 15:33:56 +04:00
struct hci_ev_conn_request * ev = ( void * ) skb - > data ;
int mask = hdev - > link_mode ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s bdaddr %s type 0x%x " , hdev - > name ,
batostr ( & ev - > bdaddr ) , ev - > link_type ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
mask | = hci_proto_connect_ind ( hdev , & ev - > bdaddr , ev - > link_type ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( mask & HCI_LM_ACCEPT ) {
/* Connection accepted */
2008-07-14 22:13:47 +04:00
struct inquiry_entry * ie ;
2005-04-17 02:20:36 +04:00
struct hci_conn * conn ;
2007-10-20 15:33:56 +04:00
hci_dev_lock ( hdev ) ;
2007-10-20 16:55:10 +04:00
2008-07-14 22:13:47 +04:00
if ( ( ie = hci_inquiry_cache_lookup ( hdev , & ev - > bdaddr ) ) )
memcpy ( ie - > data . dev_class , ev - > dev_class , 3 ) ;
2007-10-20 15:33:56 +04:00
conn = hci_conn_hash_lookup_ba ( hdev , ev - > link_type , & ev - > bdaddr ) ;
if ( ! conn ) {
if ( ! ( conn = hci_conn_add ( hdev , ev - > link_type , & ev - > bdaddr ) ) ) {
BT_ERR ( " No memmory for new connection " ) ;
hci_dev_unlock ( hdev ) ;
return ;
2005-04-17 02:20:36 +04:00
}
}
2007-10-20 16:55:10 +04:00
2007-10-20 15:33:56 +04:00
memcpy ( conn - > dev_class , ev - > dev_class , 3 ) ;
conn - > state = BT_CONNECT ;
2007-10-20 16:55:10 +04:00
2007-10-20 15:33:56 +04:00
hci_dev_unlock ( hdev ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 16:55:10 +04:00
if ( ev - > link_type = = ACL_LINK | | ! lmp_esco_capable ( hdev ) ) {
struct hci_cp_accept_conn_req cp ;
2005-04-17 02:20:36 +04:00
2007-10-20 16:55:10 +04:00
bacpy ( & cp . bdaddr , & ev - > bdaddr ) ;
if ( lmp_rswitch_capable ( hdev ) & & ( mask & HCI_LM_MASTER ) )
cp . role = 0x00 ; /* Become master */
else
cp . role = 0x01 ; /* Remain slave */
hci_send_cmd ( hdev , HCI_OP_ACCEPT_CONN_REQ ,
sizeof ( cp ) , & cp ) ;
} else {
struct hci_cp_accept_sync_conn_req cp ;
bacpy ( & cp . bdaddr , & ev - > bdaddr ) ;
2008-07-14 22:13:46 +04:00
cp . pkt_type = cpu_to_le16 ( conn - > pkt_type ) ;
2007-10-20 16:55:10 +04:00
cp . tx_bandwidth = cpu_to_le32 ( 0x00001f40 ) ;
cp . rx_bandwidth = cpu_to_le32 ( 0x00001f40 ) ;
cp . max_latency = cpu_to_le16 ( 0xffff ) ;
cp . content_format = cpu_to_le16 ( hdev - > voice_setting ) ;
cp . retrans_effort = 0xff ;
2005-04-17 02:20:36 +04:00
2007-10-20 16:55:10 +04:00
hci_send_cmd ( hdev , HCI_OP_ACCEPT_SYNC_CONN_REQ ,
sizeof ( cp ) , & cp ) ;
}
2007-10-20 15:33:56 +04:00
} else {
/* Connection rejected */
struct hci_cp_reject_conn_req cp ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
bacpy ( & cp . bdaddr , & ev - > bdaddr ) ;
cp . reason = 0x0f ;
hci_send_cmd ( hdev , HCI_OP_REJECT_CONN_REQ , sizeof ( cp ) , & cp ) ;
2005-04-17 02:20:36 +04:00
}
}
2007-10-20 15:33:56 +04:00
static inline void hci_disconn_complete_evt ( struct hci_dev * hdev , struct sk_buff * skb )
2006-07-03 12:02:33 +04:00
{
2007-10-20 15:33:56 +04:00
struct hci_ev_disconn_complete * ev = ( void * ) skb - > data ;
2006-07-03 12:02:33 +04:00
struct hci_conn * conn ;
BT_DBG ( " %s status %d " , hdev - > name , ev - > status ) ;
2007-10-20 15:33:56 +04:00
if ( ev - > status )
return ;
2006-07-03 12:02:33 +04:00
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( ev - > handle ) ) ;
if ( conn ) {
2007-10-20 15:33:56 +04:00
conn - > state = BT_CLOSED ;
hci_proto_disconn_ind ( conn , ev - > reason ) ;
hci_conn_del ( conn ) ;
2006-07-03 12:02:33 +04:00
}
hci_dev_unlock ( hdev ) ;
}
2005-04-17 02:20:36 +04:00
static inline void hci_auth_complete_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
2007-10-20 15:33:56 +04:00
struct hci_ev_auth_complete * ev = ( void * ) skb - > data ;
2006-07-03 12:02:33 +04:00
struct hci_conn * conn ;
2005-04-17 02:20:36 +04:00
BT_DBG ( " %s status %d " , hdev - > name , ev - > status ) ;
hci_dev_lock ( hdev ) ;
2006-07-03 12:02:33 +04:00
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( ev - > handle ) ) ;
2005-04-17 02:20:36 +04:00
if ( conn ) {
if ( ! ev - > status )
conn - > link_mode | = HCI_LM_AUTH ;
clear_bit ( HCI_CONN_AUTH_PEND , & conn - > pend ) ;
hci_auth_cfm ( conn , ev - > status ) ;
if ( test_bit ( HCI_CONN_ENCRYPT_PEND , & conn - > pend ) ) {
if ( ! ev - > status ) {
struct hci_cp_set_conn_encrypt cp ;
2007-03-26 07:12:50 +04:00
cp . handle = cpu_to_le16 ( conn - > handle ) ;
2005-04-17 02:20:36 +04:00
cp . encrypt = 1 ;
2007-10-20 15:33:56 +04:00
hci_send_cmd ( conn - > hdev ,
HCI_OP_SET_CONN_ENCRYPT , sizeof ( cp ) , & cp ) ;
2005-04-17 02:20:36 +04:00
} else {
clear_bit ( HCI_CONN_ENCRYPT_PEND , & conn - > pend ) ;
hci_encrypt_cfm ( conn , ev - > status , 0x00 ) ;
}
}
}
hci_dev_unlock ( hdev ) ;
}
2007-10-20 15:33:56 +04:00
static inline void hci_remote_name_evt ( struct hci_dev * hdev , struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s " , hdev - > name ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
hci_conn_check_pending ( hdev ) ;
}
static inline void hci_encrypt_change_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_ev_encrypt_change * ev = ( void * ) skb - > data ;
struct hci_conn * conn ;
BT_DBG ( " %s status %d " , hdev - > name , ev - > status ) ;
2005-04-17 02:20:36 +04:00
hci_dev_lock ( hdev ) ;
2006-07-03 12:02:33 +04:00
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( ev - > handle ) ) ;
2005-04-17 02:20:36 +04:00
if ( conn ) {
if ( ! ev - > status ) {
2008-07-14 22:13:45 +04:00
if ( ev - > encrypt ) {
/* Encryption implies authentication */
conn - > link_mode | = HCI_LM_AUTH ;
2005-04-17 02:20:36 +04:00
conn - > link_mode | = HCI_LM_ENCRYPT ;
2008-07-14 22:13:45 +04:00
} else
2005-04-17 02:20:36 +04:00
conn - > link_mode & = ~ HCI_LM_ENCRYPT ;
}
clear_bit ( HCI_CONN_ENCRYPT_PEND , & conn - > pend ) ;
hci_encrypt_cfm ( conn , ev - > status , ev - > encrypt ) ;
}
hci_dev_unlock ( hdev ) ;
}
2007-10-20 15:33:56 +04:00
static inline void hci_change_link_key_complete_evt ( struct hci_dev * hdev , struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
2007-10-20 15:33:56 +04:00
struct hci_ev_change_link_key_complete * ev = ( void * ) skb - > data ;
2006-07-03 12:02:33 +04:00
struct hci_conn * conn ;
2005-04-17 02:20:36 +04:00
BT_DBG ( " %s status %d " , hdev - > name , ev - > status ) ;
hci_dev_lock ( hdev ) ;
2006-07-03 12:02:33 +04:00
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( ev - > handle ) ) ;
2005-04-17 02:20:36 +04:00
if ( conn ) {
if ( ! ev - > status )
conn - > link_mode | = HCI_LM_SECURE ;
clear_bit ( HCI_CONN_AUTH_PEND , & conn - > pend ) ;
hci_key_change_cfm ( conn , ev - > status ) ;
}
hci_dev_unlock ( hdev ) ;
}
2007-10-20 15:33:56 +04:00
static inline void hci_remote_features_evt ( struct hci_dev * hdev , struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
2007-10-20 15:33:56 +04:00
struct hci_ev_remote_features * ev = ( void * ) skb - > data ;
struct hci_conn * conn ;
BT_DBG ( " %s status %d " , hdev - > name , ev - > status ) ;
if ( ev - > status )
return ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( ev - > handle ) ) ;
if ( conn )
memcpy ( conn - > features , ev - > features , 8 ) ;
hci_dev_unlock ( hdev ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-20 15:33:56 +04:00
static inline void hci_remote_version_evt ( struct hci_dev * hdev , struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s " , hdev - > name ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-20 15:33:56 +04:00
static inline void hci_qos_setup_complete_evt ( struct hci_dev * hdev , struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s " , hdev - > name ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-20 15:33:56 +04:00
static inline void hci_cmd_complete_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_ev_cmd_complete * ev = ( void * ) skb - > data ;
__u16 opcode ;
skb_pull ( skb , sizeof ( * ev ) ) ;
opcode = __le16_to_cpu ( ev - > opcode ) ;
switch ( opcode ) {
case HCI_OP_INQUIRY_CANCEL :
hci_cc_inquiry_cancel ( hdev , skb ) ;
break ;
case HCI_OP_EXIT_PERIODIC_INQ :
hci_cc_exit_periodic_inq ( hdev , skb ) ;
break ;
case HCI_OP_REMOTE_NAME_REQ_CANCEL :
hci_cc_remote_name_req_cancel ( hdev , skb ) ;
break ;
case HCI_OP_ROLE_DISCOVERY :
hci_cc_role_discovery ( hdev , skb ) ;
break ;
2008-07-14 22:13:47 +04:00
case HCI_OP_READ_LINK_POLICY :
hci_cc_read_link_policy ( hdev , skb ) ;
break ;
2007-10-20 15:33:56 +04:00
case HCI_OP_WRITE_LINK_POLICY :
hci_cc_write_link_policy ( hdev , skb ) ;
break ;
2008-07-14 22:13:47 +04:00
case HCI_OP_READ_DEF_LINK_POLICY :
hci_cc_read_def_link_policy ( hdev , skb ) ;
break ;
case HCI_OP_WRITE_DEF_LINK_POLICY :
hci_cc_write_def_link_policy ( hdev , skb ) ;
break ;
2007-10-20 15:33:56 +04:00
case HCI_OP_RESET :
hci_cc_reset ( hdev , skb ) ;
break ;
case HCI_OP_WRITE_LOCAL_NAME :
hci_cc_write_local_name ( hdev , skb ) ;
break ;
case HCI_OP_READ_LOCAL_NAME :
hci_cc_read_local_name ( hdev , skb ) ;
break ;
case HCI_OP_WRITE_AUTH_ENABLE :
hci_cc_write_auth_enable ( hdev , skb ) ;
break ;
case HCI_OP_WRITE_ENCRYPT_MODE :
hci_cc_write_encrypt_mode ( hdev , skb ) ;
break ;
case HCI_OP_WRITE_SCAN_ENABLE :
hci_cc_write_scan_enable ( hdev , skb ) ;
break ;
case HCI_OP_READ_CLASS_OF_DEV :
hci_cc_read_class_of_dev ( hdev , skb ) ;
break ;
case HCI_OP_WRITE_CLASS_OF_DEV :
hci_cc_write_class_of_dev ( hdev , skb ) ;
break ;
case HCI_OP_READ_VOICE_SETTING :
hci_cc_read_voice_setting ( hdev , skb ) ;
break ;
case HCI_OP_WRITE_VOICE_SETTING :
hci_cc_write_voice_setting ( hdev , skb ) ;
break ;
case HCI_OP_HOST_BUFFER_SIZE :
hci_cc_host_buffer_size ( hdev , skb ) ;
break ;
2008-07-14 22:13:48 +04:00
case HCI_OP_READ_SSP_MODE :
hci_cc_read_ssp_mode ( hdev , skb ) ;
break ;
case HCI_OP_WRITE_SSP_MODE :
hci_cc_write_ssp_mode ( hdev , skb ) ;
break ;
2007-10-20 15:33:56 +04:00
case HCI_OP_READ_LOCAL_VERSION :
hci_cc_read_local_version ( hdev , skb ) ;
break ;
case HCI_OP_READ_LOCAL_COMMANDS :
hci_cc_read_local_commands ( hdev , skb ) ;
break ;
case HCI_OP_READ_LOCAL_FEATURES :
hci_cc_read_local_features ( hdev , skb ) ;
break ;
case HCI_OP_READ_BUFFER_SIZE :
hci_cc_read_buffer_size ( hdev , skb ) ;
break ;
case HCI_OP_READ_BD_ADDR :
hci_cc_read_bd_addr ( hdev , skb ) ;
break ;
default :
BT_DBG ( " %s opcode 0x%x " , hdev - > name , opcode ) ;
break ;
}
if ( ev - > ncmd ) {
atomic_set ( & hdev - > cmd_cnt , 1 ) ;
if ( ! skb_queue_empty ( & hdev - > cmd_q ) )
hci_sched_cmd ( hdev ) ;
}
}
static inline void hci_cmd_status_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_ev_cmd_status * ev = ( void * ) skb - > data ;
__u16 opcode ;
skb_pull ( skb , sizeof ( * ev ) ) ;
opcode = __le16_to_cpu ( ev - > opcode ) ;
switch ( opcode ) {
case HCI_OP_INQUIRY :
hci_cs_inquiry ( hdev , ev - > status ) ;
break ;
case HCI_OP_CREATE_CONN :
hci_cs_create_conn ( hdev , ev - > status ) ;
break ;
case HCI_OP_ADD_SCO :
hci_cs_add_sco ( hdev , ev - > status ) ;
break ;
case HCI_OP_REMOTE_NAME_REQ :
hci_cs_remote_name_req ( hdev , ev - > status ) ;
break ;
case HCI_OP_SETUP_SYNC_CONN :
hci_cs_setup_sync_conn ( hdev , ev - > status ) ;
break ;
case HCI_OP_SNIFF_MODE :
hci_cs_sniff_mode ( hdev , ev - > status ) ;
break ;
case HCI_OP_EXIT_SNIFF_MODE :
hci_cs_exit_sniff_mode ( hdev , ev - > status ) ;
break ;
default :
BT_DBG ( " %s opcode 0x%x " , hdev - > name , opcode ) ;
break ;
}
if ( ev - > ncmd ) {
atomic_set ( & hdev - > cmd_cnt , 1 ) ;
if ( ! skb_queue_empty ( & hdev - > cmd_q ) )
hci_sched_cmd ( hdev ) ;
}
}
static inline void hci_role_change_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_ev_role_change * ev = ( void * ) skb - > data ;
struct hci_conn * conn ;
BT_DBG ( " %s status %d " , hdev - > name , ev - > status ) ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_ba ( hdev , ACL_LINK , & ev - > bdaddr ) ;
if ( conn ) {
if ( ! ev - > status ) {
if ( ev - > role )
conn - > link_mode & = ~ HCI_LM_MASTER ;
else
conn - > link_mode | = HCI_LM_MASTER ;
}
clear_bit ( HCI_CONN_RSWITCH_PEND , & conn - > pend ) ;
hci_role_switch_cfm ( conn , ev - > status , ev - > role ) ;
}
hci_dev_unlock ( hdev ) ;
}
static inline void hci_num_comp_pkts_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_ev_num_comp_pkts * ev = ( void * ) skb - > data ;
__le16 * ptr ;
int i ;
skb_pull ( skb , sizeof ( * ev ) ) ;
BT_DBG ( " %s num_hndl %d " , hdev - > name , ev - > num_hndl ) ;
if ( skb - > len < ev - > num_hndl * 4 ) {
BT_DBG ( " %s bad parameters " , hdev - > name ) ;
return ;
}
tasklet_disable ( & hdev - > tx_task ) ;
for ( i = 0 , ptr = ( __le16 * ) skb - > data ; i < ev - > num_hndl ; i + + ) {
struct hci_conn * conn ;
__u16 handle , count ;
2008-05-03 03:25:46 +04:00
handle = get_unaligned_le16 ( ptr + + ) ;
count = get_unaligned_le16 ( ptr + + ) ;
2007-10-20 15:33:56 +04:00
conn = hci_conn_hash_lookup_handle ( hdev , handle ) ;
if ( conn ) {
conn - > sent - = count ;
if ( conn - > type = = ACL_LINK ) {
if ( ( hdev - > acl_cnt + = count ) > hdev - > acl_pkts )
hdev - > acl_cnt = hdev - > acl_pkts ;
} else {
if ( ( hdev - > sco_cnt + = count ) > hdev - > sco_pkts )
hdev - > sco_cnt = hdev - > sco_pkts ;
}
}
}
hci_sched_tx ( hdev ) ;
tasklet_enable ( & hdev - > tx_task ) ;
}
static inline void hci_mode_change_evt ( struct hci_dev * hdev , struct sk_buff * skb )
2006-07-03 12:02:33 +04:00
{
2007-10-20 15:33:56 +04:00
struct hci_ev_mode_change * ev = ( void * ) skb - > data ;
2006-07-03 12:02:33 +04:00
struct hci_conn * conn ;
BT_DBG ( " %s status %d " , hdev - > name , ev - > status ) ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( ev - > handle ) ) ;
2007-10-20 15:33:56 +04:00
if ( conn ) {
conn - > mode = ev - > mode ;
conn - > interval = __le16_to_cpu ( ev - > interval ) ;
if ( ! test_and_clear_bit ( HCI_CONN_MODE_CHANGE_PEND , & conn - > pend ) ) {
if ( conn - > mode = = HCI_CM_ACTIVE )
conn - > power_save = 1 ;
else
conn - > power_save = 0 ;
}
2006-07-03 12:02:33 +04:00
}
hci_dev_unlock ( hdev ) ;
}
2007-10-20 15:33:56 +04:00
static inline void hci_pin_code_request_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
BT_DBG ( " %s " , hdev - > name ) ;
}
static inline void hci_link_key_request_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
BT_DBG ( " %s " , hdev - > name ) ;
}
static inline void hci_link_key_notify_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
BT_DBG ( " %s " , hdev - > name ) ;
}
2005-04-17 02:20:36 +04:00
static inline void hci_clock_offset_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
2007-10-20 15:33:56 +04:00
struct hci_ev_clock_offset * ev = ( void * ) skb - > data ;
2006-07-03 12:02:33 +04:00
struct hci_conn * conn ;
2005-04-17 02:20:36 +04:00
BT_DBG ( " %s status %d " , hdev - > name , ev - > status ) ;
hci_dev_lock ( hdev ) ;
2006-07-03 12:02:33 +04:00
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( ev - > handle ) ) ;
2005-04-17 02:20:36 +04:00
if ( conn & & ! ev - > status ) {
struct inquiry_entry * ie ;
if ( ( ie = hci_inquiry_cache_lookup ( hdev , & conn - > dst ) ) ) {
ie - > data . clock_offset = ev - > clock_offset ;
ie - > timestamp = jiffies ;
}
}
hci_dev_unlock ( hdev ) ;
}
2008-07-14 22:13:46 +04:00
static inline void hci_pkt_type_change_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_ev_pkt_type_change * ev = ( void * ) skb - > data ;
struct hci_conn * conn ;
BT_DBG ( " %s status %d " , hdev - > name , ev - > status ) ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( ev - > handle ) ) ;
if ( conn & & ! ev - > status )
conn - > pkt_type = __le16_to_cpu ( ev - > pkt_type ) ;
hci_dev_unlock ( hdev ) ;
}
2005-08-10 07:28:02 +04:00
static inline void hci_pscan_rep_mode_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
2007-10-20 15:33:56 +04:00
struct hci_ev_pscan_rep_mode * ev = ( void * ) skb - > data ;
2005-08-10 07:28:02 +04:00
struct inquiry_entry * ie ;
BT_DBG ( " %s " , hdev - > name ) ;
hci_dev_lock ( hdev ) ;
if ( ( ie = hci_inquiry_cache_lookup ( hdev , & ev - > bdaddr ) ) ) {
ie - > data . pscan_rep_mode = ev - > pscan_rep_mode ;
ie - > timestamp = jiffies ;
}
hci_dev_unlock ( hdev ) ;
}
2007-10-20 15:33:56 +04:00
static inline void hci_inquiry_result_with_rssi_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct inquiry_data data ;
int num_rsp = * ( ( __u8 * ) skb - > data ) ;
BT_DBG ( " %s num_rsp %d " , hdev - > name , num_rsp ) ;
if ( ! num_rsp )
return ;
hci_dev_lock ( hdev ) ;
if ( ( skb - > len - 1 ) / num_rsp ! = sizeof ( struct inquiry_info_with_rssi ) ) {
struct inquiry_info_with_rssi_and_pscan_mode * info = ( void * ) ( skb - > data + 1 ) ;
for ( ; num_rsp ; num_rsp - - ) {
bacpy ( & data . bdaddr , & info - > bdaddr ) ;
data . pscan_rep_mode = info - > pscan_rep_mode ;
data . pscan_period_mode = info - > pscan_period_mode ;
data . pscan_mode = info - > pscan_mode ;
memcpy ( data . dev_class , info - > dev_class , 3 ) ;
data . clock_offset = info - > clock_offset ;
data . rssi = info - > rssi ;
2008-07-14 22:13:48 +04:00
data . ssp_mode = 0x00 ;
2007-10-20 15:33:56 +04:00
info + + ;
hci_inquiry_cache_update ( hdev , & data ) ;
}
} else {
struct inquiry_info_with_rssi * info = ( void * ) ( skb - > data + 1 ) ;
for ( ; num_rsp ; num_rsp - - ) {
bacpy ( & data . bdaddr , & info - > bdaddr ) ;
data . pscan_rep_mode = info - > pscan_rep_mode ;
data . pscan_period_mode = info - > pscan_period_mode ;
data . pscan_mode = 0x00 ;
memcpy ( data . dev_class , info - > dev_class , 3 ) ;
data . clock_offset = info - > clock_offset ;
data . rssi = info - > rssi ;
2008-07-14 22:13:48 +04:00
data . ssp_mode = 0x00 ;
2007-10-20 15:33:56 +04:00
info + + ;
hci_inquiry_cache_update ( hdev , & data ) ;
}
}
hci_dev_unlock ( hdev ) ;
}
static inline void hci_remote_ext_features_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
2008-07-14 22:13:48 +04:00
struct hci_ev_remote_ext_features * ev = ( void * ) skb - > data ;
struct hci_conn * conn ;
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s " , hdev - > name ) ;
2008-07-14 22:13:48 +04:00
if ( ev - > status | | ev - > page ! = 0x01 )
return ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( ev - > handle ) ) ;
if ( conn ) {
struct inquiry_entry * ie ;
if ( ( ie = hci_inquiry_cache_lookup ( hdev , & conn - > dst ) ) )
ie - > data . ssp_mode = ( ev - > features [ 0 ] & 0x01 ) ;
conn - > ssp_mode = ( ev - > features [ 0 ] & 0x01 ) ;
}
hci_dev_unlock ( hdev ) ;
2007-10-20 15:33:56 +04:00
}
static inline void hci_sync_conn_complete_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
2007-10-20 16:55:10 +04:00
struct hci_ev_sync_conn_complete * ev = ( void * ) skb - > data ;
struct hci_conn * conn ;
BT_DBG ( " %s status %d " , hdev - > name , ev - > status ) ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_ba ( hdev , ev - > link_type , & ev - > bdaddr ) ;
2008-07-14 22:13:46 +04:00
if ( ! conn ) {
if ( ev - > link_type = = ESCO_LINK )
goto unlock ;
conn = hci_conn_hash_lookup_ba ( hdev , ESCO_LINK , & ev - > bdaddr ) ;
if ( ! conn )
goto unlock ;
conn - > type = SCO_LINK ;
}
2007-10-20 16:55:10 +04:00
if ( ! ev - > status ) {
conn - > handle = __le16_to_cpu ( ev - > handle ) ;
conn - > state = BT_CONNECTED ;
} else
conn - > state = BT_CLOSED ;
hci_proto_connect_cfm ( conn , ev - > status ) ;
if ( ev - > status )
hci_conn_del ( conn ) ;
unlock :
hci_dev_unlock ( hdev ) ;
2007-10-20 15:33:56 +04:00
}
static inline void hci_sync_conn_changed_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
BT_DBG ( " %s " , hdev - > name ) ;
}
2006-07-03 12:02:33 +04:00
static inline void hci_sniff_subrate_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
2007-10-20 15:33:56 +04:00
struct hci_ev_sniff_subrate * ev = ( void * ) skb - > data ;
2006-07-03 12:02:33 +04:00
struct hci_conn * conn ;
BT_DBG ( " %s status %d " , hdev - > name , ev - > status ) ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( ev - > handle ) ) ;
if ( conn ) {
}
hci_dev_unlock ( hdev ) ;
}
2007-10-20 15:33:56 +04:00
static inline void hci_extended_inquiry_result_evt ( struct hci_dev * hdev , struct sk_buff * skb )
2005-04-17 02:20:36 +04:00
{
2007-10-20 15:33:56 +04:00
struct inquiry_data data ;
struct extended_inquiry_info * info = ( void * ) ( skb - > data + 1 ) ;
int num_rsp = * ( ( __u8 * ) skb - > data ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s num_rsp %d " , hdev - > name , num_rsp ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
if ( ! num_rsp )
return ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
hci_dev_lock ( hdev ) ;
for ( ; num_rsp ; num_rsp - - ) {
bacpy ( & data . bdaddr , & info - > bdaddr ) ;
data . pscan_rep_mode = info - > pscan_rep_mode ;
data . pscan_period_mode = info - > pscan_period_mode ;
data . pscan_mode = 0x00 ;
memcpy ( data . dev_class , info - > dev_class , 3 ) ;
data . clock_offset = info - > clock_offset ;
data . rssi = info - > rssi ;
2008-07-14 22:13:48 +04:00
data . ssp_mode = 0x01 ;
2007-10-20 15:33:56 +04:00
info + + ;
hci_inquiry_cache_update ( hdev , & data ) ;
}
hci_dev_unlock ( hdev ) ;
}
2005-04-17 02:20:36 +04:00
2008-07-14 22:13:48 +04:00
static inline void hci_io_capa_request_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_ev_io_capa_request * ev = ( void * ) skb - > data ;
struct hci_conn * conn ;
BT_DBG ( " %s " , hdev - > name ) ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_ba ( hdev , ACL_LINK , & ev - > bdaddr ) ;
if ( conn )
hci_conn_hold ( conn ) ;
hci_dev_unlock ( hdev ) ;
}
static inline void hci_simple_pair_complete_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_ev_simple_pair_complete * ev = ( void * ) skb - > data ;
struct hci_conn * conn ;
BT_DBG ( " %s " , hdev - > name ) ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_ba ( hdev , ACL_LINK , & ev - > bdaddr ) ;
if ( conn )
hci_conn_put ( conn ) ;
hci_dev_unlock ( hdev ) ;
}
2008-07-14 22:13:48 +04:00
static inline void hci_remote_host_features_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_ev_remote_host_features * ev = ( void * ) skb - > data ;
struct inquiry_entry * ie ;
BT_DBG ( " %s " , hdev - > name ) ;
hci_dev_lock ( hdev ) ;
if ( ( ie = hci_inquiry_cache_lookup ( hdev , & ev - > bdaddr ) ) )
ie - > data . ssp_mode = ( ev - > features [ 0 ] & 0x01 ) ;
hci_dev_unlock ( hdev ) ;
}
2007-10-20 15:33:56 +04:00
void hci_event_packet ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_event_hdr * hdr = ( void * ) skb - > data ;
__u8 event = hdr - > evt ;
skb_pull ( skb , HCI_EVENT_HDR_SIZE ) ;
switch ( event ) {
2005-04-17 02:20:36 +04:00
case HCI_EV_INQUIRY_COMPLETE :
hci_inquiry_complete_evt ( hdev , skb ) ;
break ;
case HCI_EV_INQUIRY_RESULT :
hci_inquiry_result_evt ( hdev , skb ) ;
break ;
2007-10-20 15:33:56 +04:00
case HCI_EV_CONN_COMPLETE :
hci_conn_complete_evt ( hdev , skb ) ;
2005-09-13 03:32:25 +04:00
break ;
2005-04-17 02:20:36 +04:00
case HCI_EV_CONN_REQUEST :
hci_conn_request_evt ( hdev , skb ) ;
break ;
case HCI_EV_DISCONN_COMPLETE :
hci_disconn_complete_evt ( hdev , skb ) ;
break ;
case HCI_EV_AUTH_COMPLETE :
hci_auth_complete_evt ( hdev , skb ) ;
break ;
2007-10-20 15:33:56 +04:00
case HCI_EV_REMOTE_NAME :
hci_remote_name_evt ( hdev , skb ) ;
break ;
2005-04-17 02:20:36 +04:00
case HCI_EV_ENCRYPT_CHANGE :
hci_encrypt_change_evt ( hdev , skb ) ;
break ;
2007-10-20 15:33:56 +04:00
case HCI_EV_CHANGE_LINK_KEY_COMPLETE :
hci_change_link_key_complete_evt ( hdev , skb ) ;
break ;
case HCI_EV_REMOTE_FEATURES :
hci_remote_features_evt ( hdev , skb ) ;
break ;
case HCI_EV_REMOTE_VERSION :
hci_remote_version_evt ( hdev , skb ) ;
break ;
case HCI_EV_QOS_SETUP_COMPLETE :
hci_qos_setup_complete_evt ( hdev , skb ) ;
break ;
case HCI_EV_CMD_COMPLETE :
hci_cmd_complete_evt ( hdev , skb ) ;
break ;
case HCI_EV_CMD_STATUS :
hci_cmd_status_evt ( hdev , skb ) ;
break ;
case HCI_EV_ROLE_CHANGE :
hci_role_change_evt ( hdev , skb ) ;
break ;
case HCI_EV_NUM_COMP_PKTS :
hci_num_comp_pkts_evt ( hdev , skb ) ;
break ;
case HCI_EV_MODE_CHANGE :
hci_mode_change_evt ( hdev , skb ) ;
2005-04-17 02:20:36 +04:00
break ;
case HCI_EV_PIN_CODE_REQ :
hci_pin_code_request_evt ( hdev , skb ) ;
break ;
case HCI_EV_LINK_KEY_REQ :
hci_link_key_request_evt ( hdev , skb ) ;
break ;
case HCI_EV_LINK_KEY_NOTIFY :
hci_link_key_notify_evt ( hdev , skb ) ;
break ;
case HCI_EV_CLOCK_OFFSET :
hci_clock_offset_evt ( hdev , skb ) ;
break ;
2008-07-14 22:13:46 +04:00
case HCI_EV_PKT_TYPE_CHANGE :
hci_pkt_type_change_evt ( hdev , skb ) ;
break ;
2005-08-10 07:28:02 +04:00
case HCI_EV_PSCAN_REP_MODE :
hci_pscan_rep_mode_evt ( hdev , skb ) ;
break ;
2007-10-20 15:33:56 +04:00
case HCI_EV_INQUIRY_RESULT_WITH_RSSI :
hci_inquiry_result_with_rssi_evt ( hdev , skb ) ;
2006-07-03 12:02:33 +04:00
break ;
2007-10-20 15:33:56 +04:00
case HCI_EV_REMOTE_EXT_FEATURES :
hci_remote_ext_features_evt ( hdev , skb ) ;
2005-04-17 02:20:36 +04:00
break ;
2007-10-20 15:33:56 +04:00
case HCI_EV_SYNC_CONN_COMPLETE :
hci_sync_conn_complete_evt ( hdev , skb ) ;
break ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
case HCI_EV_SYNC_CONN_CHANGED :
hci_sync_conn_changed_evt ( hdev , skb ) ;
break ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
case HCI_EV_SNIFF_SUBRATE :
hci_sniff_subrate_evt ( hdev , skb ) ;
break ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
case HCI_EV_EXTENDED_INQUIRY_RESULT :
hci_extended_inquiry_result_evt ( hdev , skb ) ;
break ;
2005-04-17 02:20:36 +04:00
2008-07-14 22:13:48 +04:00
case HCI_EV_IO_CAPA_REQUEST :
hci_io_capa_request_evt ( hdev , skb ) ;
break ;
case HCI_EV_SIMPLE_PAIR_COMPLETE :
hci_simple_pair_complete_evt ( hdev , skb ) ;
break ;
2008-07-14 22:13:48 +04:00
case HCI_EV_REMOTE_HOST_FEATURES :
hci_remote_host_features_evt ( hdev , skb ) ;
break ;
2007-10-20 15:33:56 +04:00
default :
BT_DBG ( " %s event 0x%x " , hdev - > name , event ) ;
2005-04-17 02:20:36 +04:00
break ;
}
kfree_skb ( skb ) ;
hdev - > stat . evt_rx + + ;
}
/* Generate internal stack event */
void hci_si_event ( struct hci_dev * hdev , int type , int dlen , void * data )
{
struct hci_event_hdr * hdr ;
struct hci_ev_stack_internal * ev ;
struct sk_buff * skb ;
skb = bt_skb_alloc ( HCI_EVENT_HDR_SIZE + sizeof ( * ev ) + dlen , GFP_ATOMIC ) ;
if ( ! skb )
return ;
hdr = ( void * ) skb_put ( skb , HCI_EVENT_HDR_SIZE ) ;
hdr - > evt = HCI_EV_STACK_INTERNAL ;
hdr - > plen = sizeof ( * ev ) + dlen ;
ev = ( void * ) skb_put ( skb , sizeof ( * ev ) + dlen ) ;
ev - > type = type ;
memcpy ( ev - > data , data , dlen ) ;
2005-08-06 14:36:54 +04:00
bt_cb ( skb ) - > incoming = 1 ;
2005-08-15 04:24:31 +04:00
__net_timestamp ( skb ) ;
2005-08-06 14:36:54 +04:00
2005-08-10 07:30:28 +04:00
bt_cb ( skb ) - > pkt_type = HCI_EVENT_PKT ;
2005-04-17 02:20:36 +04:00
skb - > dev = ( void * ) hdev ;
hci_send_to_sock ( hdev , skb ) ;
kfree_skb ( skb ) ;
}