mgmt_config.c (9489B)
1// SPDX-License-Identifier: GPL-2.0-only 2 3/* 4 * Copyright (C) 2020 Google Corporation 5 */ 6 7#include <net/bluetooth/bluetooth.h> 8#include <net/bluetooth/hci_core.h> 9#include <net/bluetooth/mgmt.h> 10 11#include "mgmt_util.h" 12#include "mgmt_config.h" 13 14#define HDEV_PARAM_U16(_param_name_) \ 15 struct {\ 16 struct mgmt_tlv entry; \ 17 __le16 value; \ 18 } __packed _param_name_ 19 20#define HDEV_PARAM_U8(_param_name_) \ 21 struct {\ 22 struct mgmt_tlv entry; \ 23 __u8 value; \ 24 } __packed _param_name_ 25 26#define TLV_SET_U16(_param_code_, _param_name_) \ 27 { \ 28 { cpu_to_le16(_param_code_), sizeof(__u16) }, \ 29 cpu_to_le16(hdev->_param_name_) \ 30 } 31 32#define TLV_SET_U8(_param_code_, _param_name_) \ 33 { \ 34 { cpu_to_le16(_param_code_), sizeof(__u8) }, \ 35 hdev->_param_name_ \ 36 } 37 38#define TLV_SET_U16_JIFFIES_TO_MSECS(_param_code_, _param_name_) \ 39 { \ 40 { cpu_to_le16(_param_code_), sizeof(__u16) }, \ 41 cpu_to_le16(jiffies_to_msecs(hdev->_param_name_)) \ 42 } 43 44int read_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data, 45 u16 data_len) 46{ 47 int ret; 48 struct mgmt_rp_read_def_system_config { 49 /* Please see mgmt-api.txt for documentation of these values */ 50 HDEV_PARAM_U16(def_page_scan_type); 51 HDEV_PARAM_U16(def_page_scan_int); 52 HDEV_PARAM_U16(def_page_scan_window); 53 HDEV_PARAM_U16(def_inq_scan_type); 54 HDEV_PARAM_U16(def_inq_scan_int); 55 HDEV_PARAM_U16(def_inq_scan_window); 56 HDEV_PARAM_U16(def_br_lsto); 57 HDEV_PARAM_U16(def_page_timeout); 58 HDEV_PARAM_U16(sniff_min_interval); 59 HDEV_PARAM_U16(sniff_max_interval); 60 HDEV_PARAM_U16(le_adv_min_interval); 61 HDEV_PARAM_U16(le_adv_max_interval); 62 HDEV_PARAM_U16(def_multi_adv_rotation_duration); 63 HDEV_PARAM_U16(le_scan_interval); 64 HDEV_PARAM_U16(le_scan_window); 65 HDEV_PARAM_U16(le_scan_int_suspend); 66 HDEV_PARAM_U16(le_scan_window_suspend); 67 HDEV_PARAM_U16(le_scan_int_discovery); 68 HDEV_PARAM_U16(le_scan_window_discovery); 69 HDEV_PARAM_U16(le_scan_int_adv_monitor); 70 HDEV_PARAM_U16(le_scan_window_adv_monitor); 71 HDEV_PARAM_U16(le_scan_int_connect); 72 HDEV_PARAM_U16(le_scan_window_connect); 73 HDEV_PARAM_U16(le_conn_min_interval); 74 HDEV_PARAM_U16(le_conn_max_interval); 75 HDEV_PARAM_U16(le_conn_latency); 76 HDEV_PARAM_U16(le_supv_timeout); 77 HDEV_PARAM_U16(def_le_autoconnect_timeout); 78 HDEV_PARAM_U16(advmon_allowlist_duration); 79 HDEV_PARAM_U16(advmon_no_filter_duration); 80 HDEV_PARAM_U8(enable_advmon_interleave_scan); 81 } __packed rp = { 82 TLV_SET_U16(0x0000, def_page_scan_type), 83 TLV_SET_U16(0x0001, def_page_scan_int), 84 TLV_SET_U16(0x0002, def_page_scan_window), 85 TLV_SET_U16(0x0003, def_inq_scan_type), 86 TLV_SET_U16(0x0004, def_inq_scan_int), 87 TLV_SET_U16(0x0005, def_inq_scan_window), 88 TLV_SET_U16(0x0006, def_br_lsto), 89 TLV_SET_U16(0x0007, def_page_timeout), 90 TLV_SET_U16(0x0008, sniff_min_interval), 91 TLV_SET_U16(0x0009, sniff_max_interval), 92 TLV_SET_U16(0x000a, le_adv_min_interval), 93 TLV_SET_U16(0x000b, le_adv_max_interval), 94 TLV_SET_U16(0x000c, def_multi_adv_rotation_duration), 95 TLV_SET_U16(0x000d, le_scan_interval), 96 TLV_SET_U16(0x000e, le_scan_window), 97 TLV_SET_U16(0x000f, le_scan_int_suspend), 98 TLV_SET_U16(0x0010, le_scan_window_suspend), 99 TLV_SET_U16(0x0011, le_scan_int_discovery), 100 TLV_SET_U16(0x0012, le_scan_window_discovery), 101 TLV_SET_U16(0x0013, le_scan_int_adv_monitor), 102 TLV_SET_U16(0x0014, le_scan_window_adv_monitor), 103 TLV_SET_U16(0x0015, le_scan_int_connect), 104 TLV_SET_U16(0x0016, le_scan_window_connect), 105 TLV_SET_U16(0x0017, le_conn_min_interval), 106 TLV_SET_U16(0x0018, le_conn_max_interval), 107 TLV_SET_U16(0x0019, le_conn_latency), 108 TLV_SET_U16(0x001a, le_supv_timeout), 109 TLV_SET_U16_JIFFIES_TO_MSECS(0x001b, 110 def_le_autoconnect_timeout), 111 TLV_SET_U16(0x001d, advmon_allowlist_duration), 112 TLV_SET_U16(0x001e, advmon_no_filter_duration), 113 TLV_SET_U8(0x001f, enable_advmon_interleave_scan), 114 }; 115 116 bt_dev_dbg(hdev, "sock %p", sk); 117 118 ret = mgmt_cmd_complete(sk, hdev->id, 119 MGMT_OP_READ_DEF_SYSTEM_CONFIG, 120 0, &rp, sizeof(rp)); 121 return ret; 122} 123 124#define TO_TLV(x) ((struct mgmt_tlv *)(x)) 125#define TLV_GET_LE16(tlv) le16_to_cpu(*((__le16 *)(TO_TLV(tlv)->value))) 126#define TLV_GET_U8(tlv) (*((__u8 *)(TO_TLV(tlv)->value))) 127 128int set_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data, 129 u16 data_len) 130{ 131 u16 buffer_left = data_len; 132 u8 *buffer = data; 133 134 if (buffer_left < sizeof(struct mgmt_tlv)) { 135 return mgmt_cmd_status(sk, hdev->id, 136 MGMT_OP_SET_DEF_SYSTEM_CONFIG, 137 MGMT_STATUS_INVALID_PARAMS); 138 } 139 140 /* First pass to validate the tlv */ 141 while (buffer_left >= sizeof(struct mgmt_tlv)) { 142 const u8 len = TO_TLV(buffer)->length; 143 size_t exp_type_len; 144 const u16 exp_len = sizeof(struct mgmt_tlv) + 145 len; 146 const u16 type = le16_to_cpu(TO_TLV(buffer)->type); 147 148 if (buffer_left < exp_len) { 149 bt_dev_warn(hdev, "invalid len left %u, exp >= %u", 150 buffer_left, exp_len); 151 152 return mgmt_cmd_status(sk, hdev->id, 153 MGMT_OP_SET_DEF_SYSTEM_CONFIG, 154 MGMT_STATUS_INVALID_PARAMS); 155 } 156 157 /* Please see mgmt-api.txt for documentation of these values */ 158 switch (type) { 159 case 0x0000: 160 case 0x0001: 161 case 0x0002: 162 case 0x0003: 163 case 0x0004: 164 case 0x0005: 165 case 0x0006: 166 case 0x0007: 167 case 0x0008: 168 case 0x0009: 169 case 0x000a: 170 case 0x000b: 171 case 0x000c: 172 case 0x000d: 173 case 0x000e: 174 case 0x000f: 175 case 0x0010: 176 case 0x0011: 177 case 0x0012: 178 case 0x0013: 179 case 0x0014: 180 case 0x0015: 181 case 0x0016: 182 case 0x0017: 183 case 0x0018: 184 case 0x0019: 185 case 0x001a: 186 case 0x001b: 187 case 0x001d: 188 case 0x001e: 189 exp_type_len = sizeof(u16); 190 break; 191 case 0x001f: 192 exp_type_len = sizeof(u8); 193 break; 194 default: 195 exp_type_len = 0; 196 bt_dev_warn(hdev, "unsupported parameter %u", type); 197 break; 198 } 199 200 if (exp_type_len && len != exp_type_len) { 201 bt_dev_warn(hdev, "invalid length %d, exp %zu for type %u", 202 len, exp_type_len, type); 203 204 return mgmt_cmd_status(sk, hdev->id, 205 MGMT_OP_SET_DEF_SYSTEM_CONFIG, 206 MGMT_STATUS_INVALID_PARAMS); 207 } 208 209 buffer_left -= exp_len; 210 buffer += exp_len; 211 } 212 213 buffer_left = data_len; 214 buffer = data; 215 while (buffer_left >= sizeof(struct mgmt_tlv)) { 216 const u8 len = TO_TLV(buffer)->length; 217 const u16 exp_len = sizeof(struct mgmt_tlv) + 218 len; 219 const u16 type = le16_to_cpu(TO_TLV(buffer)->type); 220 221 switch (type) { 222 case 0x0000: 223 hdev->def_page_scan_type = TLV_GET_LE16(buffer); 224 break; 225 case 0x0001: 226 hdev->def_page_scan_int = TLV_GET_LE16(buffer); 227 break; 228 case 0x0002: 229 hdev->def_page_scan_window = TLV_GET_LE16(buffer); 230 break; 231 case 0x0003: 232 hdev->def_inq_scan_type = TLV_GET_LE16(buffer); 233 break; 234 case 0x0004: 235 hdev->def_inq_scan_int = TLV_GET_LE16(buffer); 236 break; 237 case 0x0005: 238 hdev->def_inq_scan_window = TLV_GET_LE16(buffer); 239 break; 240 case 0x0006: 241 hdev->def_br_lsto = TLV_GET_LE16(buffer); 242 break; 243 case 0x0007: 244 hdev->def_page_timeout = TLV_GET_LE16(buffer); 245 break; 246 case 0x0008: 247 hdev->sniff_min_interval = TLV_GET_LE16(buffer); 248 break; 249 case 0x0009: 250 hdev->sniff_max_interval = TLV_GET_LE16(buffer); 251 break; 252 case 0x000a: 253 hdev->le_adv_min_interval = TLV_GET_LE16(buffer); 254 break; 255 case 0x000b: 256 hdev->le_adv_max_interval = TLV_GET_LE16(buffer); 257 break; 258 case 0x000c: 259 hdev->def_multi_adv_rotation_duration = 260 TLV_GET_LE16(buffer); 261 break; 262 case 0x000d: 263 hdev->le_scan_interval = TLV_GET_LE16(buffer); 264 break; 265 case 0x000e: 266 hdev->le_scan_window = TLV_GET_LE16(buffer); 267 break; 268 case 0x000f: 269 hdev->le_scan_int_suspend = TLV_GET_LE16(buffer); 270 break; 271 case 0x0010: 272 hdev->le_scan_window_suspend = TLV_GET_LE16(buffer); 273 break; 274 case 0x0011: 275 hdev->le_scan_int_discovery = TLV_GET_LE16(buffer); 276 break; 277 case 0x00012: 278 hdev->le_scan_window_discovery = TLV_GET_LE16(buffer); 279 break; 280 case 0x00013: 281 hdev->le_scan_int_adv_monitor = TLV_GET_LE16(buffer); 282 break; 283 case 0x00014: 284 hdev->le_scan_window_adv_monitor = TLV_GET_LE16(buffer); 285 break; 286 case 0x00015: 287 hdev->le_scan_int_connect = TLV_GET_LE16(buffer); 288 break; 289 case 0x00016: 290 hdev->le_scan_window_connect = TLV_GET_LE16(buffer); 291 break; 292 case 0x00017: 293 hdev->le_conn_min_interval = TLV_GET_LE16(buffer); 294 break; 295 case 0x00018: 296 hdev->le_conn_max_interval = TLV_GET_LE16(buffer); 297 break; 298 case 0x00019: 299 hdev->le_conn_latency = TLV_GET_LE16(buffer); 300 break; 301 case 0x0001a: 302 hdev->le_supv_timeout = TLV_GET_LE16(buffer); 303 break; 304 case 0x0001b: 305 hdev->def_le_autoconnect_timeout = 306 msecs_to_jiffies(TLV_GET_LE16(buffer)); 307 break; 308 case 0x0001d: 309 hdev->advmon_allowlist_duration = TLV_GET_LE16(buffer); 310 break; 311 case 0x0001e: 312 hdev->advmon_no_filter_duration = TLV_GET_LE16(buffer); 313 break; 314 case 0x0001f: 315 hdev->enable_advmon_interleave_scan = TLV_GET_U8(buffer); 316 break; 317 default: 318 bt_dev_warn(hdev, "unsupported parameter %u", type); 319 break; 320 } 321 322 buffer_left -= exp_len; 323 buffer += exp_len; 324 } 325 326 return mgmt_cmd_complete(sk, hdev->id, 327 MGMT_OP_SET_DEF_SYSTEM_CONFIG, 0, NULL, 0); 328} 329 330int read_def_runtime_config(struct sock *sk, struct hci_dev *hdev, void *data, 331 u16 data_len) 332{ 333 bt_dev_dbg(hdev, "sock %p", sk); 334 335 return mgmt_cmd_complete(sk, hdev->id, 336 MGMT_OP_READ_DEF_RUNTIME_CONFIG, 0, NULL, 0); 337} 338 339int set_def_runtime_config(struct sock *sk, struct hci_dev *hdev, void *data, 340 u16 data_len) 341{ 342 bt_dev_dbg(hdev, "sock %p", sk); 343 344 return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_DEF_SYSTEM_CONFIG, 345 MGMT_STATUS_INVALID_PARAMS); 346}