2014-12-20 18:05:13 +03:00
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright ( C ) 2014 Intel Corporation
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
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
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
ALL LIABILITY , INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS ,
COPYRIGHTS , TRADEMARKS OR OTHER RIGHTS , RELATING TO USE OF THIS
SOFTWARE IS DISCLAIMED .
*/
# include <linux/debugfs.h>
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
2020-01-25 11:19:51 +03:00
# include "smp.h"
2021-09-21 21:25:04 +03:00
# include "hci_request.h"
2014-12-20 18:05:13 +03:00
# include "hci_debugfs.h"
2015-03-20 21:14:50 +03:00
# define DEFINE_QUIRK_ATTRIBUTE(__name, __quirk) \
static ssize_t __name # # _read ( struct file * file , \
char __user * user_buf , \
size_t count , loff_t * ppos ) \
{ \
struct hci_dev * hdev = file - > private_data ; \
char buf [ 3 ] ; \
\
buf [ 0 ] = test_bit ( __quirk , & hdev - > quirks ) ? ' Y ' : ' N ' ; \
buf [ 1 ] = ' \n ' ; \
buf [ 2 ] = ' \0 ' ; \
return simple_read_from_buffer ( user_buf , count , ppos , buf , 2 ) ; \
} \
\
static ssize_t __name # # _write ( struct file * file , \
const char __user * user_buf , \
size_t count , loff_t * ppos ) \
{ \
struct hci_dev * hdev = file - > private_data ; \
bool enable ; \
2018-05-29 16:33:48 +03:00
int err ; \
2015-03-20 21:14:50 +03:00
\
if ( test_bit ( HCI_UP , & hdev - > flags ) ) \
return - EBUSY ; \
\
2018-05-29 16:33:48 +03:00
err = kstrtobool_from_user ( user_buf , count , & enable ) ; \
if ( err ) \
return err ; \
2015-03-20 21:14:50 +03:00
\
if ( enable = = test_bit ( __quirk , & hdev - > quirks ) ) \
return - EALREADY ; \
\
change_bit ( __quirk , & hdev - > quirks ) ; \
\
return count ; \
} \
\
static const struct file_operations __name # # _fops = { \
. open = simple_open , \
. read = __name # # _read , \
. write = __name # # _write , \
. llseek = default_llseek , \
} \
2016-07-17 20:55:16 +03:00
# define DEFINE_INFO_ATTRIBUTE(__name, __field) \
static int __name # # _show ( struct seq_file * f , void * ptr ) \
{ \
struct hci_dev * hdev = f - > private ; \
\
hci_dev_lock ( hdev ) ; \
seq_printf ( f , " %s \n " , hdev - > __field ? : " " ) ; \
hci_dev_unlock ( hdev ) ; \
\
return 0 ; \
} \
\
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( __name )
2014-12-20 18:05:14 +03:00
static int features_show ( struct seq_file * f , void * ptr )
{
struct hci_dev * hdev = f - > private ;
u8 p ;
hci_dev_lock ( hdev ) ;
2017-12-11 13:10:33 +03:00
for ( p = 0 ; p < HCI_MAX_PAGES & & p < = hdev - > max_page ; p + + )
seq_printf ( f , " %2u: %8ph \n " , p , hdev - > features [ p ] ) ;
2014-12-20 18:05:14 +03:00
if ( lmp_le_capable ( hdev ) )
2017-12-11 13:10:33 +03:00
seq_printf ( f , " LE: %8ph \n " , hdev - > le_features ) ;
2014-12-20 18:05:14 +03:00
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( features ) ;
2014-12-20 18:05:14 +03:00
2015-04-01 23:21:37 +03:00
static int device_id_show ( struct seq_file * f , void * ptr )
{
struct hci_dev * hdev = f - > private ;
hci_dev_lock ( hdev ) ;
seq_printf ( f , " %4.4x:%4.4x:%4.4x:%4.4x \n " , hdev - > devid_source ,
hdev - > devid_vendor , hdev - > devid_product , hdev - > devid_version ) ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( device_id ) ;
2015-04-01 23:21:37 +03:00
2014-12-20 18:05:14 +03:00
static int device_list_show ( struct seq_file * f , void * ptr )
{
struct hci_dev * hdev = f - > private ;
struct hci_conn_params * p ;
struct bdaddr_list * b ;
hci_dev_lock ( hdev ) ;
2021-06-04 11:26:27 +03:00
list_for_each_entry ( b , & hdev - > accept_list , list )
2014-12-20 18:05:14 +03:00
seq_printf ( f , " %pMR (type %u) \n " , & b - > bdaddr , b - > bdaddr_type ) ;
list_for_each_entry ( p , & hdev - > le_conn_params , list ) {
seq_printf ( f , " %pMR (type %u) %u \n " , & p - > addr , p - > addr_type ,
p - > auto_connect ) ;
}
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( device_list ) ;
2014-12-20 18:05:14 +03:00
static int blacklist_show ( struct seq_file * f , void * p )
{
struct hci_dev * hdev = f - > private ;
struct bdaddr_list * b ;
hci_dev_lock ( hdev ) ;
2021-06-04 11:26:27 +03:00
list_for_each_entry ( b , & hdev - > reject_list , list )
2014-12-20 18:05:14 +03:00
seq_printf ( f , " %pMR (type %u) \n " , & b - > bdaddr , b - > bdaddr_type ) ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( blacklist ) ;
2014-12-20 18:05:14 +03:00
2020-01-07 03:43:17 +03:00
static int blocked_keys_show ( struct seq_file * f , void * p )
{
struct hci_dev * hdev = f - > private ;
struct blocked_key * key ;
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( key , & hdev - > blocked_keys , list )
seq_printf ( f , " %u %*phN \n " , key - > type , 16 , key - > val ) ;
rcu_read_unlock ( ) ;
return 0 ;
}
DEFINE_SHOW_ATTRIBUTE ( blocked_keys ) ;
2014-12-20 18:05:14 +03:00
static int uuids_show ( struct seq_file * f , void * p )
{
struct hci_dev * hdev = f - > private ;
struct bt_uuid * uuid ;
hci_dev_lock ( hdev ) ;
list_for_each_entry ( uuid , & hdev - > uuids , list ) {
u8 i , val [ 16 ] ;
/* The Bluetooth UUID values are stored in big endian,
* but with reversed byte order . So convert them into
* the right order for the % pUb modifier .
*/
for ( i = 0 ; i < 16 ; i + + )
val [ i ] = uuid - > uuid [ 15 - i ] ;
seq_printf ( f , " %pUb \n " , val ) ;
}
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( uuids ) ;
2014-12-20 18:05:14 +03:00
2015-02-01 08:01:07 +03:00
static int remote_oob_show ( struct seq_file * f , void * ptr )
{
struct hci_dev * hdev = f - > private ;
struct oob_data * data ;
hci_dev_lock ( hdev ) ;
list_for_each_entry ( data , & hdev - > remote_oob_data , list ) {
seq_printf ( f , " %pMR (type %u) %u %*phN %*phN %*phN %*phN \n " ,
& data - > bdaddr , data - > bdaddr_type , data - > present ,
16 , data - > hash192 , 16 , data - > rand192 ,
2015-03-16 22:34:58 +03:00
16 , data - > hash256 , 16 , data - > rand256 ) ;
2015-02-01 08:01:07 +03:00
}
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( remote_oob ) ;
2015-02-01 08:01:07 +03:00
2014-12-20 18:05:14 +03:00
static int conn_info_min_age_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val = = 0 | | val > hdev - > conn_info_max_age )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > conn_info_min_age = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int conn_info_min_age_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > conn_info_min_age ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( conn_info_min_age_fops , conn_info_min_age_get ,
conn_info_min_age_set , " %llu \n " ) ;
2014-12-20 18:05:14 +03:00
static int conn_info_max_age_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val = = 0 | | val < hdev - > conn_info_min_age )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > conn_info_max_age = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int conn_info_max_age_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > conn_info_max_age ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( conn_info_max_age_fops , conn_info_max_age_get ,
conn_info_max_age_set , " %llu \n " ) ;
2014-12-20 18:05:14 +03:00
2015-02-01 02:12:06 +03:00
static ssize_t use_debug_keys_read ( struct file * file , char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct hci_dev * hdev = file - > private_data ;
char buf [ 3 ] ;
2021-04-01 09:50:39 +03:00
buf [ 0 ] = hci_dev_test_flag ( hdev , HCI_USE_DEBUG_KEYS ) ? ' Y ' : ' N ' ;
2015-02-01 02:12:06 +03:00
buf [ 1 ] = ' \n ' ;
buf [ 2 ] = ' \0 ' ;
return simple_read_from_buffer ( user_buf , count , ppos , buf , 2 ) ;
}
static const struct file_operations use_debug_keys_fops = {
. open = simple_open ,
. read = use_debug_keys_read ,
. llseek = default_llseek ,
} ;
2015-01-01 01:43:19 +03:00
static ssize_t sc_only_mode_read ( struct file * file , char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct hci_dev * hdev = file - > private_data ;
char buf [ 3 ] ;
2021-04-01 09:50:39 +03:00
buf [ 0 ] = hci_dev_test_flag ( hdev , HCI_SC_ONLY ) ? ' Y ' : ' N ' ;
2015-01-01 01:43:19 +03:00
buf [ 1 ] = ' \n ' ;
buf [ 2 ] = ' \0 ' ;
return simple_read_from_buffer ( user_buf , count , ppos , buf , 2 ) ;
}
static const struct file_operations sc_only_mode_fops = {
. open = simple_open ,
. read = sc_only_mode_read ,
. llseek = default_llseek ,
} ;
2016-07-17 20:55:16 +03:00
DEFINE_INFO_ATTRIBUTE ( hardware_info , hw_info ) ;
DEFINE_INFO_ATTRIBUTE ( firmware_info , fw_info ) ;
2014-12-20 18:05:13 +03:00
void hci_debugfs_create_common ( struct hci_dev * hdev )
{
2014-12-20 18:05:14 +03:00
debugfs_create_file ( " features " , 0444 , hdev - > debugfs , hdev ,
& features_fops ) ;
debugfs_create_u16 ( " manufacturer " , 0444 , hdev - > debugfs ,
& hdev - > manufacturer ) ;
debugfs_create_u8 ( " hci_version " , 0444 , hdev - > debugfs , & hdev - > hci_ver ) ;
debugfs_create_u16 ( " hci_revision " , 0444 , hdev - > debugfs , & hdev - > hci_rev ) ;
2015-02-01 06:54:39 +03:00
debugfs_create_u8 ( " hardware_error " , 0444 , hdev - > debugfs ,
& hdev - > hw_error_code ) ;
2015-04-01 23:21:37 +03:00
debugfs_create_file ( " device_id " , 0444 , hdev - > debugfs , hdev ,
& device_id_fops ) ;
2015-02-01 06:54:39 +03:00
2014-12-20 18:05:14 +03:00
debugfs_create_file ( " device_list " , 0444 , hdev - > debugfs , hdev ,
& device_list_fops ) ;
debugfs_create_file ( " blacklist " , 0444 , hdev - > debugfs , hdev ,
& blacklist_fops ) ;
2020-01-07 03:43:17 +03:00
debugfs_create_file ( " blocked_keys " , 0444 , hdev - > debugfs , hdev ,
& blocked_keys_fops ) ;
2014-12-20 18:05:14 +03:00
debugfs_create_file ( " uuids " , 0444 , hdev - > debugfs , hdev , & uuids_fops ) ;
2015-02-01 08:01:07 +03:00
debugfs_create_file ( " remote_oob " , 0400 , hdev - > debugfs , hdev ,
& remote_oob_fops ) ;
2014-12-20 18:05:14 +03:00
debugfs_create_file ( " conn_info_min_age " , 0644 , hdev - > debugfs , hdev ,
& conn_info_min_age_fops ) ;
debugfs_create_file ( " conn_info_max_age " , 0644 , hdev - > debugfs , hdev ,
& conn_info_max_age_fops ) ;
2015-01-01 01:43:19 +03:00
2015-02-01 02:12:06 +03:00
if ( lmp_ssp_capable ( hdev ) | | lmp_le_capable ( hdev ) )
debugfs_create_file ( " use_debug_keys " , 0444 , hdev - > debugfs ,
hdev , & use_debug_keys_fops ) ;
2015-01-01 01:43:19 +03:00
if ( lmp_sc_capable ( hdev ) | | lmp_le_capable ( hdev ) )
debugfs_create_file ( " sc_only_mode " , 0444 , hdev - > debugfs ,
hdev , & sc_only_mode_fops ) ;
2016-07-17 20:55:16 +03:00
if ( hdev - > hw_info )
debugfs_create_file ( " hardware_info " , 0444 , hdev - > debugfs ,
hdev , & hardware_info_fops ) ;
if ( hdev - > fw_info )
debugfs_create_file ( " firmware_info " , 0444 , hdev - > debugfs ,
hdev , & firmware_info_fops ) ;
2014-12-20 18:05:13 +03:00
}
2014-12-20 18:05:15 +03:00
static int inquiry_cache_show ( struct seq_file * f , void * p )
{
struct hci_dev * hdev = f - > private ;
struct discovery_state * cache = & hdev - > discovery ;
struct inquiry_entry * e ;
hci_dev_lock ( hdev ) ;
list_for_each_entry ( e , & cache - > all , all ) {
struct inquiry_data * data = & e - > data ;
seq_printf ( f , " %pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u \n " ,
& data - > bdaddr ,
data - > pscan_rep_mode , data - > pscan_period_mode ,
data - > pscan_mode , data - > dev_class [ 2 ] ,
data - > dev_class [ 1 ] , data - > dev_class [ 0 ] ,
__le16_to_cpu ( data - > clock_offset ) ,
data - > rssi , data - > ssp_mode , e - > timestamp ) ;
}
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( inquiry_cache ) ;
2014-12-20 18:05:15 +03:00
static int link_keys_show ( struct seq_file * f , void * ptr )
{
struct hci_dev * hdev = f - > private ;
struct link_key * key ;
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( key , & hdev - > link_keys , list )
seq_printf ( f , " %pMR %u %*phN %u \n " , & key - > bdaddr , key - > type ,
HCI_LINK_KEY_SIZE , key - > val , key - > pin_len ) ;
rcu_read_unlock ( ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( link_keys ) ;
2014-12-20 18:05:15 +03:00
static int dev_class_show ( struct seq_file * f , void * ptr )
{
struct hci_dev * hdev = f - > private ;
hci_dev_lock ( hdev ) ;
seq_printf ( f , " 0x%.2x%.2x%.2x \n " , hdev - > dev_class [ 2 ] ,
hdev - > dev_class [ 1 ] , hdev - > dev_class [ 0 ] ) ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( dev_class ) ;
2014-12-20 18:05:15 +03:00
static int voice_setting_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > voice_setting ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( voice_setting_fops , voice_setting_get ,
NULL , " 0x%4.4llx \n " ) ;
2014-12-20 18:05:15 +03:00
2015-02-01 02:07:51 +03:00
static ssize_t ssp_debug_mode_read ( struct file * file , char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct hci_dev * hdev = file - > private_data ;
char buf [ 3 ] ;
2021-04-01 09:50:39 +03:00
buf [ 0 ] = hdev - > ssp_debug_mode ? ' Y ' : ' N ' ;
2015-02-01 02:07:51 +03:00
buf [ 1 ] = ' \n ' ;
buf [ 2 ] = ' \0 ' ;
return simple_read_from_buffer ( user_buf , count , ppos , buf , 2 ) ;
}
static const struct file_operations ssp_debug_mode_fops = {
. open = simple_open ,
. read = ssp_debug_mode_read ,
. llseek = default_llseek ,
} ;
2014-12-20 18:05:15 +03:00
static int auto_accept_delay_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
hdev - > auto_accept_delay = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2019-07-16 21:34:41 +03:00
static int min_encrypt_key_size_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val < 1 | | val > 16 )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > min_enc_key_size = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int min_encrypt_key_size_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > min_enc_key_size ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( min_encrypt_key_size_fops ,
min_encrypt_key_size_get ,
min_encrypt_key_size_set , " %llu \n " ) ;
2019-07-16 21:34:41 +03:00
2014-12-20 18:05:15 +03:00
static int auto_accept_delay_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > auto_accept_delay ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( auto_accept_delay_fops , auto_accept_delay_get ,
auto_accept_delay_set , " %llu \n " ) ;
2014-12-20 18:05:15 +03:00
2020-09-29 11:03:24 +03:00
static ssize_t force_bredr_smp_read ( struct file * file ,
char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct hci_dev * hdev = file - > private_data ;
char buf [ 3 ] ;
buf [ 0 ] = hci_dev_test_flag ( hdev , HCI_FORCE_BREDR_SMP ) ? ' Y ' : ' N ' ;
buf [ 1 ] = ' \n ' ;
buf [ 2 ] = ' \0 ' ;
return simple_read_from_buffer ( user_buf , count , ppos , buf , 2 ) ;
}
static ssize_t force_bredr_smp_write ( struct file * file ,
const char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct hci_dev * hdev = file - > private_data ;
bool enable ;
int err ;
err = kstrtobool_from_user ( user_buf , count , & enable ) ;
if ( err )
return err ;
err = smp_force_bredr ( hdev , enable ) ;
if ( err )
return err ;
return count ;
}
static const struct file_operations force_bredr_smp_fops = {
. open = simple_open ,
. read = force_bredr_smp_read ,
. write = force_bredr_smp_write ,
. llseek = default_llseek ,
} ;
2014-12-20 18:05:15 +03:00
static int idle_timeout_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val ! = 0 & & ( val < 500 | | val > 3600000 ) )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > idle_timeout = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int idle_timeout_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > idle_timeout ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( idle_timeout_fops , idle_timeout_get ,
idle_timeout_set , " %llu \n " ) ;
2014-12-20 18:05:15 +03:00
static int sniff_min_interval_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val = = 0 | | val % 2 | | val > hdev - > sniff_max_interval )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > sniff_min_interval = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int sniff_min_interval_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > sniff_min_interval ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( sniff_min_interval_fops , sniff_min_interval_get ,
sniff_min_interval_set , " %llu \n " ) ;
2014-12-20 18:05:15 +03:00
static int sniff_max_interval_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val = = 0 | | val % 2 | | val < hdev - > sniff_min_interval )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > sniff_max_interval = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int sniff_max_interval_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > sniff_max_interval ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( sniff_max_interval_fops , sniff_max_interval_get ,
sniff_max_interval_set , " %llu \n " ) ;
2014-12-20 18:05:15 +03:00
2014-12-20 18:05:13 +03:00
void hci_debugfs_create_bredr ( struct hci_dev * hdev )
{
2014-12-20 18:05:15 +03:00
debugfs_create_file ( " inquiry_cache " , 0444 , hdev - > debugfs , hdev ,
& inquiry_cache_fops ) ;
debugfs_create_file ( " link_keys " , 0400 , hdev - > debugfs , hdev ,
& link_keys_fops ) ;
debugfs_create_file ( " dev_class " , 0444 , hdev - > debugfs , hdev ,
& dev_class_fops ) ;
debugfs_create_file ( " voice_setting " , 0444 , hdev - > debugfs , hdev ,
& voice_setting_fops ) ;
2020-09-29 11:03:24 +03:00
/* If the controller does not support BR/EDR Secure Connections
* feature , then the BR / EDR SMP channel shall not be present .
*
* To test this with Bluetooth 4.0 controllers , create a debugfs
* switch that allows forcing BR / EDR SMP support and accepting
* cross - transport pairing on non - AES encrypted connections .
*/
if ( ! lmp_sc_capable ( hdev ) )
debugfs_create_file ( " force_bredr_smp " , 0644 , hdev - > debugfs ,
hdev , & force_bredr_smp_fops ) ;
2015-02-01 02:07:51 +03:00
if ( lmp_ssp_capable ( hdev ) ) {
debugfs_create_file ( " ssp_debug_mode " , 0444 , hdev - > debugfs ,
hdev , & ssp_debug_mode_fops ) ;
2019-07-16 21:34:41 +03:00
debugfs_create_file ( " min_encrypt_key_size " , 0644 , hdev - > debugfs ,
hdev , & min_encrypt_key_size_fops ) ;
2014-12-20 18:05:15 +03:00
debugfs_create_file ( " auto_accept_delay " , 0644 , hdev - > debugfs ,
hdev , & auto_accept_delay_fops ) ;
2015-02-01 02:07:51 +03:00
}
2014-12-20 18:05:15 +03:00
if ( lmp_sniff_capable ( hdev ) ) {
debugfs_create_file ( " idle_timeout " , 0644 , hdev - > debugfs ,
hdev , & idle_timeout_fops ) ;
debugfs_create_file ( " sniff_min_interval " , 0644 , hdev - > debugfs ,
hdev , & sniff_min_interval_fops ) ;
debugfs_create_file ( " sniff_max_interval " , 0644 , hdev - > debugfs ,
hdev , & sniff_max_interval_fops ) ;
}
2014-12-20 18:05:13 +03:00
}
2014-12-20 18:05:16 +03:00
static int identity_show ( struct seq_file * f , void * p )
{
struct hci_dev * hdev = f - > private ;
bdaddr_t addr ;
u8 addr_type ;
hci_dev_lock ( hdev ) ;
hci_copy_identity_address ( hdev , & addr , & addr_type ) ;
seq_printf ( f , " %pMR (type %u) %*phN %pMR \n " , & addr , addr_type ,
16 , hdev - > irk , & hdev - > rpa ) ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( identity ) ;
2014-12-20 18:05:16 +03:00
static int rpa_timeout_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
/* Require the RPA timeout to be at least 30 seconds and at most
* 24 hours .
*/
if ( val < 30 | | val > ( 60 * 60 * 24 ) )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > rpa_timeout = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int rpa_timeout_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > rpa_timeout ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( rpa_timeout_fops , rpa_timeout_get ,
rpa_timeout_set , " %llu \n " ) ;
2014-12-20 18:05:16 +03:00
static int random_address_show ( struct seq_file * f , void * p )
{
struct hci_dev * hdev = f - > private ;
hci_dev_lock ( hdev ) ;
seq_printf ( f , " %pMR \n " , & hdev - > random_addr ) ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( random_address ) ;
2014-12-20 18:05:16 +03:00
static int static_address_show ( struct seq_file * f , void * p )
{
struct hci_dev * hdev = f - > private ;
hci_dev_lock ( hdev ) ;
seq_printf ( f , " %pMR \n " , & hdev - > static_addr ) ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( static_address ) ;
2014-12-20 18:05:16 +03:00
static ssize_t force_static_address_read ( struct file * file ,
char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct hci_dev * hdev = file - > private_data ;
char buf [ 3 ] ;
2021-04-01 09:50:39 +03:00
buf [ 0 ] = hci_dev_test_flag ( hdev , HCI_FORCE_STATIC_ADDR ) ? ' Y ' : ' N ' ;
2014-12-20 18:05:16 +03:00
buf [ 1 ] = ' \n ' ;
buf [ 2 ] = ' \0 ' ;
return simple_read_from_buffer ( user_buf , count , ppos , buf , 2 ) ;
}
static ssize_t force_static_address_write ( struct file * file ,
const char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct hci_dev * hdev = file - > private_data ;
bool enable ;
2018-05-29 16:33:48 +03:00
int err ;
2014-12-20 18:05:16 +03:00
if ( test_bit ( HCI_UP , & hdev - > flags ) )
return - EBUSY ;
2018-05-29 16:33:48 +03:00
err = kstrtobool_from_user ( user_buf , count , & enable ) ;
if ( err )
return err ;
2014-12-20 18:05:16 +03:00
2015-03-13 20:20:35 +03:00
if ( enable = = hci_dev_test_flag ( hdev , HCI_FORCE_STATIC_ADDR ) )
2014-12-20 18:05:16 +03:00
return - EALREADY ;
2015-03-13 20:20:35 +03:00
hci_dev_change_flag ( hdev , HCI_FORCE_STATIC_ADDR ) ;
2014-12-20 18:05:16 +03:00
return count ;
}
static const struct file_operations force_static_address_fops = {
. open = simple_open ,
. read = force_static_address_read ,
. write = force_static_address_write ,
. llseek = default_llseek ,
} ;
static int white_list_show ( struct seq_file * f , void * ptr )
{
struct hci_dev * hdev = f - > private ;
struct bdaddr_list * b ;
hci_dev_lock ( hdev ) ;
2021-06-04 11:26:27 +03:00
list_for_each_entry ( b , & hdev - > le_accept_list , list )
2014-12-20 18:05:16 +03:00
seq_printf ( f , " %pMR (type %u) \n " , & b - > bdaddr , b - > bdaddr_type ) ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( white_list ) ;
2014-12-20 18:05:16 +03:00
2018-06-29 09:42:50 +03:00
static int resolv_list_show ( struct seq_file * f , void * ptr )
{
struct hci_dev * hdev = f - > private ;
struct bdaddr_list * b ;
hci_dev_lock ( hdev ) ;
list_for_each_entry ( b , & hdev - > le_resolv_list , list )
seq_printf ( f , " %pMR (type %u) \n " , & b - > bdaddr , b - > bdaddr_type ) ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
DEFINE_SHOW_ATTRIBUTE ( resolv_list ) ;
2014-12-20 18:05:16 +03:00
static int identity_resolving_keys_show ( struct seq_file * f , void * ptr )
{
struct hci_dev * hdev = f - > private ;
struct smp_irk * irk ;
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( irk , & hdev - > identity_resolving_keys , list ) {
seq_printf ( f , " %pMR (type %u) %*phN %pMR \n " ,
& irk - > bdaddr , irk - > addr_type ,
16 , irk - > val , & irk - > rpa ) ;
}
rcu_read_unlock ( ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( identity_resolving_keys ) ;
2014-12-20 18:05:16 +03:00
static int long_term_keys_show ( struct seq_file * f , void * ptr )
{
struct hci_dev * hdev = f - > private ;
struct smp_ltk * ltk ;
rcu_read_lock ( ) ;
list_for_each_entry_rcu ( ltk , & hdev - > long_term_keys , list )
seq_printf ( f , " %pMR (type %u) %u 0x%02x %u %.4x %.16llx %*phN \n " ,
& ltk - > bdaddr , ltk - > bdaddr_type , ltk - > authenticated ,
ltk - > type , ltk - > enc_size , __le16_to_cpu ( ltk - > ediv ) ,
__le64_to_cpu ( ltk - > rand ) , 16 , ltk - > val ) ;
rcu_read_unlock ( ) ;
return 0 ;
}
2017-11-23 00:15:46 +03:00
DEFINE_SHOW_ATTRIBUTE ( long_term_keys ) ;
2014-12-20 18:05:16 +03:00
static int conn_min_interval_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val < 0x0006 | | val > 0x0c80 | | val > hdev - > le_conn_max_interval )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > le_conn_min_interval = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int conn_min_interval_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > le_conn_min_interval ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( conn_min_interval_fops , conn_min_interval_get ,
conn_min_interval_set , " %llu \n " ) ;
2014-12-20 18:05:16 +03:00
static int conn_max_interval_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val < 0x0006 | | val > 0x0c80 | | val < hdev - > le_conn_min_interval )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > le_conn_max_interval = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int conn_max_interval_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > le_conn_max_interval ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( conn_max_interval_fops , conn_max_interval_get ,
conn_max_interval_set , " %llu \n " ) ;
2014-12-20 18:05:16 +03:00
static int conn_latency_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val > 0x01f3 )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > le_conn_latency = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int conn_latency_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > le_conn_latency ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( conn_latency_fops , conn_latency_get ,
conn_latency_set , " %llu \n " ) ;
2014-12-20 18:05:16 +03:00
static int supervision_timeout_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val < 0x000a | | val > 0x0c80 )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > le_supv_timeout = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int supervision_timeout_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > le_supv_timeout ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( supervision_timeout_fops , supervision_timeout_get ,
supervision_timeout_set , " %llu \n " ) ;
2014-12-20 18:05:16 +03:00
static int adv_channel_map_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val < 0x01 | | val > 0x07 )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > le_adv_channel_map = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int adv_channel_map_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > le_adv_channel_map ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( adv_channel_map_fops , adv_channel_map_get ,
adv_channel_map_set , " %llu \n " ) ;
2014-12-20 18:05:16 +03:00
static int adv_min_interval_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val < 0x0020 | | val > 0x4000 | | val > hdev - > le_adv_max_interval )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > le_adv_min_interval = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int adv_min_interval_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > le_adv_min_interval ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( adv_min_interval_fops , adv_min_interval_get ,
adv_min_interval_set , " %llu \n " ) ;
2014-12-20 18:05:16 +03:00
static int adv_max_interval_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val < 0x0020 | | val > 0x4000 | | val < hdev - > le_adv_min_interval )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > le_adv_max_interval = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int adv_max_interval_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > le_adv_max_interval ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( adv_max_interval_fops , adv_max_interval_get ,
adv_max_interval_set , " %llu \n " ) ;
2014-12-20 18:05:16 +03:00
2020-01-25 11:19:51 +03:00
static int min_key_size_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val > hdev - > le_max_key_size | | val < SMP_MIN_ENC_KEY_SIZE )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > le_min_key_size = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int min_key_size_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > le_min_key_size ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( min_key_size_fops , min_key_size_get ,
min_key_size_set , " %llu \n " ) ;
2020-01-25 11:19:51 +03:00
static int max_key_size_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val > SMP_MAX_ENC_KEY_SIZE | | val < hdev - > le_min_key_size )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > le_max_key_size = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int max_key_size_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > le_max_key_size ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( max_key_size_fops , max_key_size_get ,
max_key_size_set , " %llu \n " ) ;
2020-01-25 11:19:51 +03:00
2019-06-21 12:21:56 +03:00
static int auth_payload_timeout_set ( void * data , u64 val )
{
struct hci_dev * hdev = data ;
if ( val < 0x0001 | | val > 0xffff )
return - EINVAL ;
hci_dev_lock ( hdev ) ;
hdev - > auth_payload_timeout = val ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
static int auth_payload_timeout_get ( void * data , u64 * val )
{
struct hci_dev * hdev = data ;
hci_dev_lock ( hdev ) ;
* val = hdev - > auth_payload_timeout ;
hci_dev_unlock ( hdev ) ;
return 0 ;
}
2021-01-27 09:17:33 +03:00
DEFINE_DEBUGFS_ATTRIBUTE ( auth_payload_timeout_fops ,
auth_payload_timeout_get ,
auth_payload_timeout_set , " %llu \n " ) ;
2019-06-21 12:21:56 +03:00
2020-04-07 07:26:27 +03:00
static ssize_t force_no_mitm_read ( struct file * file ,
char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct hci_dev * hdev = file - > private_data ;
char buf [ 3 ] ;
buf [ 0 ] = hci_dev_test_flag ( hdev , HCI_FORCE_NO_MITM ) ? ' Y ' : ' N ' ;
buf [ 1 ] = ' \n ' ;
buf [ 2 ] = ' \0 ' ;
return simple_read_from_buffer ( user_buf , count , ppos , buf , 2 ) ;
}
static ssize_t force_no_mitm_write ( struct file * file ,
const char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct hci_dev * hdev = file - > private_data ;
char buf [ 32 ] ;
size_t buf_size = min ( count , ( sizeof ( buf ) - 1 ) ) ;
bool enable ;
if ( copy_from_user ( buf , user_buf , buf_size ) )
return - EFAULT ;
buf [ buf_size ] = ' \0 ' ;
if ( strtobool ( buf , & enable ) )
return - EINVAL ;
if ( enable = = hci_dev_test_flag ( hdev , HCI_FORCE_NO_MITM ) )
return - EALREADY ;
hci_dev_change_flag ( hdev , HCI_FORCE_NO_MITM ) ;
return count ;
}
static const struct file_operations force_no_mitm_fops = {
. open = simple_open ,
. read = force_no_mitm_read ,
. write = force_no_mitm_write ,
. llseek = default_llseek ,
} ;
2015-03-20 21:14:50 +03:00
DEFINE_QUIRK_ATTRIBUTE ( quirk_strict_duplicate_filter ,
HCI_QUIRK_STRICT_DUPLICATE_FILTER ) ;
DEFINE_QUIRK_ATTRIBUTE ( quirk_simultaneous_discovery ,
HCI_QUIRK_SIMULTANEOUS_DISCOVERY ) ;
2014-12-20 18:05:13 +03:00
void hci_debugfs_create_le ( struct hci_dev * hdev )
{
2014-12-20 18:05:16 +03:00
debugfs_create_file ( " identity " , 0400 , hdev - > debugfs , hdev ,
& identity_fops ) ;
debugfs_create_file ( " rpa_timeout " , 0644 , hdev - > debugfs , hdev ,
& rpa_timeout_fops ) ;
debugfs_create_file ( " random_address " , 0444 , hdev - > debugfs , hdev ,
& random_address_fops ) ;
debugfs_create_file ( " static_address " , 0444 , hdev - > debugfs , hdev ,
& static_address_fops ) ;
/* For controllers with a public address, provide a debug
* option to force the usage of the configured static
* address . By default the public address is used .
*/
if ( bacmp ( & hdev - > bdaddr , BDADDR_ANY ) )
debugfs_create_file ( " force_static_address " , 0644 ,
hdev - > debugfs , hdev ,
& force_static_address_fops ) ;
debugfs_create_u8 ( " white_list_size " , 0444 , hdev - > debugfs ,
2021-06-04 11:26:27 +03:00
& hdev - > le_accept_list_size ) ;
2014-12-20 18:05:16 +03:00
debugfs_create_file ( " white_list " , 0444 , hdev - > debugfs , hdev ,
& white_list_fops ) ;
2018-06-29 09:42:50 +03:00
debugfs_create_u8 ( " resolv_list_size " , 0444 , hdev - > debugfs ,
& hdev - > le_resolv_list_size ) ;
debugfs_create_file ( " resolv_list " , 0444 , hdev - > debugfs , hdev ,
& resolv_list_fops ) ;
2014-12-20 18:05:16 +03:00
debugfs_create_file ( " identity_resolving_keys " , 0400 , hdev - > debugfs ,
hdev , & identity_resolving_keys_fops ) ;
debugfs_create_file ( " long_term_keys " , 0400 , hdev - > debugfs , hdev ,
& long_term_keys_fops ) ;
debugfs_create_file ( " conn_min_interval " , 0644 , hdev - > debugfs , hdev ,
& conn_min_interval_fops ) ;
debugfs_create_file ( " conn_max_interval " , 0644 , hdev - > debugfs , hdev ,
& conn_max_interval_fops ) ;
debugfs_create_file ( " conn_latency " , 0644 , hdev - > debugfs , hdev ,
& conn_latency_fops ) ;
debugfs_create_file ( " supervision_timeout " , 0644 , hdev - > debugfs , hdev ,
& supervision_timeout_fops ) ;
debugfs_create_file ( " adv_channel_map " , 0644 , hdev - > debugfs , hdev ,
& adv_channel_map_fops ) ;
debugfs_create_file ( " adv_min_interval " , 0644 , hdev - > debugfs , hdev ,
& adv_min_interval_fops ) ;
debugfs_create_file ( " adv_max_interval " , 0644 , hdev - > debugfs , hdev ,
& adv_max_interval_fops ) ;
debugfs_create_u16 ( " discov_interleaved_timeout " , 0644 , hdev - > debugfs ,
& hdev - > discov_interleaved_timeout ) ;
2020-01-25 11:19:51 +03:00
debugfs_create_file ( " min_key_size " , 0644 , hdev - > debugfs , hdev ,
& min_key_size_fops ) ;
debugfs_create_file ( " max_key_size " , 0644 , hdev - > debugfs , hdev ,
& max_key_size_fops ) ;
2019-06-21 12:21:56 +03:00
debugfs_create_file ( " auth_payload_timeout " , 0644 , hdev - > debugfs , hdev ,
& auth_payload_timeout_fops ) ;
2020-04-07 07:26:27 +03:00
debugfs_create_file ( " force_no_mitm " , 0644 , hdev - > debugfs , hdev ,
& force_no_mitm_fops ) ;
2015-03-20 21:14:50 +03:00
debugfs_create_file ( " quirk_strict_duplicate_filter " , 0644 ,
hdev - > debugfs , hdev ,
& quirk_strict_duplicate_filter_fops ) ;
debugfs_create_file ( " quirk_simultaneous_discovery " , 0644 ,
hdev - > debugfs , hdev ,
& quirk_simultaneous_discovery_fops ) ;
2014-12-20 18:05:13 +03:00
}
2014-12-20 19:13:41 +03:00
void hci_debugfs_create_conn ( struct hci_conn * conn )
{
struct hci_dev * hdev = conn - > hdev ;
char name [ 6 ] ;
2022-09-19 20:57:00 +03:00
if ( IS_ERR_OR_NULL ( hdev - > debugfs ) | | conn - > debugfs )
2014-12-20 19:13:41 +03:00
return ;
snprintf ( name , sizeof ( name ) , " %u " , conn - > handle ) ;
conn - > debugfs = debugfs_create_dir ( name , hdev - > debugfs ) ;
}
2021-09-21 21:25:04 +03:00
static ssize_t dut_mode_read ( struct file * file , char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct hci_dev * hdev = file - > private_data ;
char buf [ 3 ] ;
buf [ 0 ] = hci_dev_test_flag ( hdev , HCI_DUT_MODE ) ? ' Y ' : ' N ' ;
buf [ 1 ] = ' \n ' ;
buf [ 2 ] = ' \0 ' ;
return simple_read_from_buffer ( user_buf , count , ppos , buf , 2 ) ;
}
static ssize_t dut_mode_write ( struct file * file , const char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct hci_dev * hdev = file - > private_data ;
struct sk_buff * skb ;
bool enable ;
int err ;
if ( ! test_bit ( HCI_UP , & hdev - > flags ) )
return - ENETDOWN ;
err = kstrtobool_from_user ( user_buf , count , & enable ) ;
if ( err )
return err ;
if ( enable = = hci_dev_test_flag ( hdev , HCI_DUT_MODE ) )
return - EALREADY ;
hci_req_sync_lock ( hdev ) ;
if ( enable )
skb = __hci_cmd_sync ( hdev , HCI_OP_ENABLE_DUT_MODE , 0 , NULL ,
HCI_CMD_TIMEOUT ) ;
else
skb = __hci_cmd_sync ( hdev , HCI_OP_RESET , 0 , NULL ,
HCI_CMD_TIMEOUT ) ;
hci_req_sync_unlock ( hdev ) ;
if ( IS_ERR ( skb ) )
return PTR_ERR ( skb ) ;
kfree_skb ( skb ) ;
hci_dev_change_flag ( hdev , HCI_DUT_MODE ) ;
return count ;
}
static const struct file_operations dut_mode_fops = {
. open = simple_open ,
. read = dut_mode_read ,
. write = dut_mode_write ,
. llseek = default_llseek ,
} ;
static ssize_t vendor_diag_read ( struct file * file , char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct hci_dev * hdev = file - > private_data ;
char buf [ 3 ] ;
buf [ 0 ] = hci_dev_test_flag ( hdev , HCI_VENDOR_DIAG ) ? ' Y ' : ' N ' ;
buf [ 1 ] = ' \n ' ;
buf [ 2 ] = ' \0 ' ;
return simple_read_from_buffer ( user_buf , count , ppos , buf , 2 ) ;
}
static ssize_t vendor_diag_write ( struct file * file , const char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct hci_dev * hdev = file - > private_data ;
bool enable ;
int err ;
err = kstrtobool_from_user ( user_buf , count , & enable ) ;
if ( err )
return err ;
/* When the diagnostic flags are not persistent and the transport
* is not active or in user channel operation , then there is no need
* for the vendor callback . Instead just store the desired value and
* the setting will be programmed when the controller gets powered on .
*/
if ( test_bit ( HCI_QUIRK_NON_PERSISTENT_DIAG , & hdev - > quirks ) & &
( ! test_bit ( HCI_RUNNING , & hdev - > flags ) | |
hci_dev_test_flag ( hdev , HCI_USER_CHANNEL ) ) )
goto done ;
hci_req_sync_lock ( hdev ) ;
err = hdev - > set_diag ( hdev , enable ) ;
hci_req_sync_unlock ( hdev ) ;
if ( err < 0 )
return err ;
done :
if ( enable )
hci_dev_set_flag ( hdev , HCI_VENDOR_DIAG ) ;
else
hci_dev_clear_flag ( hdev , HCI_VENDOR_DIAG ) ;
return count ;
}
static const struct file_operations vendor_diag_fops = {
. open = simple_open ,
. read = vendor_diag_read ,
. write = vendor_diag_write ,
. llseek = default_llseek ,
} ;
void hci_debugfs_create_basic ( struct hci_dev * hdev )
{
debugfs_create_file ( " dut_mode " , 0644 , hdev - > debugfs , hdev ,
& dut_mode_fops ) ;
if ( hdev - > set_diag )
debugfs_create_file ( " vendor_diag " , 0644 , hdev - > debugfs , hdev ,
& vendor_diag_fops ) ;
}