2007-02-09 17:24:33 +03:00
/*
2005-04-17 02:20:36 +04:00
BlueZ - Bluetooth protocol stack for Linux
2010-05-28 19:53:46 +04:00
Copyright ( c ) 2000 - 2001 , 2010 , Code Aurora Forum . All rights reserved .
2005-04-17 02:20:36 +04:00
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>
2010-12-01 17:58:25 +03:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <asm/unaligned.h>
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
/* 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
2010-12-22 00:01:27 +03:00
hci_req_complete ( hdev , HCI_OP_INQUIRY_CANCEL , status ) ;
2007-10-20 15:33:56 +04:00
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 ) ;
2010-12-22 00:01:27 +03:00
hci_req_complete ( hdev , HCI_OP_WRITE_DEF_LINK_POLICY , status ) ;
2008-07-14 22:13:47 +04:00
}
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
2010-12-22 00:01:27 +03:00
hci_req_complete ( hdev , HCI_OP_RESET , status ) ;
2007-10-20 15:33:56 +04:00
}
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
2010-12-22 00:01:27 +03:00
hci_req_complete ( hdev , HCI_OP_WRITE_AUTH_ENABLE , 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
2010-12-22 00:01:27 +03:00
hci_req_complete ( hdev , HCI_OP_WRITE_ENCRYPT_MODE , status ) ;
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_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 ) ;
2010-12-30 01:18:33 +03:00
int old_pscan , old_iscan ;
2005-04-17 02:20:36 +04:00
2010-12-30 01:18:33 +03:00
old_pscan = test_and_clear_bit ( HCI_PSCAN , & hdev - > flags ) ;
old_iscan = test_and_clear_bit ( HCI_ISCAN , & hdev - > flags ) ;
2005-04-17 02:20:36 +04:00
2010-12-29 17:00:25 +03:00
if ( param & SCAN_INQUIRY ) {
2007-10-20 15:33:56 +04:00
set_bit ( HCI_ISCAN , & hdev - > flags ) ;
2010-12-30 01:18:33 +03:00
if ( ! old_iscan )
mgmt_discoverable ( hdev - > id , 1 ) ;
} else if ( old_iscan )
2010-12-29 17:00:25 +03:00
mgmt_discoverable ( hdev - > id , 0 ) ;
2005-04-17 02:20:36 +04:00
2010-12-30 01:18:33 +03:00
if ( param & SCAN_PAGE ) {
2007-10-20 15:33:56 +04:00
set_bit ( HCI_PSCAN , & hdev - > flags ) ;
2010-12-30 01:18:33 +03:00
if ( ! old_pscan )
mgmt_connectable ( hdev - > id , 1 ) ;
} else if ( old_pscan )
mgmt_connectable ( hdev - > id , 0 ) ;
2007-10-20 15:33:56 +04:00
}
2005-04-17 02:20:36 +04:00
2010-12-22 00:01:27 +03:00
hci_req_complete ( hdev , HCI_OP_WRITE_SCAN_ENABLE , status ) ;
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_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
2010-12-22 00:01:27 +03:00
hci_req_complete ( hdev , HCI_OP_HOST_BUFFER_SIZE , status ) ;
2007-10-20 15:33:56 +04:00
}
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 ) ;
}
2011-01-25 02:19:58 +03:00
static u8 hci_get_inquiry_mode ( struct hci_dev * hdev )
{
if ( hdev - > features [ 6 ] & LMP_EXT_INQ )
return 2 ;
if ( hdev - > features [ 3 ] & LMP_RSSI_INQ )
return 1 ;
if ( hdev - > manufacturer = = 11 & & hdev - > hci_rev = = 0x00 & &
hdev - > lmp_subver = = 0x0757 )
return 1 ;
if ( hdev - > manufacturer = = 15 ) {
if ( hdev - > hci_rev = = 0x03 & & hdev - > lmp_subver = = 0x6963 )
return 1 ;
if ( hdev - > hci_rev = = 0x09 & & hdev - > lmp_subver = = 0x6963 )
return 1 ;
if ( hdev - > hci_rev = = 0x00 & & hdev - > lmp_subver = = 0x6965 )
return 1 ;
}
if ( hdev - > manufacturer = = 31 & & hdev - > hci_rev = = 0x2005 & &
hdev - > lmp_subver = = 0x1805 )
return 1 ;
return 0 ;
}
static void hci_setup_inquiry_mode ( struct hci_dev * hdev )
{
u8 mode ;
mode = hci_get_inquiry_mode ( hdev ) ;
hci_send_cmd ( hdev , HCI_OP_WRITE_INQUIRY_MODE , 1 , & mode ) ;
}
static void hci_setup_event_mask ( struct hci_dev * hdev )
{
/* The second byte is 0xff instead of 0x9f (two reserved bits
* disabled ) since a Broadcom 1.2 dongle doesn ' t respond to the
* command otherwise */
u8 events [ 8 ] = { 0xff , 0xff , 0xfb , 0xff , 0x00 , 0x00 , 0x00 , 0x00 } ;
/* Events for 1.2 and newer controllers */
if ( hdev - > lmp_ver > 1 ) {
events [ 4 ] | = 0x01 ; /* Flow Specification Complete */
events [ 4 ] | = 0x02 ; /* Inquiry Result with RSSI */
events [ 4 ] | = 0x04 ; /* Read Remote Extended Features Complete */
events [ 5 ] | = 0x08 ; /* Synchronous Connection Complete */
events [ 5 ] | = 0x10 ; /* Synchronous Connection Changed */
}
if ( hdev - > features [ 3 ] & LMP_RSSI_INQ )
events [ 4 ] | = 0x04 ; /* Inquiry Result with RSSI */
if ( hdev - > features [ 5 ] & LMP_SNIFF_SUBR )
events [ 5 ] | = 0x20 ; /* Sniff Subrating */
if ( hdev - > features [ 5 ] & LMP_PAUSE_ENC )
events [ 5 ] | = 0x80 ; /* Encryption Key Refresh Complete */
if ( hdev - > features [ 6 ] & LMP_EXT_INQ )
events [ 5 ] | = 0x40 ; /* Extended Inquiry Result */
if ( hdev - > features [ 6 ] & LMP_NO_FLUSH )
events [ 7 ] | = 0x01 ; /* Enhanced Flush Complete */
if ( hdev - > features [ 7 ] & LMP_LSTO )
events [ 6 ] | = 0x80 ; /* Link Supervision Timeout Changed */
if ( hdev - > features [ 6 ] & LMP_SIMPLE_PAIR ) {
events [ 6 ] | = 0x01 ; /* IO Capability Request */
events [ 6 ] | = 0x02 ; /* IO Capability Response */
events [ 6 ] | = 0x04 ; /* User Confirmation Request */
events [ 6 ] | = 0x08 ; /* User Passkey Request */
events [ 6 ] | = 0x10 ; /* Remote OOB Data Request */
events [ 6 ] | = 0x20 ; /* Simple Pairing Complete */
events [ 7 ] | = 0x04 ; /* User Passkey Notification */
events [ 7 ] | = 0x08 ; /* Keypress Notification */
events [ 7 ] | = 0x10 ; /* Remote Host Supported
* Features Notification */
}
if ( hdev - > features [ 4 ] & LMP_LE )
events [ 7 ] | = 0x20 ; /* LE Meta-Event */
hci_send_cmd ( hdev , HCI_OP_SET_EVENT_MASK , sizeof ( events ) , events ) ;
}
static void hci_setup ( struct hci_dev * hdev )
{
hci_setup_event_mask ( hdev ) ;
if ( hdev - > lmp_ver > 1 )
hci_send_cmd ( hdev , HCI_OP_READ_LOCAL_COMMANDS , 0 , NULL ) ;
if ( hdev - > features [ 6 ] & LMP_SIMPLE_PAIR ) {
u8 mode = 0x01 ;
hci_send_cmd ( hdev , HCI_OP_WRITE_SSP_MODE , sizeof ( mode ) , & mode ) ;
}
if ( hdev - > features [ 3 ] & LMP_RSSI_INQ )
hci_setup_inquiry_mode ( hdev ) ;
if ( hdev - > features [ 7 ] & LMP_INQ_TX_PWR )
hci_send_cmd ( hdev , HCI_OP_READ_INQ_RSP_TX_POWER , 0 , NULL ) ;
}
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 ) ;
2011-01-25 02:19:58 +03:00
hdev - > lmp_ver = rp - > lmp_ver ;
2008-07-14 22:13:47 +04:00
hdev - > manufacturer = __le16_to_cpu ( rp - > manufacturer ) ;
2011-01-25 02:19:58 +03:00
hdev - > lmp_subver = __le16_to_cpu ( rp - > lmp_subver ) ;
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 ) ;
2011-01-25 02:19:58 +03:00
if ( test_bit ( HCI_INIT , & hdev - > flags ) )
hci_setup ( hdev ) ;
}
static void hci_setup_link_policy ( struct hci_dev * hdev )
{
u16 link_policy = 0 ;
if ( hdev - > features [ 0 ] & LMP_RSWITCH )
link_policy | = HCI_LP_RSWITCH ;
if ( hdev - > features [ 0 ] & LMP_HOLD )
link_policy | = HCI_LP_HOLD ;
if ( hdev - > features [ 0 ] & LMP_SNIFF )
link_policy | = HCI_LP_SNIFF ;
if ( hdev - > features [ 1 ] & LMP_PARK )
link_policy | = HCI_LP_PARK ;
link_policy = cpu_to_le16 ( link_policy ) ;
hci_send_cmd ( hdev , HCI_OP_WRITE_DEF_LINK_POLICY ,
sizeof ( link_policy ) , & link_policy ) ;
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_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 )
2011-01-25 02:19:58 +03:00
goto done ;
2005-04-17 02:20:36 +04:00
2007-10-20 15:33:56 +04:00
memcpy ( hdev - > commands , rp - > commands , sizeof ( hdev - > commands ) ) ;
2011-01-25 02:19:58 +03:00
if ( test_bit ( HCI_INIT , & hdev - > flags ) & & ( hdev - > commands [ 5 ] & 0x10 ) )
hci_setup_link_policy ( hdev ) ;
done :
hci_req_complete ( hdev , HCI_OP_READ_LOCAL_COMMANDS , rp - > status ) ;
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_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
2009-02-06 11:13:37 +03:00
if ( hdev - > features [ 5 ] & LMP_EDR_ESCO_2M )
hdev - > esco_type | = ( ESCO_2EV3 ) ;
if ( hdev - > features [ 5 ] & LMP_EDR_ESCO_3M )
hdev - > esco_type | = ( ESCO_3EV3 ) ;
if ( hdev - > features [ 5 ] & LMP_EDR_3S_ESCO )
hdev - > esco_type | = ( ESCO_2EV5 | ESCO_3EV5 ) ;
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 ) ;
2010-12-22 00:01:27 +03:00
hci_req_complete ( hdev , HCI_OP_READ_BD_ADDR , rp - > status ) ;
}
static void hci_cc_write_ca_timeout ( struct hci_dev * hdev , struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
hci_req_complete ( hdev , HCI_OP_WRITE_CA_TIMEOUT , status ) ;
2007-10-20 15:33:56 +04:00
}
2011-01-10 14:44:55 +03:00
static void hci_cc_delete_stored_link_key ( struct hci_dev * hdev ,
struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
hci_req_complete ( hdev , HCI_OP_DELETE_STORED_LINK_KEY , status ) ;
}
2011-01-25 02:19:58 +03:00
static void hci_cc_set_event_mask ( struct hci_dev * hdev , struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
hci_req_complete ( hdev , HCI_OP_SET_EVENT_MASK , status ) ;
}
static void hci_cc_write_inquiry_mode ( struct hci_dev * hdev ,
struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
hci_req_complete ( hdev , HCI_OP_WRITE_INQUIRY_MODE , status ) ;
}
static void hci_cc_read_inq_rsp_tx_power ( struct hci_dev * hdev ,
struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
hci_req_complete ( hdev , HCI_OP_READ_INQ_RSP_TX_POWER , status ) ;
}
static void hci_cc_set_event_flt ( struct hci_dev * hdev , struct sk_buff * skb )
{
__u8 status = * ( ( __u8 * ) skb - > data ) ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
hci_req_complete ( hdev , HCI_OP_SET_EVENT_FLT , status ) ;
}
2011-01-22 07:10:07 +03:00
static void hci_cc_pin_code_reply ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_rp_pin_code_reply * rp = ( void * ) skb - > data ;
struct hci_cp_pin_code_reply * cp ;
struct hci_conn * conn ;
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
if ( test_bit ( HCI_MGMT , & hdev - > flags ) )
mgmt_pin_code_reply_complete ( hdev - > id , & rp - > bdaddr , rp - > status ) ;
if ( rp - > status ! = 0 )
return ;
cp = hci_sent_cmd_data ( hdev , HCI_OP_PIN_CODE_REPLY ) ;
if ( ! cp )
return ;
conn = hci_conn_hash_lookup_ba ( hdev , ACL_LINK , & cp - > bdaddr ) ;
if ( conn )
conn - > pin_length = cp - > pin_len ;
}
static void hci_cc_pin_code_neg_reply ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_rp_pin_code_neg_reply * rp = ( void * ) skb - > data ;
BT_DBG ( " %s status 0x%x " , hdev - > name , rp - > status ) ;
if ( test_bit ( HCI_MGMT , & hdev - > flags ) )
mgmt_pin_code_neg_reply_complete ( hdev - > id , & rp - > bdaddr ,
rp - > status ) ;
}
2007-10-20 15:33:56 +04:00
static inline void hci_cs_inquiry ( struct hci_dev * hdev , __u8 status )
{
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
if ( status ) {
2010-12-22 00:01:27 +03:00
hci_req_complete ( hdev , HCI_OP_INQUIRY , status ) ;
2007-10-20 15:33:56 +04:00
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
2010-07-18 22:13:37 +04:00
BT_ERR ( " No memory for new connection " ) ;
2005-04-17 02:20:36 +04:00
}
}
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 ) ;
2011-01-11 18:20:20 +03:00
if ( acl ) {
sco = acl - > link ;
if ( sco ) {
sco - > state = BT_CLOSED ;
2005-04-17 02:20:36 +04:00
2011-01-11 18:20:20 +03:00
hci_proto_connect_cfm ( sco , status ) ;
hci_conn_del ( sco ) ;
}
2007-10-20 15:33:56 +04:00
}
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:49 +04:00
static void hci_cs_auth_requested ( struct hci_dev * hdev , __u8 status )
{
struct hci_cp_auth_requested * cp ;
struct hci_conn * conn ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
if ( ! status )
return ;
cp = hci_sent_cmd_data ( hdev , HCI_OP_AUTH_REQUESTED ) ;
if ( ! cp )
return ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( cp - > handle ) ) ;
if ( conn ) {
if ( conn - > state = = BT_CONFIG ) {
hci_proto_connect_cfm ( conn , status ) ;
hci_conn_put ( conn ) ;
}
}
hci_dev_unlock ( hdev ) ;
}
static void hci_cs_set_conn_encrypt ( struct hci_dev * hdev , __u8 status )
{
struct hci_cp_set_conn_encrypt * cp ;
struct hci_conn * conn ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
if ( ! status )
return ;
cp = hci_sent_cmd_data ( hdev , HCI_OP_SET_CONN_ENCRYPT ) ;
if ( ! cp )
return ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( cp - > handle ) ) ;
if ( conn ) {
if ( conn - > state = = BT_CONFIG ) {
hci_proto_connect_cfm ( conn , status ) ;
hci_conn_put ( conn ) ;
}
}
hci_dev_unlock ( hdev ) ;
}
2010-11-18 23:22:29 +03:00
static int hci_outgoing_auth_needed ( struct hci_dev * hdev ,
2010-11-18 23:22:28 +03:00
struct hci_conn * conn )
{
if ( conn - > state ! = BT_CONFIG | | ! conn - > out )
return 0 ;
2011-01-19 09:36:52 +03:00
if ( conn - > pending_sec_level = = BT_SECURITY_SDP )
2010-11-18 23:22:28 +03:00
return 0 ;
/* Only request authentication for SSP connections or non-SSP
* devices with sec_level HIGH */
if ( ! ( hdev - > ssp_mode > 0 & & conn - > ssp_mode > 0 ) & &
2011-01-19 09:36:52 +03:00
conn - > pending_sec_level ! = BT_SECURITY_HIGH )
2010-11-18 23:22:28 +03:00
return 0 ;
return 1 ;
}
2007-10-20 15:33:56 +04:00
static void hci_cs_remote_name_req ( struct hci_dev * hdev , __u8 status )
{
2010-11-18 23:22:29 +03:00
struct hci_cp_remote_name_req * cp ;
struct hci_conn * conn ;
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
2010-11-18 23:22:29 +03:00
/* If successful wait for the name req complete event before
* checking for the need to do authentication */
if ( ! status )
return ;
cp = hci_sent_cmd_data ( hdev , HCI_OP_REMOTE_NAME_REQ ) ;
if ( ! cp )
return ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_ba ( hdev , ACL_LINK , & cp - > bdaddr ) ;
if ( conn & & hci_outgoing_auth_needed ( hdev , conn ) ) {
struct hci_cp_auth_requested cp ;
cp . handle = __cpu_to_le16 ( conn - > handle ) ;
hci_send_cmd ( hdev , HCI_OP_AUTH_REQUESTED , sizeof ( cp ) , & cp ) ;
}
hci_dev_unlock ( hdev ) ;
2007-10-20 15:33:56 +04:00
}
2005-04-17 02:20:36 +04:00
2008-07-14 22:13:49 +04:00
static void hci_cs_read_remote_features ( struct hci_dev * hdev , __u8 status )
{
struct hci_cp_read_remote_features * cp ;
struct hci_conn * conn ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
if ( ! status )
return ;
cp = hci_sent_cmd_data ( hdev , HCI_OP_READ_REMOTE_FEATURES ) ;
if ( ! cp )
return ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( cp - > handle ) ) ;
if ( conn ) {
if ( conn - > state = = BT_CONFIG ) {
hci_proto_connect_cfm ( conn , status ) ;
hci_conn_put ( conn ) ;
}
}
hci_dev_unlock ( hdev ) ;
}
static void hci_cs_read_remote_ext_features ( struct hci_dev * hdev , __u8 status )
{
struct hci_cp_read_remote_ext_features * cp ;
struct hci_conn * conn ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
if ( ! status )
return ;
cp = hci_sent_cmd_data ( hdev , HCI_OP_READ_REMOTE_EXT_FEATURES ) ;
if ( ! cp )
return ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( cp - > handle ) ) ;
if ( conn ) {
if ( conn - > state = = BT_CONFIG ) {
hci_proto_connect_cfm ( conn , status ) ;
hci_conn_put ( conn ) ;
}
}
hci_dev_unlock ( hdev ) ;
}
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 ) ;
2011-01-11 18:20:20 +03:00
if ( acl ) {
sco = acl - > link ;
if ( sco ) {
sco - > state = BT_CLOSED ;
2007-10-20 16:55:10 +04:00
2011-01-11 18:20:20 +03:00
hci_proto_connect_cfm ( sco , status ) ;
hci_conn_del ( sco ) ;
}
2007-10-20 16:55:10 +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_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 ) ) ;
2010-07-26 18:06:00 +04:00
if ( conn ) {
2007-10-20 15:33:56 +04:00
clear_bit ( HCI_CONN_MODE_CHANGE_PEND , & conn - > pend ) ;
2006-07-03 12:02:33 +04:00
2010-07-26 18:06:00 +04:00
if ( test_and_clear_bit ( HCI_CONN_SCO_SETUP_PEND , & conn - > pend ) )
hci_sco_setup ( conn , status ) ;
}
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 ) ) ;
2010-07-26 18:06:00 +04:00
if ( conn ) {
2007-10-20 15:33:56 +04:00
clear_bit ( HCI_CONN_MODE_CHANGE_PEND , & conn - > pend ) ;
2005-04-17 02:20:36 +04:00
2010-07-26 18:06:00 +04:00
if ( test_and_clear_bit ( HCI_CONN_SCO_SETUP_PEND , & conn - > pend ) )
hci_sco_setup ( conn , status ) ;
}
2007-10-20 15:33:56 +04:00
hci_dev_unlock ( hdev ) ;
2005-04-17 02:20:36 +04:00
}
2011-02-11 04:38:47 +03:00
static void hci_cs_le_create_conn ( struct hci_dev * hdev , __u8 status )
{
struct hci_cp_le_create_conn * cp ;
struct hci_conn * conn ;
BT_DBG ( " %s status 0x%x " , hdev - > name , status ) ;
cp = hci_sent_cmd_data ( hdev , HCI_OP_LE_CREATE_CONN ) ;
if ( ! cp )
return ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_ba ( hdev , LE_LINK , & cp - > peer_addr ) ;
BT_DBG ( " %s bdaddr %s conn %p " , hdev - > name , batostr ( & cp - > peer_addr ) ,
conn ) ;
if ( status ) {
if ( conn & & conn - > state = = BT_CONNECT ) {
conn - > state = BT_CLOSED ;
hci_proto_connect_cfm ( conn , status ) ;
hci_conn_del ( conn ) ;
}
} else {
if ( ! conn ) {
conn = hci_conn_add ( hdev , LE_LINK , & cp - > peer_addr ) ;
if ( conn )
conn - > out = 1 ;
else
BT_ERR ( " No memory for new connection " ) ;
}
}
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
2010-12-22 00:01:27 +03:00
hci_req_complete ( hdev , HCI_OP_INQUIRY , 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 ) ;
2009-04-19 21:30:03 +04:00
if ( ! conn ) {
if ( ev - > link_type ! = SCO_LINK )
goto unlock ;
conn = hci_conn_hash_lookup_ba ( hdev , ESCO_LINK , & ev - > bdaddr ) ;
if ( ! conn )
goto unlock ;
conn - > type = SCO_LINK ;
}
2005-04-17 02:20:36 +04:00
if ( ! ev - > status ) {
conn - > handle = __le16_to_cpu ( ev - > handle ) ;
2008-07-14 22:13:49 +04:00
if ( conn - > type = = ACL_LINK ) {
conn - > state = BT_CONFIG ;
hci_conn_hold ( conn ) ;
2009-04-26 22:01:22 +04:00
conn - > disc_timeout = HCI_DISCONN_TIMEOUT ;
2011-01-20 13:34:39 +03:00
mgmt_connected ( hdev - > id , & ev - > bdaddr ) ;
2008-07-14 22:13:49 +04:00
} else
conn - > state = BT_CONNECTED ;
2005-04-17 02:20:36 +04:00
2009-08-23 01:19:26 +04:00
hci_conn_hold_device ( conn ) ;
2008-07-14 22:13:51 +04:00
hci_conn_add_sysfs ( conn ) ;
2005-04-17 02:20:36 +04:00
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 ;
2008-07-14 22:13:49 +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 ) ;
2005-04-17 02:20:36 +04:00
}
2011-01-22 07:09:08 +03:00
} else {
2005-04-17 02:20:36 +04:00
conn - > state = BT_CLOSED ;
2011-01-22 07:09:08 +03:00
if ( conn - > type = = ACL_LINK )
mgmt_connect_failed ( hdev - > id , & ev - > bdaddr , ev - > status ) ;
}
2005-04-17 02:20:36 +04:00
2010-07-26 18:06:00 +04:00
if ( conn - > type = = ACL_LINK )
hci_sco_setup ( conn , ev - > status ) ;
2005-04-17 02:20:36 +04:00
2008-07-14 22:13:49 +04:00
if ( ev - > status ) {
hci_proto_connect_cfm ( conn , ev - > status ) ;
2005-04-17 02:20:36 +04:00
hci_conn_del ( conn ) ;
2009-01-15 23:57:03 +03:00
} else if ( ev - > link_type ! = ACL_LINK )
hci_proto_connect_cfm ( conn , ev - > status ) ;
2005-04-17 02:20:36 +04:00
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
2010-05-18 15:20:32 +04:00
if ( ( mask & HCI_LM_ACCEPT ) & & ! hci_blacklist_lookup ( hdev , & ev - > bdaddr ) ) {
2007-10-20 15:33:56 +04:00
/* 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
2010-11-22 14:21:37 +03:00
ie = hci_inquiry_cache_lookup ( hdev , & ev - > bdaddr ) ;
if ( ie )
2008-07-14 22:13:47 +04:00
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 ) {
2010-11-22 14:21:37 +03:00
conn = hci_conn_add ( hdev , ev - > link_type , & ev - > bdaddr ) ;
if ( ! conn ) {
2010-07-18 22:13:37 +04:00
BT_ERR ( " No memory for new connection " ) ;
2007-10-20 15:33:56 +04:00
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 ) ;
2011-01-20 13:40:27 +03:00
if ( ev - > status ) {
mgmt_disconnect_failed ( hdev - > id ) ;
2007-10-20 15:33:56 +04:00
return ;
2011-01-20 13:40:27 +03:00
}
2007-10-20 15:33:56 +04:00
2006-07-03 12:02:33 +04:00
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( ev - > handle ) ) ;
2011-01-20 13:34:39 +03:00
if ( ! conn )
goto unlock ;
2008-07-14 22:13:51 +04:00
2011-01-20 13:34:39 +03:00
conn - > state = BT_CLOSED ;
2006-07-03 12:02:33 +04:00
2011-01-20 13:34:39 +03:00
if ( conn - > type = = ACL_LINK )
mgmt_disconnected ( hdev - > id , & conn - > dst ) ;
hci_proto_disconn_cfm ( conn , ev - > reason ) ;
hci_conn_del ( conn ) ;
unlock :
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 ) {
2011-01-19 09:36:52 +03:00
if ( ! ev - > status ) {
2005-04-17 02:20:36 +04:00
conn - > link_mode | = HCI_LM_AUTH ;
2011-01-19 09:36:52 +03:00
conn - > sec_level = conn - > pending_sec_level ;
} else
2010-06-18 12:08:56 +04:00
conn - > sec_level = BT_SECURITY_LOW ;
2005-04-17 02:20:36 +04:00
clear_bit ( HCI_CONN_AUTH_PEND , & conn - > pend ) ;
2008-07-14 22:13:49 +04:00
if ( conn - > state = = BT_CONFIG ) {
if ( ! ev - > status & & hdev - > ssp_mode > 0 & &
conn - > ssp_mode > 0 ) {
struct hci_cp_set_conn_encrypt cp ;
cp . handle = ev - > handle ;
cp . encrypt = 0x01 ;
hci_send_cmd ( hdev , HCI_OP_SET_CONN_ENCRYPT ,
sizeof ( cp ) , & cp ) ;
} else {
conn - > state = BT_CONNECTED ;
hci_proto_connect_cfm ( conn , ev - > status ) ;
hci_conn_put ( conn ) ;
}
2009-04-26 22:01:22 +04:00
} else {
2008-07-14 22:13:49 +04:00
hci_auth_cfm ( conn , ev - > status ) ;
2005-04-17 02:20:36 +04:00
2009-04-26 22:01:22 +04:00
hci_conn_hold ( conn ) ;
conn - > disc_timeout = HCI_DISCONN_TIMEOUT ;
hci_conn_put ( conn ) ;
}
2005-04-17 02:20:36 +04:00
if ( test_bit ( HCI_CONN_ENCRYPT_PEND , & conn - > pend ) ) {
if ( ! ev - > status ) {
struct hci_cp_set_conn_encrypt cp ;
2008-07-14 22:13:49 +04:00
cp . handle = ev - > handle ;
cp . encrypt = 0x01 ;
hci_send_cmd ( 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
{
2010-11-18 23:22:29 +03:00
struct hci_ev_remote_name * ev = ( void * ) skb - > data ;
struct hci_conn * conn ;
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 ) ;
2010-11-18 23:22:29 +03:00
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_ba ( hdev , ACL_LINK , & ev - > bdaddr ) ;
if ( conn & & hci_outgoing_auth_needed ( hdev , conn ) ) {
struct hci_cp_auth_requested cp ;
cp . handle = __cpu_to_le16 ( conn - > handle ) ;
hci_send_cmd ( hdev , HCI_OP_AUTH_REQUESTED , sizeof ( cp ) , & cp ) ;
}
hci_dev_unlock ( hdev ) ;
2007-10-20 15:33:56 +04:00
}
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 ) ;
2008-07-14 22:13:49 +04:00
if ( conn - > state = = BT_CONFIG ) {
if ( ! ev - > status )
conn - > state = BT_CONNECTED ;
hci_proto_connect_cfm ( conn , ev - > status ) ;
hci_conn_put ( conn ) ;
} else
hci_encrypt_cfm ( conn , ev - > status , ev - > encrypt ) ;
2005-04-17 02:20:36 +04:00
}
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 ) ;
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( ev - > handle ) ) ;
2010-11-10 18:11:51 +03:00
if ( ! conn )
goto unlock ;
2008-07-14 22:13:49 +04:00
2010-11-10 18:11:51 +03:00
if ( ! ev - > status )
memcpy ( conn - > features , ev - > features , 8 ) ;
if ( conn - > state ! = BT_CONFIG )
goto unlock ;
if ( ! ev - > status & & lmp_ssp_capable ( hdev ) & & lmp_ssp_capable ( conn ) ) {
struct hci_cp_read_remote_ext_features cp ;
cp . handle = ev - > handle ;
cp . page = 0x01 ;
hci_send_cmd ( hdev , HCI_OP_READ_REMOTE_EXT_FEATURES ,
2010-10-15 11:46:09 +04:00
sizeof ( cp ) , & cp ) ;
2010-11-18 23:22:28 +03:00
goto unlock ;
}
2010-11-18 23:22:29 +03:00
if ( ! ev - > status ) {
struct hci_cp_remote_name_req cp ;
memset ( & cp , 0 , sizeof ( cp ) ) ;
bacpy ( & cp . bdaddr , & conn - > dst ) ;
cp . pscan_rep_mode = 0x02 ;
hci_send_cmd ( hdev , HCI_OP_REMOTE_NAME_REQ , sizeof ( cp ) , & cp ) ;
}
2010-11-18 23:22:28 +03:00
2010-11-18 23:22:29 +03:00
if ( ! hci_outgoing_auth_needed ( hdev , conn ) ) {
2010-11-10 18:11:51 +03:00
conn - > state = BT_CONNECTED ;
hci_proto_connect_cfm ( conn , ev - > status ) ;
hci_conn_put ( conn ) ;
2008-07-14 22:13:49 +04:00
}
2007-10-20 15:33:56 +04:00
2010-11-10 18:11:51 +03:00
unlock :
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 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 ;
2010-12-22 00:01:27 +03:00
case HCI_OP_WRITE_CA_TIMEOUT :
hci_cc_write_ca_timeout ( hdev , skb ) ;
break ;
2011-01-10 14:44:55 +03:00
case HCI_OP_DELETE_STORED_LINK_KEY :
hci_cc_delete_stored_link_key ( hdev , skb ) ;
break ;
2011-01-25 02:19:58 +03:00
case HCI_OP_SET_EVENT_MASK :
hci_cc_set_event_mask ( hdev , skb ) ;
break ;
case HCI_OP_WRITE_INQUIRY_MODE :
hci_cc_write_inquiry_mode ( hdev , skb ) ;
break ;
case HCI_OP_READ_INQ_RSP_TX_POWER :
hci_cc_read_inq_rsp_tx_power ( hdev , skb ) ;
break ;
case HCI_OP_SET_EVENT_FLT :
hci_cc_set_event_flt ( hdev , skb ) ;
break ;
2011-01-22 07:10:07 +03:00
case HCI_OP_PIN_CODE_REPLY :
hci_cc_pin_code_reply ( hdev , skb ) ;
break ;
case HCI_OP_PIN_CODE_NEG_REPLY :
hci_cc_pin_code_neg_reply ( hdev , skb ) ;
break ;
2007-10-20 15:33:56 +04:00
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 ) )
2009-11-18 03:02:54 +03:00
tasklet_schedule ( & hdev - > cmd_task ) ;
2007-10-20 15:33:56 +04:00
}
}
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 ;
2008-07-14 22:13:49 +04:00
case HCI_OP_AUTH_REQUESTED :
hci_cs_auth_requested ( hdev , ev - > status ) ;
break ;
case HCI_OP_SET_CONN_ENCRYPT :
hci_cs_set_conn_encrypt ( hdev , ev - > status ) ;
break ;
2007-10-20 15:33:56 +04:00
case HCI_OP_REMOTE_NAME_REQ :
hci_cs_remote_name_req ( hdev , ev - > status ) ;
break ;
2008-07-14 22:13:49 +04:00
case HCI_OP_READ_REMOTE_FEATURES :
hci_cs_read_remote_features ( hdev , ev - > status ) ;
break ;
case HCI_OP_READ_REMOTE_EXT_FEATURES :
hci_cs_read_remote_ext_features ( hdev , ev - > status ) ;
break ;
2007-10-20 15:33:56 +04:00
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 ;
2011-01-20 13:40:27 +03:00
case HCI_OP_DISCONNECT :
if ( ev - > status ! = 0 )
mgmt_disconnect_failed ( hdev - > id ) ;
break ;
2011-02-11 04:38:47 +03:00
case HCI_OP_LE_CREATE_CONN :
hci_cs_le_create_conn ( hdev , ev - > status ) ;
break ;
2007-10-20 15:33:56 +04:00
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 ) )
2009-11-18 03:02:54 +03:00
tasklet_schedule ( & hdev - > cmd_task ) ;
2007-10-20 15:33:56 +04:00
}
}
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 ) {
2010-12-01 17:58:25 +03:00
hdev - > acl_cnt + = count ;
if ( hdev - > acl_cnt > hdev - > acl_pkts )
2007-10-20 15:33:56 +04:00
hdev - > acl_cnt = hdev - > acl_pkts ;
} else {
2010-12-01 17:58:25 +03:00
hdev - > sco_cnt + = count ;
if ( hdev - > sco_cnt > hdev - > sco_pkts )
2007-10-20 15:33:56 +04:00
hdev - > sco_cnt = hdev - > sco_pkts ;
}
}
}
2009-11-18 03:02:54 +03:00
tasklet_schedule ( & hdev - > tx_task ) ;
2007-10-20 15:33:56 +04:00
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 ;
}
2010-07-26 18:06:00 +04:00
if ( test_and_clear_bit ( HCI_CONN_SCO_SETUP_PEND , & conn - > pend ) )
hci_sco_setup ( conn , ev - > status ) ;
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 )
{
2009-04-26 22:01:22 +04:00
struct hci_ev_pin_code_req * ev = ( void * ) skb - > data ;
struct hci_conn * conn ;
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s " , hdev - > name ) ;
2009-04-26 22:01:22 +04:00
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_ba ( hdev , ACL_LINK , & ev - > bdaddr ) ;
2009-05-09 23:09:21 +04:00
if ( conn & & conn - > state = = BT_CONNECTED ) {
2009-04-26 22:01:22 +04:00
hci_conn_hold ( conn ) ;
conn - > disc_timeout = HCI_PAIRING_TIMEOUT ;
hci_conn_put ( conn ) ;
}
2011-01-04 16:40:05 +03:00
if ( ! test_bit ( HCI_PAIRABLE , & hdev - > flags ) )
hci_send_cmd ( hdev , HCI_OP_PIN_CODE_NEG_REPLY ,
sizeof ( ev - > bdaddr ) , & ev - > bdaddr ) ;
2011-01-22 07:10:07 +03:00
if ( test_bit ( HCI_MGMT , & hdev - > flags ) )
mgmt_pin_code_request ( hdev - > id , & ev - > bdaddr ) ;
2009-04-26 22:01:22 +04:00
hci_dev_unlock ( hdev ) ;
2007-10-20 15:33:56 +04:00
}
static inline void hci_link_key_request_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
2011-01-17 15:41:05 +03:00
struct hci_ev_link_key_req * ev = ( void * ) skb - > data ;
struct hci_cp_link_key_reply cp ;
struct hci_conn * conn ;
struct link_key * key ;
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s " , hdev - > name ) ;
2011-01-17 15:41:05 +03:00
if ( ! test_bit ( HCI_LINK_KEYS , & hdev - > flags ) )
return ;
hci_dev_lock ( hdev ) ;
key = hci_find_link_key ( hdev , & ev - > bdaddr ) ;
if ( ! key ) {
BT_DBG ( " %s link key not found for %s " , hdev - > name ,
batostr ( & ev - > bdaddr ) ) ;
goto not_found ;
}
BT_DBG ( " %s found key type %u for %s " , hdev - > name , key - > type ,
batostr ( & ev - > bdaddr ) ) ;
if ( ! test_bit ( HCI_DEBUG_KEYS , & hdev - > flags ) & & key - > type = = 0x03 ) {
BT_DBG ( " %s ignoring debug key " , hdev - > name ) ;
goto not_found ;
}
conn = hci_conn_hash_lookup_ba ( hdev , ACL_LINK , & ev - > bdaddr ) ;
if ( key - > type = = 0x04 & & conn & & conn - > auth_type ! = 0xff & &
( conn - > auth_type & 0x01 ) ) {
BT_DBG ( " %s ignoring unauthenticated key " , hdev - > name ) ;
goto not_found ;
}
bacpy ( & cp . bdaddr , & ev - > bdaddr ) ;
memcpy ( cp . link_key , key - > val , 16 ) ;
hci_send_cmd ( hdev , HCI_OP_LINK_KEY_REPLY , sizeof ( cp ) , & cp ) ;
hci_dev_unlock ( hdev ) ;
return ;
not_found :
hci_send_cmd ( hdev , HCI_OP_LINK_KEY_NEG_REPLY , 6 , & ev - > bdaddr ) ;
hci_dev_unlock ( hdev ) ;
2007-10-20 15:33:56 +04:00
}
static inline void hci_link_key_notify_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
2009-04-26 22:01:22 +04:00
struct hci_ev_link_key_notify * ev = ( void * ) skb - > data ;
struct hci_conn * conn ;
2011-01-17 15:41:05 +03:00
u8 pin_len = 0 ;
2009-04-26 22:01:22 +04:00
2007-10-20 15:33:56 +04:00
BT_DBG ( " %s " , hdev - > name ) ;
2009-04-26 22:01:22 +04:00
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_ba ( hdev , ACL_LINK , & ev - > bdaddr ) ;
if ( conn ) {
hci_conn_hold ( conn ) ;
conn - > disc_timeout = HCI_DISCONN_TIMEOUT ;
2011-01-22 07:10:07 +03:00
pin_len = conn - > pin_length ;
2009-04-26 22:01:22 +04:00
hci_conn_put ( conn ) ;
}
2011-01-17 15:41:05 +03:00
if ( test_bit ( HCI_LINK_KEYS , & hdev - > flags ) )
hci_add_link_key ( hdev , 1 , & ev - > bdaddr , ev - > link_key ,
ev - > key_type , pin_len ) ;
2009-04-26 22:01:22 +04:00
hci_dev_unlock ( hdev ) ;
2007-10-20 15:33:56 +04:00
}
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 ;
2010-11-22 14:21:37 +03:00
ie = hci_inquiry_cache_lookup ( hdev , & conn - > dst ) ;
if ( ie ) {
2005-04-17 02:20:36 +04:00
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 ) ;
2010-11-22 14:21:37 +03:00
ie = hci_inquiry_cache_lookup ( hdev , & ev - > bdaddr ) ;
if ( ie ) {
2005-08-10 07:28:02 +04:00
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
hci_dev_lock ( hdev ) ;
conn = hci_conn_hash_lookup_handle ( hdev , __le16_to_cpu ( ev - > handle ) ) ;
2010-11-10 18:11:51 +03:00
if ( ! conn )
goto unlock ;
2008-07-14 22:13:48 +04:00
2010-11-10 18:11:51 +03:00
if ( ! ev - > status & & ev - > page = = 0x01 ) {
struct inquiry_entry * ie ;
2008-07-14 22:13:48 +04:00
2010-11-22 14:21:37 +03:00
ie = hci_inquiry_cache_lookup ( hdev , & conn - > dst ) ;
if ( ie )
2010-11-10 18:11:51 +03:00
ie - > data . ssp_mode = ( ev - > features [ 0 ] & 0x01 ) ;
2008-07-14 22:13:49 +04:00
2010-11-10 18:11:51 +03:00
conn - > ssp_mode = ( ev - > features [ 0 ] & 0x01 ) ;
}
if ( conn - > state ! = BT_CONFIG )
goto unlock ;
2010-11-18 23:22:29 +03:00
if ( ! ev - > status ) {
struct hci_cp_remote_name_req cp ;
memset ( & cp , 0 , sizeof ( cp ) ) ;
bacpy ( & cp . bdaddr , & conn - > dst ) ;
cp . pscan_rep_mode = 0x02 ;
hci_send_cmd ( hdev , HCI_OP_REMOTE_NAME_REQ , sizeof ( cp ) , & cp ) ;
}
2010-11-18 23:22:28 +03:00
2010-11-18 23:22:29 +03:00
if ( ! hci_outgoing_auth_needed ( hdev , conn ) ) {
2010-11-10 18:11:51 +03:00
conn - > state = BT_CONNECTED ;
hci_proto_connect_cfm ( conn , ev - > status ) ;
hci_conn_put ( conn ) ;
2008-07-14 22:13:48 +04:00
}
2010-11-10 18:11:51 +03:00
unlock :
2008-07-14 22:13:48 +04:00
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
2009-04-19 21:14:14 +04:00
switch ( ev - > status ) {
case 0x00 :
2007-10-20 16:55:10 +04:00
conn - > handle = __le16_to_cpu ( ev - > handle ) ;
conn - > state = BT_CONNECTED ;
2008-07-14 22:13:51 +04:00
2009-08-23 01:19:26 +04:00
hci_conn_hold_device ( conn ) ;
2008-07-14 22:13:51 +04:00
hci_conn_add_sysfs ( conn ) ;
2009-04-19 21:14:14 +04:00
break ;
2010-02-16 19:29:44 +03:00
case 0x11 : /* Unsupported Feature or Parameter Value */
2009-04-19 21:14:14 +04:00
case 0x1c : /* SCO interval rejected */
2010-02-03 22:42:26 +03:00
case 0x1a : /* Unsupported Remote Feature */
2009-04-19 21:14:14 +04:00
case 0x1f : /* Unspecified error */
if ( conn - > out & & conn - > attempt < 2 ) {
conn - > pkt_type = ( hdev - > esco_type & SCO_ESCO_MASK ) |
( hdev - > esco_type & EDR_ESCO_MASK ) ;
hci_setup_sync ( conn , conn - > link - > handle ) ;
goto unlock ;
}
/* fall through */
default :
2007-10-20 16:55:10 +04:00
conn - > state = BT_CLOSED ;
2009-04-19 21:14:14 +04:00
break ;
}
2007-10-20 16:55:10 +04:00
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
2011-01-25 14:28:33 +03:00
static inline u8 hci_get_auth_req ( struct hci_conn * conn )
{
/* If remote requests dedicated bonding follow that lead */
if ( conn - > remote_auth = = 0x02 | | conn - > remote_auth = = 0x03 ) {
/* If both remote and local IO capabilities allow MITM
* protection then require it , otherwise don ' t */
if ( conn - > remote_cap = = 0x03 | | conn - > io_capability = = 0x03 )
return 0x02 ;
else
return 0x03 ;
}
/* If remote requests no-bonding follow that lead */
if ( conn - > remote_auth = = 0x00 | | conn - > remote_auth = = 0x01 )
return 0x00 ;
return conn - > auth_type ;
}
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 ) ;
2011-01-04 16:40:05 +03:00
if ( ! conn )
goto unlock ;
hci_conn_hold ( conn ) ;
if ( ! test_bit ( HCI_MGMT , & hdev - > flags ) )
goto unlock ;
if ( test_bit ( HCI_PAIRABLE , & hdev - > flags ) | |
( conn - > remote_auth & ~ 0x01 ) = = HCI_AT_NO_BONDING ) {
2011-01-25 14:28:33 +03:00
struct hci_cp_io_capability_reply cp ;
bacpy ( & cp . bdaddr , & ev - > bdaddr ) ;
cp . capability = conn - > io_capability ;
cp . oob_data = 0 ;
cp . authentication = hci_get_auth_req ( conn ) ;
hci_send_cmd ( hdev , HCI_OP_IO_CAPABILITY_REPLY ,
sizeof ( cp ) , & cp ) ;
2011-01-04 16:40:05 +03:00
} else {
struct hci_cp_io_capability_neg_reply cp ;
bacpy ( & cp . bdaddr , & ev - > bdaddr ) ;
cp . reason = 0x16 ; /* Pairing not allowed */
2008-07-14 22:13:48 +04:00
2011-01-04 16:40:05 +03:00
hci_send_cmd ( hdev , HCI_OP_IO_CAPABILITY_NEG_REPLY ,
sizeof ( cp ) , & cp ) ;
}
unlock :
hci_dev_unlock ( hdev ) ;
}
static inline void hci_io_capa_reply_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_ev_io_capa_reply * 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 )
goto unlock ;
hci_conn_hold ( conn ) ;
conn - > remote_cap = ev - > capability ;
conn - > remote_oob = ev - > oob_data ;
conn - > remote_auth = ev - > authentication ;
unlock :
2008-07-14 22:13:48 +04:00
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 ) ;
2010-11-22 14:21:37 +03:00
ie = hci_inquiry_cache_lookup ( hdev , & ev - > bdaddr ) ;
if ( ie )
2008-07-14 22:13:48 +04:00
ie - > data . ssp_mode = ( ev - > features [ 0 ] & 0x01 ) ;
hci_dev_unlock ( hdev ) ;
}
2011-02-11 04:38:47 +03:00
static inline void hci_le_conn_complete_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_ev_le_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 , LE_LINK , & ev - > bdaddr ) ;
if ( ! conn )
goto unlock ;
if ( ev - > status ) {
hci_proto_connect_cfm ( conn , ev - > status ) ;
conn - > state = BT_CLOSED ;
hci_conn_del ( conn ) ;
goto unlock ;
}
conn - > handle = __le16_to_cpu ( ev - > handle ) ;
conn - > state = BT_CONNECTED ;
hci_conn_hold_device ( conn ) ;
hci_conn_add_sysfs ( conn ) ;
hci_proto_connect_cfm ( conn , ev - > status ) ;
unlock :
hci_dev_unlock ( hdev ) ;
}
static inline void hci_le_meta_evt ( struct hci_dev * hdev , struct sk_buff * skb )
{
struct hci_ev_le_meta * le_ev = ( void * ) skb - > data ;
skb_pull ( skb , sizeof ( * le_ev ) ) ;
switch ( le_ev - > subevent ) {
case HCI_EV_LE_CONN_COMPLETE :
hci_le_conn_complete_evt ( hdev , skb ) ;
break ;
default :
break ;
}
}
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 ;
2011-01-04 16:40:05 +03:00
case HCI_EV_IO_CAPA_REPLY :
hci_io_capa_reply_evt ( hdev , skb ) ;
break ;
2008-07-14 22:13:48 +04:00
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 ;
2011-02-11 04:38:47 +03:00
case HCI_EV_LE_META :
hci_le_meta_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 ;
2010-12-16 11:17:38 +03:00
hci_send_to_sock ( hdev , skb , NULL ) ;
2005-04-17 02:20:36 +04:00
kfree_skb ( skb ) ;
}