2020-06-11 05:01:57 +03:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright ( C ) 2020 Google Corporation
*/
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
# include <net/bluetooth/mgmt.h>
# include "mgmt_util.h"
# include "mgmt_config.h"
2020-11-26 07:22:24 +03:00
# define HDEV_PARAM_U16(_param_name_) \
struct { \
struct mgmt_tlv entry ; \
__le16 value ; \
} __packed _param_name_
2020-06-11 05:01:57 +03:00
2020-11-26 07:22:25 +03:00
# define HDEV_PARAM_U8(_param_name_) \
struct { \
struct mgmt_tlv entry ; \
__u8 value ; \
} __packed _param_name_
2020-11-26 07:22:24 +03:00
# define TLV_SET_U16(_param_code_, _param_name_) \
{ \
{ cpu_to_le16 ( _param_code_ ) , sizeof ( __u16 ) } , \
cpu_to_le16 ( hdev - > _param_name_ ) \
}
2020-11-26 07:22:25 +03:00
# define TLV_SET_U8(_param_code_, _param_name_) \
{ \
{ cpu_to_le16 ( _param_code_ ) , sizeof ( __u8 ) } , \
hdev - > _param_name_ \
}
2020-11-26 07:22:24 +03:00
# define TLV_SET_U16_JIFFIES_TO_MSECS(_param_code_, _param_name_) \
{ \
{ cpu_to_le16 ( _param_code_ ) , sizeof ( __u16 ) } , \
cpu_to_le16 ( jiffies_to_msecs ( hdev - > _param_name_ ) ) \
}
2020-06-29 19:11:00 +03:00
2020-06-11 05:01:57 +03:00
int read_def_system_config ( struct sock * sk , struct hci_dev * hdev , void * data ,
u16 data_len )
{
2020-11-26 07:22:24 +03:00
int ret ;
struct mgmt_rp_read_def_system_config {
2020-06-11 05:01:57 +03:00
/* Please see mgmt-api.txt for documentation of these values */
2020-11-26 07:22:24 +03:00
HDEV_PARAM_U16 ( def_page_scan_type ) ;
HDEV_PARAM_U16 ( def_page_scan_int ) ;
HDEV_PARAM_U16 ( def_page_scan_window ) ;
HDEV_PARAM_U16 ( def_inq_scan_type ) ;
HDEV_PARAM_U16 ( def_inq_scan_int ) ;
HDEV_PARAM_U16 ( def_inq_scan_window ) ;
HDEV_PARAM_U16 ( def_br_lsto ) ;
HDEV_PARAM_U16 ( def_page_timeout ) ;
HDEV_PARAM_U16 ( sniff_min_interval ) ;
HDEV_PARAM_U16 ( sniff_max_interval ) ;
HDEV_PARAM_U16 ( le_adv_min_interval ) ;
HDEV_PARAM_U16 ( le_adv_max_interval ) ;
HDEV_PARAM_U16 ( def_multi_adv_rotation_duration ) ;
HDEV_PARAM_U16 ( le_scan_interval ) ;
HDEV_PARAM_U16 ( le_scan_window ) ;
HDEV_PARAM_U16 ( le_scan_int_suspend ) ;
HDEV_PARAM_U16 ( le_scan_window_suspend ) ;
HDEV_PARAM_U16 ( le_scan_int_discovery ) ;
HDEV_PARAM_U16 ( le_scan_window_discovery ) ;
HDEV_PARAM_U16 ( le_scan_int_adv_monitor ) ;
HDEV_PARAM_U16 ( le_scan_window_adv_monitor ) ;
HDEV_PARAM_U16 ( le_scan_int_connect ) ;
HDEV_PARAM_U16 ( le_scan_window_connect ) ;
HDEV_PARAM_U16 ( le_conn_min_interval ) ;
HDEV_PARAM_U16 ( le_conn_max_interval ) ;
HDEV_PARAM_U16 ( le_conn_latency ) ;
HDEV_PARAM_U16 ( le_supv_timeout ) ;
HDEV_PARAM_U16 ( def_le_autoconnect_timeout ) ;
HDEV_PARAM_U16 ( advmon_allowlist_duration ) ;
HDEV_PARAM_U16 ( advmon_no_filter_duration ) ;
2020-11-26 07:22:25 +03:00
HDEV_PARAM_U8 ( enable_advmon_interleave_scan ) ;
2020-11-26 07:22:24 +03:00
} __packed rp = {
TLV_SET_U16 ( 0x0000 , def_page_scan_type ) ,
TLV_SET_U16 ( 0x0001 , def_page_scan_int ) ,
TLV_SET_U16 ( 0x0002 , def_page_scan_window ) ,
TLV_SET_U16 ( 0x0003 , def_inq_scan_type ) ,
TLV_SET_U16 ( 0x0004 , def_inq_scan_int ) ,
TLV_SET_U16 ( 0x0005 , def_inq_scan_window ) ,
TLV_SET_U16 ( 0x0006 , def_br_lsto ) ,
TLV_SET_U16 ( 0x0007 , def_page_timeout ) ,
TLV_SET_U16 ( 0x0008 , sniff_min_interval ) ,
TLV_SET_U16 ( 0x0009 , sniff_max_interval ) ,
TLV_SET_U16 ( 0x000a , le_adv_min_interval ) ,
TLV_SET_U16 ( 0x000b , le_adv_max_interval ) ,
TLV_SET_U16 ( 0x000c , def_multi_adv_rotation_duration ) ,
TLV_SET_U16 ( 0x000d , le_scan_interval ) ,
TLV_SET_U16 ( 0x000e , le_scan_window ) ,
TLV_SET_U16 ( 0x000f , le_scan_int_suspend ) ,
TLV_SET_U16 ( 0x0010 , le_scan_window_suspend ) ,
TLV_SET_U16 ( 0x0011 , le_scan_int_discovery ) ,
TLV_SET_U16 ( 0x0012 , le_scan_window_discovery ) ,
TLV_SET_U16 ( 0x0013 , le_scan_int_adv_monitor ) ,
TLV_SET_U16 ( 0x0014 , le_scan_window_adv_monitor ) ,
TLV_SET_U16 ( 0x0015 , le_scan_int_connect ) ,
TLV_SET_U16 ( 0x0016 , le_scan_window_connect ) ,
TLV_SET_U16 ( 0x0017 , le_conn_min_interval ) ,
TLV_SET_U16 ( 0x0018 , le_conn_max_interval ) ,
TLV_SET_U16 ( 0x0019 , le_conn_latency ) ,
TLV_SET_U16 ( 0x001a , le_supv_timeout ) ,
TLV_SET_U16_JIFFIES_TO_MSECS ( 0x001b ,
def_le_autoconnect_timeout ) ,
TLV_SET_U16 ( 0x001d , advmon_allowlist_duration ) ,
TLV_SET_U16 ( 0x001e , advmon_no_filter_duration ) ,
2020-11-26 07:22:25 +03:00
TLV_SET_U8 ( 0x001f , enable_advmon_interleave_scan ) ,
2020-06-11 05:01:57 +03:00
} ;
bt_dev_dbg ( hdev , " sock %p " , sk ) ;
2020-11-26 07:22:24 +03:00
ret = mgmt_cmd_complete ( sk , hdev - > id ,
MGMT_OP_READ_DEF_SYSTEM_CONFIG ,
0 , & rp , sizeof ( rp ) ) ;
return ret ;
2020-06-11 05:01:57 +03:00
}
# define TO_TLV(x) ((struct mgmt_tlv *)(x))
# define TLV_GET_LE16(tlv) le16_to_cpu(*((__le16 *)(TO_TLV(tlv)->value)))
2020-11-26 07:22:25 +03:00
# define TLV_GET_U8(tlv) (*((__u8 *)(TO_TLV(tlv)->value)))
2020-06-11 05:01:57 +03:00
int set_def_system_config ( struct sock * sk , struct hci_dev * hdev , void * data ,
u16 data_len )
{
u16 buffer_left = data_len ;
u8 * buffer = data ;
if ( buffer_left < sizeof ( struct mgmt_tlv ) ) {
return mgmt_cmd_status ( sk , hdev - > id ,
MGMT_OP_SET_DEF_SYSTEM_CONFIG ,
MGMT_STATUS_INVALID_PARAMS ) ;
}
/* First pass to validate the tlv */
while ( buffer_left > = sizeof ( struct mgmt_tlv ) ) {
const u8 len = TO_TLV ( buffer ) - > length ;
2020-11-26 07:22:25 +03:00
size_t exp_type_len ;
2020-06-11 05:01:57 +03:00
const u16 exp_len = sizeof ( struct mgmt_tlv ) +
len ;
const u16 type = le16_to_cpu ( TO_TLV ( buffer ) - > type ) ;
if ( buffer_left < exp_len ) {
2021-06-03 10:41:02 +03:00
bt_dev_warn ( hdev , " invalid len left %u, exp >= %u " ,
2020-06-11 05:01:57 +03:00
buffer_left , exp_len ) ;
return mgmt_cmd_status ( sk , hdev - > id ,
MGMT_OP_SET_DEF_SYSTEM_CONFIG ,
MGMT_STATUS_INVALID_PARAMS ) ;
}
/* Please see mgmt-api.txt for documentation of these values */
switch ( type ) {
case 0x0000 :
case 0x0001 :
case 0x0002 :
case 0x0003 :
case 0x0004 :
case 0x0005 :
case 0x0006 :
case 0x0007 :
case 0x0008 :
case 0x0009 :
case 0x000a :
case 0x000b :
case 0x000c :
case 0x000d :
case 0x000e :
case 0x000f :
case 0x0010 :
case 0x0011 :
case 0x0012 :
case 0x0013 :
case 0x0014 :
case 0x0015 :
case 0x0016 :
case 0x0017 :
case 0x0018 :
case 0x0019 :
case 0x001a :
2020-06-29 19:11:00 +03:00
case 0x001b :
2020-11-26 07:22:21 +03:00
case 0x001d :
case 0x001e :
2020-11-26 07:22:25 +03:00
exp_type_len = sizeof ( u16 ) ;
break ;
case 0x001f :
exp_type_len = sizeof ( u8 ) ;
2020-06-11 05:01:57 +03:00
break ;
default :
2020-11-26 07:22:25 +03:00
exp_type_len = 0 ;
2020-06-11 05:01:57 +03:00
bt_dev_warn ( hdev , " unsupported parameter %u " , type ) ;
break ;
}
2020-11-26 07:22:25 +03:00
if ( exp_type_len & & len ! = exp_type_len ) {
2021-06-03 10:41:02 +03:00
bt_dev_warn ( hdev , " invalid length %d, exp %zu for type %u " ,
2020-11-26 07:22:25 +03:00
len , exp_type_len , type ) ;
return mgmt_cmd_status ( sk , hdev - > id ,
MGMT_OP_SET_DEF_SYSTEM_CONFIG ,
MGMT_STATUS_INVALID_PARAMS ) ;
}
2020-06-11 05:01:57 +03:00
buffer_left - = exp_len ;
buffer + = exp_len ;
}
buffer_left = data_len ;
buffer = data ;
while ( buffer_left > = sizeof ( struct mgmt_tlv ) ) {
const u8 len = TO_TLV ( buffer ) - > length ;
const u16 exp_len = sizeof ( struct mgmt_tlv ) +
len ;
const u16 type = le16_to_cpu ( TO_TLV ( buffer ) - > type ) ;
switch ( type ) {
case 0x0000 :
hdev - > def_page_scan_type = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x0001 :
hdev - > def_page_scan_int = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x0002 :
hdev - > def_page_scan_window = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x0003 :
hdev - > def_inq_scan_type = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x0004 :
hdev - > def_inq_scan_int = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x0005 :
hdev - > def_inq_scan_window = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x0006 :
hdev - > def_br_lsto = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x0007 :
hdev - > def_page_timeout = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x0008 :
hdev - > sniff_min_interval = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x0009 :
hdev - > sniff_max_interval = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x000a :
hdev - > le_adv_min_interval = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x000b :
hdev - > le_adv_max_interval = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x000c :
hdev - > def_multi_adv_rotation_duration =
TLV_GET_LE16 ( buffer ) ;
break ;
case 0x000d :
hdev - > le_scan_interval = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x000e :
hdev - > le_scan_window = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x000f :
hdev - > le_scan_int_suspend = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x0010 :
hdev - > le_scan_window_suspend = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x0011 :
hdev - > le_scan_int_discovery = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x00012 :
hdev - > le_scan_window_discovery = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x00013 :
hdev - > le_scan_int_adv_monitor = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x00014 :
hdev - > le_scan_window_adv_monitor = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x00015 :
hdev - > le_scan_int_connect = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x00016 :
hdev - > le_scan_window_connect = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x00017 :
hdev - > le_conn_min_interval = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x00018 :
hdev - > le_conn_max_interval = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x00019 :
hdev - > le_conn_latency = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x0001a :
hdev - > le_supv_timeout = TLV_GET_LE16 ( buffer ) ;
break ;
2020-06-29 19:11:00 +03:00
case 0x0001b :
hdev - > def_le_autoconnect_timeout =
msecs_to_jiffies ( TLV_GET_LE16 ( buffer ) ) ;
break ;
2020-11-26 07:22:21 +03:00
case 0x0001d :
hdev - > advmon_allowlist_duration = TLV_GET_LE16 ( buffer ) ;
break ;
case 0x0001e :
hdev - > advmon_no_filter_duration = TLV_GET_LE16 ( buffer ) ;
break ;
2020-11-26 07:22:25 +03:00
case 0x0001f :
hdev - > enable_advmon_interleave_scan = TLV_GET_U8 ( buffer ) ;
break ;
2020-06-11 05:01:57 +03:00
default :
bt_dev_warn ( hdev , " unsupported parameter %u " , type ) ;
break ;
}
buffer_left - = exp_len ;
buffer + = exp_len ;
}
2020-06-17 17:39:20 +03:00
return mgmt_cmd_complete ( sk , hdev - > id ,
MGMT_OP_SET_DEF_SYSTEM_CONFIG , 0 , NULL , 0 ) ;
2020-06-11 05:01:57 +03:00
}
2020-06-17 17:39:07 +03:00
int read_def_runtime_config ( struct sock * sk , struct hci_dev * hdev , void * data ,
u16 data_len )
{
bt_dev_dbg ( hdev , " sock %p " , sk ) ;
return mgmt_cmd_complete ( sk , hdev - > id ,
MGMT_OP_READ_DEF_RUNTIME_CONFIG , 0 , NULL , 0 ) ;
}
int set_def_runtime_config ( struct sock * sk , struct hci_dev * hdev , void * data ,
u16 data_len )
{
bt_dev_dbg ( hdev , " sock %p " , sk ) ;
return mgmt_cmd_status ( sk , hdev - > id , MGMT_OP_SET_DEF_SYSTEM_CONFIG ,
MGMT_STATUS_INVALID_PARAMS ) ;
}